From b8e9f620b6da41b4bcdd31f565096b58f1779675 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Fri, 18 Feb 2022 16:40:45 +0100 Subject: [PATCH 001/282] [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 @@ +<ds-openaire-broker-events></ds-openaire-broker-events> 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<AdminNotificationsOpenaireEventsPageComponent>; + + 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<AdminNotificationsOpenaireEventsPageParams> { + + /** + * 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<AdminNotificationsOpenaireTopicsPageParams> { + + /** + * 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 @@ +<ds-openaire-broker-topic></ds-openaire-broker-topic> 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<AdminNotificationsOpenaireTopicsPageComponent>; + + 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<T extends CacheableObject> implements UpdateDa return result$; } + /** + * Perform a post on an endpoint related item with ID. Ex.: endpoint/<itemId>/related?item=<relatedItemId> + * @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<T>(requestId); + } + + /** + * Perform a delete on an endpoint related item. Ex.: endpoint/<itemId>/related + * @param itemId The item id + * @return the RestResponse as an Observable + */ + public deleteOnRelated(itemId: string): Observable<RemoteData<NoContent>> { + 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<string>[] = [ + { + 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<PaginatedList<OpenaireBrokerEventObject>> 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<OpenaireBrokerEventObject> 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<OpenaireBrokerEventObject> { + /** + * The REST endpoint. + */ + protected linkPath = 'nbevents'; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {Store<CoreState>} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {ChangeAnalyzer<OpenaireBrokerEventObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store<CoreState>, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: ChangeAnalyzer<OpenaireBrokerEventObject>) { + 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<OpenaireBrokerEventObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer<OpenaireBrokerEventObject>) { + 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<RemoteData<PaginatedList<OpenaireBrokerEventObject>>> + * The list of OpenAIRE Broker events. + */ + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<OpenaireBrokerEventObject>[]): Observable<RemoteData<PaginatedList<OpenaireBrokerEventObject>>> { + 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<RemoteData<OpenaireBrokerEventObject>> + * The OpenAIRE Broker event. + */ + public getEvent(id: string, ...linksToFollow: FollowLinkConfig<OpenaireBrokerEventObject>[]): Observable<RemoteData<OpenaireBrokerEventObject>> { + 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<RestResponse> + * The REST response. + */ + public patchEvent(status, dso, reason?: string): Observable<RemoteData<OpenaireBrokerEventObject>> { + const operation: ReplaceOperation<string>[] = [ + { + 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<RestResponse> + * The REST response. + */ + public boundProject(itemId: string, projectId: string): Observable<RemoteData<OpenaireBrokerEventObject>> { + 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<RestResponse> + * The REST response. + */ + public removeProject(itemId: string): Observable<RemoteData<NoContent>> { + 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<RemoteData<Item>>; + + /** + * The related project for this Event + * Will be undefined unless the {@related HALLink} has been resolved. + */ + @link(ITEM) + related?: Observable<RemoteData<Item>>; +} 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<PaginatedList<OpenaireBrokerTopicObject>> 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<OpenaireBrokerTopicObject> 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<OpenaireBrokerTopicObject> { + /** + * The REST endpoint. + */ + protected linkPath = 'nbtopics'; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {Store<CoreState>} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {ChangeAnalyzer<OpenaireBrokerTopicObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store<CoreState>, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: ChangeAnalyzer<OpenaireBrokerTopicObject>) { + 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<OpenaireBrokerTopicObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer<OpenaireBrokerTopicObject>) { + 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<RemoteData<PaginatedList<OpenaireBrokerTopicObject>>> + * The list of OpenAIRE Broker topics. + */ + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<OpenaireBrokerTopicObject>[]): Observable<RemoteData<PaginatedList<OpenaireBrokerTopicObject>>> { + 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<RemoteData<OpenaireBrokerTopicObject>> + * The OpenAIRE Broker topic. + */ + public getTopic(id: string, ...linksToFollow: FollowLinkConfig<OpenaireBrokerTopicObject>[]): Observable<RemoteData<OpenaireBrokerTopicObject>> { + 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 @@ +<div class="container"> + <div class="row"> + <div class="col-12"> + <h2 class="border-bottom pb-2">{{'openaire.events.title'| translate}}</h2> + <p>{{'openaire.broker.events.description'| translate}}</p> + <p> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/openaire-broker']"> + <i class="fas fa-angle-double-left"></i> + {{'openaire.broker.events.back' | translate}} + </a> + </p> + </div> + </div> + <div class="row"> + <div class="col-12"> + <h3 class="border-bottom pb-2"> + {{'openaire.broker.events.topic' | translate}} {{this.showTopic}} + </h3> + + <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + + <ds-pagination *ngIf="!(isEventPageLoading | async)" + [paginationOptions]="paginationConfig" + [collectionSize]="(totalElements$ | async)" + [sortOptions]="paginationSortConfig" + (paginationChange)="getOpenaireBrokerEvents()"> + + <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + <ng-container *ngIf="!(isEventLoading | async)"> + <div *ngIf="(eventsUpdated$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> + {{'openaire.broker.noEvents' | translate}} + </div> + <div *ngIf="(eventsUpdated$|async)?.length != 0" class="table-responsive mt-2"> + <table id="events" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col">{{'openaire.broker.event.table.trust' | translate}}</th> + <th scope="col">{{'openaire.broker.event.table.publication' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'openaire.broker.event.table.details' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'openaire.broker.event.table.project-details' | translate}}</th> + <th scope="col" class="button-rows">{{'openaire.broker.event.table.actions' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let eventElement of (eventsUpdated$ | async); let i = index"> + <td>{{eventElement?.event?.trust}} + </td> + <td><a *ngIf="eventElement?.target" + target="_blank" + [routerLink]="['/items', eventElement?.target?.id]">{{eventElement.title}}</a> + <span *ngIf="!eventElement?.target">{{eventElement.title}}</span> + </td> + <td *ngIf="showTopic.indexOf('/PID') !== -1"> + <p><span class="small">{{'openaire.broker.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> + <p><span class="small">{{'openaire.broker.event.table.pidvalue' | translate}}</span><br> + <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" target="_blank"> + {{eventElement.event.message.value}} + </a> + <ng-template #noPID><span class="badge badge-info">{{eventElement.event.message.value}}</span></ng-template> + </p> + </td> + <td *ngIf="showTopic.indexOf('/SUBJECT') !== -1"> + <p><span class="small">{{'openaire.broker.event.table.subjectValue' | translate}}</span><br><span class="badge badge-info">{{eventElement.event.message.value}}</span></p> + </td> + <td *ngIf="showTopic.indexOf('/ABSTRACT') !== -1"> + <p class="abstract-container" [class.show]="showMore"> + <span class="small">{{'openaire.broker.event.table.abstract' | translate}}</span><br> + <span class="text-ellipsis">{{eventElement.event.message.abstract}}</span> + </p> + <button class="btn btn-outline-primary btn-sm" (click)="showMore = !showMore"> + <i *ngIf="!showMore" class="fas fa-angle-down"></i> + <i *ngIf="showMore" class="fas fa-angle-up"></i> + {{ (showMore ? 'openaire.broker.event.table.less': 'openaire.broker.event.table.more') | translate }} + </button> + </td> + <td *ngIf="showTopic.indexOf('/PROJECT') !== -1"> + <p> + {{'openaire.broker.event.table.suggestedProject' | translate}} + </p> + <p> + <span class="small">{{'openaire.broker.event.table.project' | translate}}</span><br> + <a href="https://explore.openaire.eu/search/project?projectId={{ eventElement.event.message.openaireId}}" target="_blank">{{eventElement.event.message.title}}</a> + </p> + <p> + <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'openaire.broker.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> + <span *ngIf="eventElement.event.message.code"><span class="small">{{'openaire.broker.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> + <span *ngIf="eventElement.event.message.funder"><span class="small">{{'openaire.broker.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> + <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'openaire.broker.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> + <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'openaire.broker.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> + </p> + <hr> + <div> + {{(eventElement.hasProject ? 'openaire.broker.event.project.found' : 'openaire.broker.event.project.notFound') | translate}} + <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}}</a> + <div class="btn-group"> + <button class="btn btn-outline-primary btn-sm" + [disabled]="eventElement.isRunning" + (click)="openModalLookup(eventElement); $event.stopPropagation();"> + <i class="fas fa-search"></i> + </button> + <button *ngIf="eventElement.hasProject" + class="btn btn-outline-danger btn-sm" + [disabled]="eventElement.isRunning" + (click)="removeProject(eventElement)"> + <i class="fas fa-trash-alt"></i> + </button> + </div> + </div> + </td> + <td> + <div class="btn-group-vertical button-width"> + <button *ngIf="showTopic.indexOf('/PROJECT') !== -1" + class="btn btn-outline-success btn-sm button-width" + [disabled]="eventElement.isRunning" + (click)="modalChoice('ACCEPTED', eventElement, acceptModal)"> + <i class="fas fa-check"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.import' | translate}}</span> + </button> + <button *ngIf="showTopic.indexOf('/PROJECT') == -1" class="btn btn-outline-success btn-sm button-width" [disabled]="eventElement.isRunning" (click)="executeAction('ACCEPTED', eventElement)"> + <i class="fas fa-check"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.accept' | translate}}</span> + </button> + <button class="btn btn-outline-dark btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('DISCARDED', eventElement, ignoreModal)"> + <i class="fas fa-trash-alt"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.ignore' | translate}}</span> + </button> + <button class="btn btn-outline-danger btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('REJECTED', eventElement, rejectModal)"> + <i class="fas fa-trash-alt"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.reject' | translate}}</span> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </ng-container> + </ds-pagination> + </div> + </div> + <div class="row"> + <div class="col-md-12"> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/openaire-broker']"> + <i class="fas fa-angle-double-left"></i> + {{'openaire.broker.events.back' | translate}} + </a> + </div> + </div> +</div> + +<ng-template #acceptModal let-modal> + <div class="modal-header"> + <h4 class="modal-title" id="acceptModal">{{'openaire.broker.event.sure' | translate}}</h4> + </div> + <div class="modal-body"> + <p>{{'openaire.broker.event.accept.description' | translate}}</p> + + <button class="btn btn-outline-success float-left" (click)="modal.close('do')"> + <i class="fas fa-check"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.import' | translate}}</span> + </button> + <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <i class="fas fa-close"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + </button> + </div> +</ng-template> + +<ng-template #ignoreModal let-modal> + <div class="modal-header"> + <h4 class="modal-title" id="ignoreModal">{{'openaire.broker.event.sure' | translate}}</h4> + </div> + <div class="modal-body"> + <p>{{'openaire.broker.event.ignore.description' | translate}}</p> + + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'openaire.broker.event.reason' |translate}}"></textarea --> + + <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> + <i class="fas fa-trash-alt"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.ignore' | translate}}</span> + </button> + <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <i class="fas fa-close"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + </button> + </div> +</ng-template> + +<ng-template #rejectModal let-modal> + <div class="modal-header"> + <h4 class="modal-title" id="rejectModal">{{'openaire.broker.event.sure' | translate}}</h4> + </div> + <div class="modal-body"> + <p>{{'openaire.broker.event.reject.description' | translate}}</p> + + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'openaire.broker.event.reason' |translate}}"></textarea --> + + <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> + <i class="fas fa-trash-alt"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.reject' | translate}}</span> + </button> + <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <i class="fas fa-close"></i> + <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + </button> + </div> +</ng-template> 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<OpenaireBrokerEventsComponent>; + 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<TestComponent>; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + <ds-openaire-broker-event></ds-openaire-broker-event>`; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; + 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<OpenaireBrokerEventData[]> = new BehaviorSubject([]); + /** + * The total number of OpenAIRE Broker events. + * @type {Observable<number>} + */ + public totalElements$: Observable<number>; + /** + * 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<boolean>} + */ + public isEventPageLoading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); + /** + * Contains the information about the loading status of the events inside the pagination component. + * @type {Observable<boolean>} + */ + public isEventLoading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(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<OpenaireBrokerEventObject>) => { + 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<OpenaireBrokerEventObject>) => { + 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<OpenaireBrokerEventObject>) => { + 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<PaginatedList<OpenaireBrokerEventObject>>) => { + 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<Item>, RemoteData<Item>]) => { + 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 @@ +<div class="modal-header"> + <h4 class="modal-title" id="modal-title">{{ (labelPrefix + label + '.title') | translate }}</h4> + <button type="button" class="close" aria-label="Close button" aria-describedby="modal-title" + (click)="close()"> + <span aria-hidden="true">×</span> + </button> +</div> +<div class="modal-body"> + <small>{{ (labelPrefix + label + '.publication' | translate) }}</small> + <div class="mb-3"> + <div class="text-truncate"> + <a target="_blank" href="/items/{{(externalSourceEntry.event.target|async)?.payload?.id}}"> + {{externalSourceEntry.title}} + </a> + </div> + </div> + <div *ngIf="externalSourceEntry.projectTitle"> + <small>{{ (labelPrefix + label + '.bountToLocal' |translate) }}</small> + <div class="mb-3"> + <div class="text-truncate"> + <a target="_blank" href="/items/{{externalSourceEntry.projectId}}"> + {{externalSourceEntry.projectTitle}} + </a> + </div> + </div> + </div> + + <h4>{{ (labelPrefix + label + '.select' | translate) }}</h4> + + <div id="project-entities" class="mb-3"> + + <div id="project-search" class="input-group mb-3"> + <input type="text" class="form-control" (keyup.enter)="search(projectTitle)" [(ngModel)]="projectTitle" placeholder="{{labelPrefix + label + '.placeholder' |translate}}" aria-label="" aria-describedby=""> + <div class="input-group-append"> + <button type="button" class="btn btn-outline-secondary" [disabled]="projectTitle === ''" (click)="projectTitle = ''">{{(labelPrefix + label + '.clear'|translate)}}</button> + <button type="button" class="btn btn-primary" [disabled]="projectTitle === ''" (click)="search(projectTitle)">{{(labelPrefix + label + '.search'|translate)}}</button> + </div> + </div> + + <ds-loading *ngIf="(isLoading$ | async)" message="{{'loading.search-results' | translate}}"></ds-loading> + <ds-search-results *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length > 0 && !(isLoading$ | async)" + [searchResults]="(localEntitiesRD$ | async)" + [sortConfig]="this.searchOptions?.sort" + [searchConfig]="this.searchOptions" + [selectable]="true" + [disableHeader]="true" + [hidePaginationDetail]="false" + [selectionConfig]="{ repeatable: false, listId: entityListId }" + [linkType]="linkTypes.ExternalLink" + [context]="context" + (deselectObject)="deselectEntity()" + (selectObject)="selectEntity($event)"> + </ds-search-results> + + <div *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length < 1 && !(isLoading$ | async)"> + <ds-alert [type]="'alert-info'"> + <p class="lead mb-0">{{(labelPrefix + label + '.notFound' | translate)}}</p> + </ds-alert> + </div> + + </div> +</div> +<div class="modal-footer"> + <div> + <button type="button" class="btn btn-outline-secondary" (click)="close()">{{ (labelPrefix + label + '.cancel' | translate) }}</button> + </div> + <div> + <button type="button" class="btn btn-primary" [disabled]="selectedImportType === importType.None" (click)="bound()">{{ (labelPrefix + label + '.bound' | translate) }}</button> + </div> +</div> 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<ProjectEntryImportModalComponent>; + 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<TestComponent>; + + // synchronous beforeEach + beforeEach(() => { + searchServiceStub.search.and.returnValue(observableOf(paginatedListRD)); + const html = ` + <ds-project-entry-import-modal [externalSourceEntry]="eventData"></ds-project-entry-import-modal>`; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; + 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<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>>; + /** + * 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<ListableObject> = new EventEmitter<ListableObject>(); + /** + * 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 @@ +<div class="container"> + <div class="row"> + <div class="col-12"> + <h2 class="border-bottom pb-2">{{'openaire.broker.title'| translate}}</h2> + <p>{{'openaire.broker.topics.description'| translate}}</p> + </div> + </div> + <div class="row"> + <div class="col-12"> + <h3 class="border-bottom pb-2">{{'openaire.broker.topics'| translate}}</h3> + + <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + <ds-pagination *ngIf="!(isTopicsLoading() | async)" + [paginationOptions]="paginationConfig" + [collectionSize]="(totalElements$ | async)" + [hideGear]="false" + [hideSortOptions]="true" + (paginationChange)="getOpenaireBrokerTopics()"> + + <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'openaire.broker.loading' | translate"></ds-loading> + <ng-container *ngIf="!(isTopicsProcessing() | async)"> + <div *ngIf="(topics$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> + {{'openaire.broker.noTopics' | translate}} + </div> + <div *ngIf="(topics$|async)?.length != 0" class="table-responsive mt-2"> + <table id="epeople" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col">{{'openaire.broker.table.topic' | translate}}</th> + <th scope="col">{{'openaire.broker.table.last-event' | translate}}</th> + <th scope="col">{{'openaire.broker.table.actions' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let topicElement of (topics$ | async); let i = index"> + <td>{{topicElement.name}}</td> + <td>{{topicElement.lastEvent}}</td> + <td> + <div class="btn-group edit-field"> + <button + class="btn btn-outline-primary btn-sm" + title="{{'openaire.broker.button.detail' | translate }}" + [routerLink]="[topicElement.id]"> + <span class="badge badge-info">{{topicElement.totalEvents}}</span> + <i class="fas fa-info fa-fw"></i> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </ng-container> + </ds-pagination> + </div> + </div> +</div> 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<OpenaireBrokerTopicsComponent>; + 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<TestComponent>; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + <ds-openaire-broker-topic></ds-openaire-broker-topic>`; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; + 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<OpenaireBrokerTopicObject[]>; + /** + * The total number of OpenAIRE Broker topics. + */ + public totalElements$: Observable<number>; + /** + * 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<boolean> + * 'true' if the topics are loading, 'false' otherwise. + */ + public isTopicsLoading(): Observable<boolean> { + return this.openaireStateService.isOpenaireBrokerTopicsLoading(); + } + + /** + * Returns the information about the processing status of the OpenAIRE Broker topics (if it's running or not). + * + * @return Observable<boolean> + * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. + */ + public isTopicsProcessing(): Observable<boolean> { + 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<OpenaireBrokerTopicObject>) => + 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<any>} store$ + * @param {TranslateService} translate + * @param {NotificationsService} notificationsService + * @param {OpenaireBrokerTopicsService} openaireBrokerTopicService + * @param {OpenaireBrokerTopicRestService} openaireBrokerTopicDataService + */ + constructor( + private actions$: Actions, + private store$: Store<any>, + 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<PaginatedList<OpenaireBrokerTopicObject>> + * The list of OpenAIRE Broker topics. + */ + public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<OpenaireBrokerTopicObject>> { + 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<PaginatedList<OpenaireBrokerTopicObject>>) => !rd.isResponsePending), + map((rd: RemoteData<PaginatedList<OpenaireBrokerTopicObject>>) => { + 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<OpenaireState>} store + */ + constructor(private store: Store<OpenaireState>) { } + + // OpenAIRE Broker topics + // -------------------------------------------------------------------------- + + /** + * Returns the list of OpenAIRE Broker topics from the state. + * + * @return Observable<OpenaireBrokerTopicObject> + * The list of OpenAIRE Broker topics. + */ + public getOpenaireBrokerTopics(): Observable<OpenaireBrokerTopicObject[]> { + 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<boolean> + * 'true' if the topics are loading, 'false' otherwise. + */ + public isOpenaireBrokerTopicsLoading(): Observable<boolean> { + 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<boolean> + * 'true' if the topics are loaded, 'false' otherwise. + */ + public isOpenaireBrokerTopicsLoaded(): Observable<boolean> { + 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<boolean> + * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. + */ + public isOpenaireBrokerTopicsProcessing(): Observable<boolean> { + return this.store.pipe(select(sOpenaireBrokerTopicsProcessingSelector)); + } + + /** + * Returns, from the state, the total available pages of the OpenAIRE Broker topics. + * + * @return Observable<number> + * The number of the OpenAIRE Broker topics pages. + */ + public getOpenaireBrokerTopicsTotalPages(): Observable<number> { + return this.store.pipe(select(getOpenaireBrokerTopicsTotalPagesSelector)); + } + + /** + * Returns the current page of the OpenAIRE Broker topics, from the state. + * + * @return Observable<number> + * The number of the current OpenAIRE Broker topics page. + */ + public getOpenaireBrokerTopicsCurrentPage(): Observable<number> { + return this.store.pipe(select(getOpenaireBrokerTopicsCurrentPageSelector)); + } + + /** + * Returns the total number of the OpenAIRE Broker topics. + * + * @return Observable<number> + * The number of the OpenAIRE Broker topics. + */ + public getOpenaireBrokerTopicsTotals(): Observable<number> { + 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<OpenaireState, Action>), + 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<OpenaireState> = { + brokerTopic: openaireBrokerTopicsReducer, +}; + +export const openaireSelector = createFeatureSelector<OpenaireState>('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<OpenaireState, OpenaireBrokerTopicState> { + return subStateSelector<OpenaireState,OpenaireBrokerTopicState>(openaireSelector, 'brokerTopic'); +} + +/** + * Returns the OpenAIRE Broker topics list. + * @function openaireBrokerTopicsObjectSelector + * @return {OpenaireBrokerTopicObject[]} + */ +export function openaireBrokerTopicsObjectSelector(): MemoizedSelector<OpenaireState, OpenaireBrokerTopicObject[]> { + return subStateSelector<OpenaireState, OpenaireBrokerTopicObject[]>(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<DSpaceObject> = Object.assign( + new SearchResult<DSpaceObject>(), + { + 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 @@ <div id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" ngbDropdownMenu> <h6 class="dropdown-header">{{ 'pagination.results-per-page' | translate}}</h6> <button class="dropdown-item" *ngFor="let item of pageSizeOptions" (click)="doPageSizeChange(item)"><i [ngClass]="{'invisible': item != (pageSize$|async)}" class="fas fa-check" aria-hidden="true"></i> {{item}} </button> - <h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6> - <button class="dropdown-item" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== (sortDirection$ |async)}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button> + <ng-container *ngIf="!hideSortOptions"> + <h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6> + <button class="dropdown-item" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== (sortDirection$ |async)}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button> + </ng-container> </div> </div> </div> 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<T, V>(parentSelector: Selector<any, any>, subState: string, key: string): MemoizedSelector<T, V> { + 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<T, V>(parentSelector: Selector<any, any>, subState: string): MemoizedSelector<T, V> { + 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 <luca.giamminonni@4science.it> Date: Fri, 18 Feb 2022 19:01:30 +0100 Subject: [PATCH 002/282] [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 @@ +<ds-notifications-broker-events></ds-notifications-broker-events> 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<AdminNotificationsBrokerEventsPageComponent>; + + 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<AdminNotificationsOpenaireEventsPageParams> { +export class AdminNotificationsBrokerEventsPageResolver implements Resolve<AdminNotificationsBrokerEventsPageParams> { /** * 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<AdminNotificationsOpenaireTopicsPageParams> { +export class AdminNotificationsBrokerTopicsPageResolver implements Resolve<AdminNotificationsBrokerTopicsPageParams> { /** * 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 @@ +<ds-notifications-broker-topic></ds-notifications-broker-topic> 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<AdminNotificationsBrokerTopicsPageComponent>; + + 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 @@ -<ds-openaire-broker-events></ds-openaire-broker-events> 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<AdminNotificationsOpenaireEventsPageComponent>; - - 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 @@ -<ds-openaire-broker-topic></ds-openaire-broker-topic> 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<AdminNotificationsOpenaireTopicsPageComponent>; - - 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<PaginatedList<OpenaireBrokerEventObject>> for the object with the given Topic', () => { + it('should return a RemoteData<PaginatedList<NotificationsBrokerEventObject>> 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<OpenaireBrokerEventObject> for the object with the given URL', () => { - const result = service.getEvent(openaireBrokerEventObjectMissingPid.id); + it('should return a RemoteData<NotificationsBrokerEventObject> 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<OpenaireBrokerEventObject> { +class DataServiceImpl extends DataService<NotificationsBrokerEventObject> { /** * The REST endpoint. */ @@ -44,7 +44,7 @@ class DataServiceImpl extends DataService<OpenaireBrokerEventObject> { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer<OpenaireBrokerEventObject>} comparator + * @param {ChangeAnalyzer<NotificationsBrokerEventObject>} comparator */ constructor( protected requestService: RequestService, @@ -54,17 +54,17 @@ class DataServiceImpl extends DataService<OpenaireBrokerEventObject> { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer<OpenaireBrokerEventObject>) { + protected comparator: ChangeAnalyzer<NotificationsBrokerEventObject>) { 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<OpenaireBrokerEventObject>} comparator + * @param {DefaultChangeAnalyzer<NotificationsBrokerEventObject>} comparator */ constructor( protected requestService: RequestService, @@ -87,23 +87,23 @@ export class OpenaireBrokerEventRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<OpenaireBrokerEventObject>) { + protected comparator: DefaultChangeAnalyzer<NotificationsBrokerEventObject>) { 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<RemoteData<PaginatedList<OpenaireBrokerEventObject>>> - * The list of OpenAIRE Broker events. + * @return Observable<RemoteData<PaginatedList<NotificationsBrokerEventObject>>> + * The list of Notifications Broker events. */ - public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<OpenaireBrokerEventObject>[]): Observable<RemoteData<PaginatedList<OpenaireBrokerEventObject>>> { + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerEventObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerEventObject>>> { 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<RemoteData<OpenaireBrokerEventObject>> - * The OpenAIRE Broker event. + * @return Observable<RemoteData<NotificationsBrokerEventObject>> + * The Notifications Broker event. */ - public getEvent(id: string, ...linksToFollow: FollowLinkConfig<OpenaireBrokerEventObject>[]): Observable<RemoteData<OpenaireBrokerEventObject>> { + public getEvent(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerEventObject>[]): Observable<RemoteData<NotificationsBrokerEventObject>> { 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<RestResponse> * The REST response. */ - public patchEvent(status, dso, reason?: string): Observable<RemoteData<OpenaireBrokerEventObject>> { + public patchEvent(status, dso, reason?: string): Observable<RemoteData<NotificationsBrokerEventObject>> { const operation: ReplaceOperation<string>[] = [ { 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<RestResponse> * The REST response. */ - public boundProject(itemId: string, projectId: string): Observable<RemoteData<OpenaireBrokerEventObject>> { + public boundProject(itemId: string, projectId: string): Observable<RemoteData<NotificationsBrokerEventObject>> { 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<RestResponse> * 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<PaginatedList<OpenaireBrokerTopicObject>> for the object with the given URL', () => { + it('should return a RemoteData<PaginatedList<NotificationsBrokerTopicObject>> 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<OpenaireBrokerTopicObject> for the object with the given URL', () => { - const result = service.getTopic(openaireBrokerTopicObjectMorePid.id); + it('should return a RemoteData<NotificationsBrokerTopicObject> 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<OpenaireBrokerTopicObject> { +class DataServiceImpl extends DataService<NotificationsBrokerTopicObject> { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService<OpenaireBrokerTopicObject> { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer<OpenaireBrokerTopicObject>} comparator + * @param {ChangeAnalyzer<NotificationsBrokerTopicObject>} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService<OpenaireBrokerTopicObject> { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer<OpenaireBrokerTopicObject>) { + protected comparator: ChangeAnalyzer<NotificationsBrokerTopicObject>) { 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<OpenaireBrokerTopicObject>} comparator + * @param {DefaultChangeAnalyzer<NotificationsBrokerTopicObject>} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class OpenaireBrokerTopicRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<OpenaireBrokerTopicObject>) { + protected comparator: DefaultChangeAnalyzer<NotificationsBrokerTopicObject>) { 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<RemoteData<PaginatedList<OpenaireBrokerTopicObject>>> - * The list of OpenAIRE Broker topics. + * @return Observable<RemoteData<PaginatedList<NotificationsBrokerTopicObject>>> + * The list of Notifications Broker topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<OpenaireBrokerTopicObject>[]): Observable<RemoteData<PaginatedList<OpenaireBrokerTopicObject>>> { + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerTopicObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerTopicObject>>> { 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<RemoteData<OpenaireBrokerTopicObject>> - * The OpenAIRE Broker topic. + * @return Observable<RemoteData<NotificationsBrokerTopicObject>> + * The Notifications Broker topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig<OpenaireBrokerTopicObject>[]): Observable<RemoteData<OpenaireBrokerTopicObject>> { + public getTopic(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerTopicObject>[]): Observable<RemoteData<NotificationsBrokerTopicObject>> { 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 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom pb-2">{{'openaire.events.title'| translate}}</h2> - <p>{{'openaire.broker.events.description'| translate}}</p> + <h2 class="border-bottom pb-2">{{'notifications.events.title'| translate}}</h2> + <p>{{'notifications.broker.events.description'| translate}}</p> <p> - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/openaire-broker']"> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/notifications-broker']"> <i class="fas fa-angle-double-left"></i> - {{'openaire.broker.events.back' | translate}} + {{'notifications.broker.events.back' | translate}} </a> </p> </div> @@ -14,31 +14,31 @@ <h2 class="border-bottom pb-2">{{'openaire.events.title'| translate}}</h2> <div class="row"> <div class="col-12"> <h3 class="border-bottom pb-2"> - {{'openaire.broker.events.topic' | translate}} {{this.showTopic}} + {{'notifications.broker.events.topic' | translate}} {{this.showTopic}} </h3> - <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isEventPageLoading | async)" [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" [sortOptions]="paginationSortConfig" - (paginationChange)="getOpenaireBrokerEvents()"> + (paginationChange)="getNotificationsBrokerEvents()"> - <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> <ng-container *ngIf="!(isEventLoading | async)"> <div *ngIf="(eventsUpdated$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> - {{'openaire.broker.noEvents' | translate}} + {{'notifications.broker.noEvents' | translate}} </div> <div *ngIf="(eventsUpdated$|async)?.length != 0" class="table-responsive mt-2"> <table id="events" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'openaire.broker.event.table.trust' | translate}}</th> - <th scope="col">{{'openaire.broker.event.table.publication' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'openaire.broker.event.table.details' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'openaire.broker.event.table.project-details' | translate}}</th> - <th scope="col" class="button-rows">{{'openaire.broker.event.table.actions' | translate}}</th> + <th scope="col">{{'notifications.broker.event.table.trust' | translate}}</th> + <th scope="col">{{'notifications.broker.event.table.publication' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'notifications.broker.event.table.details' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'notifications.broker.event.table.project-details' | translate}}</th> + <th scope="col" class="button-rows">{{'notifications.broker.event.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -51,8 +51,8 @@ <h3 class="border-bottom pb-2"> <span *ngIf="!eventElement?.target">{{eventElement.title}}</span> </td> <td *ngIf="showTopic.indexOf('/PID') !== -1"> - <p><span class="small">{{'openaire.broker.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> - <p><span class="small">{{'openaire.broker.event.table.pidvalue' | translate}}</span><br> + <p><span class="small">{{'notifications.broker.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> + <p><span class="small">{{'notifications.broker.event.table.pidvalue' | translate}}</span><br> <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" target="_blank"> {{eventElement.event.message.value}} </a> @@ -60,37 +60,37 @@ <h3 class="border-bottom pb-2"> </p> </td> <td *ngIf="showTopic.indexOf('/SUBJECT') !== -1"> - <p><span class="small">{{'openaire.broker.event.table.subjectValue' | translate}}</span><br><span class="badge badge-info">{{eventElement.event.message.value}}</span></p> + <p><span class="small">{{'notifications.broker.event.table.subjectValue' | translate}}</span><br><span class="badge badge-info">{{eventElement.event.message.value}}</span></p> </td> <td *ngIf="showTopic.indexOf('/ABSTRACT') !== -1"> <p class="abstract-container" [class.show]="showMore"> - <span class="small">{{'openaire.broker.event.table.abstract' | translate}}</span><br> + <span class="small">{{'notifications.broker.event.table.abstract' | translate}}</span><br> <span class="text-ellipsis">{{eventElement.event.message.abstract}}</span> </p> <button class="btn btn-outline-primary btn-sm" (click)="showMore = !showMore"> <i *ngIf="!showMore" class="fas fa-angle-down"></i> <i *ngIf="showMore" class="fas fa-angle-up"></i> - {{ (showMore ? 'openaire.broker.event.table.less': 'openaire.broker.event.table.more') | translate }} + {{ (showMore ? 'notifications.broker.event.table.less': 'notifications.broker.event.table.more') | translate }} </button> </td> <td *ngIf="showTopic.indexOf('/PROJECT') !== -1"> <p> - {{'openaire.broker.event.table.suggestedProject' | translate}} + {{'notifications.broker.event.table.suggestedProject' | translate}} </p> <p> - <span class="small">{{'openaire.broker.event.table.project' | translate}}</span><br> + <span class="small">{{'notifications.broker.event.table.project' | translate}}</span><br> <a href="https://explore.openaire.eu/search/project?projectId={{ eventElement.event.message.openaireId}}" target="_blank">{{eventElement.event.message.title}}</a> </p> <p> - <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'openaire.broker.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> - <span *ngIf="eventElement.event.message.code"><span class="small">{{'openaire.broker.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> - <span *ngIf="eventElement.event.message.funder"><span class="small">{{'openaire.broker.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> - <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'openaire.broker.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> - <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'openaire.broker.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> + <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'notifications.broker.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> + <span *ngIf="eventElement.event.message.code"><span class="small">{{'notifications.broker.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> + <span *ngIf="eventElement.event.message.funder"><span class="small">{{'notifications.broker.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> + <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'notifications.broker.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> + <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'notifications.broker.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> </p> <hr> <div> - {{(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}} <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}}</a> <div class="btn-group"> <button class="btn btn-outline-primary btn-sm" @@ -114,19 +114,19 @@ <h3 class="border-bottom pb-2"> [disabled]="eventElement.isRunning" (click)="modalChoice('ACCEPTED', eventElement, acceptModal)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.import' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.import' | translate}}</span> </button> <button *ngIf="showTopic.indexOf('/PROJECT') == -1" class="btn btn-outline-success btn-sm button-width" [disabled]="eventElement.isRunning" (click)="executeAction('ACCEPTED', eventElement)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.accept' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.accept' | translate}}</span> </button> <button class="btn btn-outline-dark btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('DISCARDED', eventElement, ignoreModal)"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.ignore' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.ignore' | translate}}</span> </button> <button class="btn btn-outline-danger btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('REJECTED', eventElement, rejectModal)"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.reject' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.reject' | translate}}</span> </button> </div> </td> @@ -140,9 +140,9 @@ <h3 class="border-bottom pb-2"> </div> <div class="row"> <div class="col-md-12"> - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/openaire-broker']"> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/notifications-broker']"> <i class="fas fa-angle-double-left"></i> - {{'openaire.broker.events.back' | translate}} + {{'notifications.broker.events.back' | translate}} </a> </div> </div> @@ -150,58 +150,58 @@ <h3 class="border-bottom pb-2"> <ng-template #acceptModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="acceptModal">{{'openaire.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="acceptModal">{{'notifications.broker.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'openaire.broker.event.accept.description' | translate}}</p> + <p>{{'notifications.broker.event.accept.description' | translate}}</p> <button class="btn btn-outline-success float-left" (click)="modal.close('do')"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.import' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.import' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> </button> </div> </ng-template> <ng-template #ignoreModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="ignoreModal">{{'openaire.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="ignoreModal">{{'notifications.broker.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'openaire.broker.event.ignore.description' | translate}}</p> + <p>{{'notifications.broker.event.ignore.description' | translate}}</p> - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'openaire.broker.event.reason' |translate}}"></textarea --> + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'notifications.broker.event.reason' |translate}}"></textarea --> <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.ignore' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.ignore' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> </button> </div> </ng-template> <ng-template #rejectModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="rejectModal">{{'openaire.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="rejectModal">{{'notifications.broker.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'openaire.broker.event.reject.description' | translate}}</p> + <p>{{'notifications.broker.event.reject.description' | translate}}</p> - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'openaire.broker.event.reason' |translate}}"></textarea --> + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'notifications.broker.event.reason' |translate}}"></textarea --> <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.reject' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.reject' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'openaire.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> </button> </div> </ng-template> 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<OpenaireBrokerEventsComponent>; - let comp: OpenaireBrokerEventsComponent; +describe('NotificationsBrokerEventsComponent test suite', () => { + let fixture: ComponentFixture<NotificationsBrokerEventsComponent>; + 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 = ` - <ds-openaire-broker-event></ds-openaire-broker-event>`; + <ds-notifications-broker-event></ds-notifications-broker-event>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; 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<OpenaireBrokerEventData[]> = new BehaviorSubject([]); + public eventsUpdated$: BehaviorSubject<NotificationsBrokerEventData[]> = new BehaviorSubject([]); /** - * The total number of OpenAIRE Broker events. + * The total number of Notifications Broker events. * @type {Observable<number>} */ public totalElements$: Observable<number>; /** - * 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<OpenaireBrokerEventObject>) => { + this.notificationsBrokerEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<NotificationsBrokerEventObject>) => { 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<OpenaireBrokerEventObject>) => { + this.notificationsBrokerEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<NotificationsBrokerEventObject>) => { 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<OpenaireBrokerEventObject>) => { + this.notificationsBrokerEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<NotificationsBrokerEventObject>) => { 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<PaginatedList<OpenaireBrokerEventObject>>) => { + ).subscribe((rd: RemoteData<PaginatedList<NotificationsBrokerEventObject>>) => { 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<Item>, RemoteData<Item>]) => { - 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 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom pb-2">{{'openaire.broker.title'| translate}}</h2> - <p>{{'openaire.broker.topics.description'| translate}}</p> + <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> + <p>{{'notifications.broker.topics.description'| translate}}</p> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2">{{'openaire.broker.topics'| translate}}</h3> + <h3 class="border-bottom pb-2">{{'notifications.broker.topics'| translate}}</h3> - <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'openaire.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isTopicsLoading() | async)" [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" [hideGear]="false" [hideSortOptions]="true" - (paginationChange)="getOpenaireBrokerTopics()"> + (paginationChange)="getNotificationsBrokerTopics()"> - <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'openaire.broker.loading' | translate"></ds-loading> + <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> <ng-container *ngIf="!(isTopicsProcessing() | async)"> <div *ngIf="(topics$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> - {{'openaire.broker.noTopics' | translate}} + {{'notifications.broker.noTopics' | translate}} </div> <div *ngIf="(topics$|async)?.length != 0" class="table-responsive mt-2"> <table id="epeople" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'openaire.broker.table.topic' | translate}}</th> - <th scope="col">{{'openaire.broker.table.last-event' | translate}}</th> - <th scope="col">{{'openaire.broker.table.actions' | translate}}</th> + <th scope="col">{{'notifications.broker.table.topic' | translate}}</th> + <th scope="col">{{'notifications.broker.table.last-event' | translate}}</th> + <th scope="col">{{'notifications.broker.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -39,7 +39,7 @@ <h3 class="border-bottom pb-2">{{'openaire.broker.topics'| translate}}</h3> <div class="btn-group edit-field"> <button class="btn btn-outline-primary btn-sm" - title="{{'openaire.broker.button.detail' | translate }}" + title="{{'notifications.broker.button.detail' | translate }}" [routerLink]="[topicElement.id]"> <span class="badge badge-info">{{topicElement.totalEvents}}</span> <i class="fas fa-info fa-fw"></i> diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.scss b/src/app/notifications/broker/topics/notifications-broker-topics.component.scss similarity index 100% rename from src/app/openaire/broker/topics/openaire-broker-topics.component.scss rename to src/app/notifications/broker/topics/notifications-broker-topics.component.scss diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts b/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts similarity index 53% rename from src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts rename to src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts index 00ea772ff9a..5bbe3b29079 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.component.spec.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.spec.ts @@ -6,23 +6,23 @@ 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'; + getMockNotificationsStateService, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMorePid +} from '../../../shared/mocks/notifications.mock'; +import { NotificationsBrokerTopicsComponent } from './notifications-broker-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'; -describe('OpenaireBrokerTopicsComponent test suite', () => { - let fixture: ComponentFixture<OpenaireBrokerTopicsComponent>; - let comp: OpenaireBrokerTopicsComponent; +describe('NotificationsBrokerTopicsComponent test suite', () => { + let fixture: ComponentFixture<NotificationsBrokerTopicsComponent>; + let comp: NotificationsBrokerTopicsComponent; let compAsAny: any; - const mockOpenaireStateService = getMockOpenaireStateService(); + const mockNotificationsStateService = getMockNotificationsStateService(); const activatedRouteParams = { - openaireBrokerTopicsParams: { + notificationsBrokerTopicsParams: { currentPage: 0, pageSize: 5 } @@ -36,27 +36,27 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { TranslateModule.forRoot(), ], declarations: [ - OpenaireBrokerTopicsComponent, + NotificationsBrokerTopicsComponent, TestComponent, ], providers: [ - { provide: OpenaireStateService, useValue: mockOpenaireStateService }, + { provide: NotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, { provide: PaginationService, useValue: paginationService }, - OpenaireBrokerTopicsComponent + NotificationsBrokerTopicsComponent ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents().then(() => { - mockOpenaireStateService.getOpenaireBrokerTopics.and.returnValue(observableOf([ - openaireBrokerTopicObjectMorePid, - openaireBrokerTopicObjectMoreAbstract + mockNotificationsStateService.getNotificationsBrokerTopics.and.returnValue(observableOf([ + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract ])); - 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)); + 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)); }); })); @@ -68,7 +68,7 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { // synchronous beforeEach beforeEach(() => { const html = ` - <ds-openaire-broker-topic></ds-openaire-broker-topic>`; + <ds-notifications-broker-topic></ds-notifications-broker-topic>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; testComp = testFixture.componentInstance; }); @@ -77,14 +77,14 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { testFixture.destroy(); }); - it('should create OpenaireBrokerTopicsComponent', inject([OpenaireBrokerTopicsComponent], (app: OpenaireBrokerTopicsComponent) => { + it('should create NotificationsBrokerTopicsComponent', inject([NotificationsBrokerTopicsComponent], (app: NotificationsBrokerTopicsComponent) => { expect(app).toBeDefined(); })); }); describe('Main tests running with two topics', () => { beforeEach(() => { - fixture = TestBed.createComponent(OpenaireBrokerTopicsComponent); + fixture = TestBed.createComponent(NotificationsBrokerTopicsComponent); comp = fixture.componentInstance; compAsAny = comp; @@ -102,8 +102,8 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { expect(comp.topics$).toBeObservable(cold('(a|)', { a: [ - openaireBrokerTopicObjectMorePid, - openaireBrokerTopicObjectMoreAbstract + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract ] })); expect(comp.totalElements$).toBeObservable(cold('(a|)', { @@ -112,12 +112,12 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { }); it(('Should set data properly after the view init'), () => { - spyOn(compAsAny, 'getOpenaireBrokerTopics'); + spyOn(compAsAny, 'getNotificationsBrokerTopics'); comp.ngAfterViewInit(); fixture.detectChanges(); - expect(compAsAny.getOpenaireBrokerTopics).toHaveBeenCalled(); + expect(compAsAny.getNotificationsBrokerTopics).toHaveBeenCalled(); }); it(('isTopicsLoading should return FALSE'), () => { @@ -132,12 +132,12 @@ describe('OpenaireBrokerTopicsComponent test suite', () => { })); }); - it(('getOpenaireBrokerTopics should call the service to dispatch a STATE change'), () => { + it(('getNotificationsBrokerTopics 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); + compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage).and.callThrough(); + expect(compAsAny.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics).toHaveBeenCalledWith(comp.paginationConfig.pageSize, comp.paginationConfig.currentPage); }); }); }); diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.component.ts b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts similarity index 60% rename from src/app/openaire/broker/topics/openaire-broker-topics.component.ts rename to src/app/notifications/broker/topics/notifications-broker-topics.component.ts index 408e21d946f..3bedf6b9d02 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.component.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.component.ts @@ -4,22 +4,22 @@ 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 { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-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 { 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'; /** - * Component to display the OpenAIRE Broker topic list. + * Component to display the Notifications Broker topic list. */ @Component({ - selector: 'ds-openaire-broker-topic', - templateUrl: './openaire-broker-topics.component.html', - styleUrls: ['./openaire-broker-topics.component.scss'], + selector: 'ds-notifications-broker-topic', + templateUrl: './notifications-broker-topics.component.html', + styleUrls: ['./notifications-broker-topics.component.scss'], }) -export class OpenaireBrokerTopicsComponent implements OnInit { +export class NotificationsBrokerTopicsComponent implements OnInit { /** * The pagination system configuration for HTML listing. * @type {PaginationComponentOptions} @@ -30,16 +30,16 @@ export class OpenaireBrokerTopicsComponent implements OnInit { pageSizeOptions: [5, 10, 20, 40, 60] }); /** - * The OpenAIRE Broker topic list sort options. + * The Notifications Broker topic list sort options. * @type {SortOptions} */ public paginationSortConfig: SortOptions; /** - * The OpenAIRE Broker topic list. + * The Notifications Broker topic list. */ - public topics$: Observable<OpenaireBrokerTopicObject[]>; + public topics$: Observable<NotificationsBrokerTopicObject[]>; /** - * The total number of OpenAIRE Broker topics. + * The total number of Notifications Broker topics. */ public totalElements$: Observable<number>; /** @@ -51,62 +51,62 @@ export class OpenaireBrokerTopicsComponent implements OnInit { /** * Initialize the component variables. * @param {PaginationService} paginationService - * @param {OpenaireStateService} openaireStateService + * @param {NotificationsStateService} notificationsStateService */ constructor( private paginationService: PaginationService, - private openaireStateService: OpenaireStateService, + private notificationsStateService: NotificationsStateService, ) { } /** * Component initialization. */ ngOnInit(): void { - this.topics$ = this.openaireStateService.getOpenaireBrokerTopics(); - this.totalElements$ = this.openaireStateService.getOpenaireBrokerTopicsTotals(); + this.topics$ = this.notificationsStateService.getNotificationsBrokerTopics(); + this.totalElements$ = this.notificationsStateService.getNotificationsBrokerTopicsTotals(); } /** - * First OpenAIRE Broker topics loading after view initialization. + * First Notifications Broker topics loading after view initialization. */ ngAfterViewInit(): void { this.subs.push( - this.openaireStateService.isOpenaireBrokerTopicsLoaded().pipe( + this.notificationsStateService.isNotificationsBrokerTopicsLoaded().pipe( take(1) ).subscribe(() => { - this.getOpenaireBrokerTopics(); + this.getNotificationsBrokerTopics(); }) ); } /** - * Returns the information about the loading status of the OpenAIRE Broker topics (if it's running or not). + * Returns the information about the loading status of the Notifications Broker topics (if it's running or not). * * @return Observable<boolean> * 'true' if the topics are loading, 'false' otherwise. */ public isTopicsLoading(): Observable<boolean> { - return this.openaireStateService.isOpenaireBrokerTopicsLoading(); + return this.notificationsStateService.isNotificationsBrokerTopicsLoading(); } /** - * Returns the information about the processing status of the OpenAIRE Broker topics (if it's running or not). + * Returns the information about the processing status of the Notifications Broker topics (if it's running or not). * * @return Observable<boolean> * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. */ public isTopicsProcessing(): Observable<boolean> { - return this.openaireStateService.isOpenaireBrokerTopicsProcessing(); + return this.notificationsStateService.isNotificationsBrokerTopicsProcessing(); } /** - * Dispatch the OpenAIRE Broker topics retrival. + * Dispatch the Notifications Broker topics retrival. */ - public getOpenaireBrokerTopics(): void { + public getNotificationsBrokerTopics(): void { this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe( distinctUntilChanged(), ).subscribe((options: PaginationComponentOptions) => { - this.openaireStateService.dispatchRetrieveOpenaireBrokerTopics( + this.notificationsStateService.dispatchRetrieveNotificationsBrokerTopics( options.pageSize, options.currentPage ); @@ -118,7 +118,7 @@ export class OpenaireBrokerTopicsComponent implements OnInit { * * @param eventsRouteParams */ - protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsOpenaireTopicsPageParams) { + protected updatePaginationFromRouteParams(eventsRouteParams: AdminNotificationsBrokerTopicsPageParams) { if (eventsRouteParams.currentPage) { this.paginationConfig.currentPage = eventsRouteParams.currentPage; } diff --git a/src/app/openaire/broker/topics/openaire-broker-topics.effects.ts b/src/app/notifications/broker/topics/notifications-broker-topics.effects.ts similarity index 57% rename from src/app/openaire/broker/topics/openaire-broker-topics.effects.ts rename to src/app/notifications/broker/topics/notifications-broker-topics.effects.ts index b590b122f52..e3e1e16098f 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.effects.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.effects.ts @@ -6,35 +6,35 @@ import { catchError, map, switchMap, tap, withLatestFrom } from 'rxjs/operators' import { of as observableOf } from 'rxjs'; import { AddTopicsAction, - OpenaireBrokerTopicActionTypes, + NotificationsBrokerTopicActionTypes, RetrieveAllTopicsAction, RetrieveAllTopicsErrorAction, -} from './openaire-broker-topics.actions'; +} from './notifications-broker-topics.actions'; -import { OpenaireBrokerTopicObject } from '../../../core/openaire/broker/models/openaire-broker-topic.model'; +import { NotificationsBrokerTopicObject } from '../../../core/notifications/broker/models/notifications-broker-topic.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; -import { OpenaireBrokerTopicsService } from './openaire-broker-topics.service'; +import { NotificationsBrokerTopicsService } from './notifications-broker-topics.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; -import { OpenaireBrokerTopicRestService } from '../../../core/openaire/broker/topics/openaire-broker-topic-rest.service'; +import { NotificationsBrokerTopicRestService } from '../../../core/notifications/broker/topics/notifications-broker-topic-rest.service'; /** - * Provides effect methods for the OpenAIRE Broker topics actions. + * Provides effect methods for the Notifications Broker topics actions. */ @Injectable() -export class OpenaireBrokerTopicsEffects { +export class NotificationsBrokerTopicsEffects { /** - * Retrieve all OpenAIRE Broker topics managing pagination and errors. + * Retrieve all Notifications Broker topics managing pagination and errors. */ @Effect() retrieveAllTopics$ = this.actions$.pipe( - ofType(OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS), + ofType(NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS), withLatestFrom(this.store$), switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => { - return this.openaireBrokerTopicService.getTopics( + return this.notificationsBrokerTopicService.getTopics( action.payload.elementsPerPage, action.payload.currentPage ).pipe( - map((topics: PaginatedList<OpenaireBrokerTopicObject>) => + map((topics: PaginatedList<NotificationsBrokerTopicObject>) => new AddTopicsAction(topics.page, topics.totalPages, topics.currentPage, topics.totalElements) ), catchError((error: Error) => { @@ -51,9 +51,9 @@ export class OpenaireBrokerTopicsEffects { * Show a notification on error. */ @Effect({ dispatch: false }) retrieveAllTopicsErrorAction$ = this.actions$.pipe( - ofType(OpenaireBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), + ofType(NotificationsBrokerTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), tap(() => { - this.notificationsService.error(null, this.translate.get('openaire.broker.topic.error.service.retrieve')); + this.notificationsService.error(null, this.translate.get('notifications.broker.topic.error.service.retrieve')); }) ); @@ -61,9 +61,9 @@ export class OpenaireBrokerTopicsEffects { * Clear find all topics requests from cache. */ @Effect({ dispatch: false }) addTopicsAction$ = this.actions$.pipe( - ofType(OpenaireBrokerTopicActionTypes.ADD_TOPICS), + ofType(NotificationsBrokerTopicActionTypes.ADD_TOPICS), tap(() => { - this.openaireBrokerTopicDataService.clearFindAllTopicsRequests(); + this.notificationsBrokerTopicDataService.clearFindAllTopicsRequests(); }) ); @@ -73,15 +73,15 @@ export class OpenaireBrokerTopicsEffects { * @param {Store<any>} store$ * @param {TranslateService} translate * @param {NotificationsService} notificationsService - * @param {OpenaireBrokerTopicsService} openaireBrokerTopicService - * @param {OpenaireBrokerTopicRestService} openaireBrokerTopicDataService + * @param {NotificationsBrokerTopicsService} notificationsBrokerTopicService + * @param {NotificationsBrokerTopicRestService} notificationsBrokerTopicDataService */ constructor( private actions$: Actions, private store$: Store<any>, private translate: TranslateService, private notificationsService: NotificationsService, - private openaireBrokerTopicService: OpenaireBrokerTopicsService, - private openaireBrokerTopicDataService: OpenaireBrokerTopicRestService + private notificationsBrokerTopicService: NotificationsBrokerTopicsService, + private notificationsBrokerTopicDataService: NotificationsBrokerTopicRestService ) { } } diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts b/src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts new file mode 100644 index 00000000000..523fac95508 --- /dev/null +++ b/src/app/notifications/broker/topics/notifications-broker-topics.reducer.spec.ts @@ -0,0 +1,68 @@ +import { + AddTopicsAction, + RetrieveAllTopicsAction, + RetrieveAllTopicsErrorAction +} from './notifications-broker-topics.actions'; +import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState } from './notifications-broker-topics.reducer'; +import { + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMorePid +} from '../../../shared/mocks/notifications.mock'; + +describe('notificationsBrokerTopicsReducer test suite', () => { + let notificationsBrokerTopicInitialState: NotificationsBrokerTopicState; + const elementPerPage = 3; + const currentPage = 0; + + beforeEach(() => { + notificationsBrokerTopicInitialState = { + 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 = notificationsBrokerTopicInitialState; + expectedState.processing = true; + + const action = new RetrieveAllTopicsAction(elementPerPage, currentPage); + const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, 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; + expectedState.processing = false; + expectedState.loaded = true; + expectedState.currentPage = 0; + + const action = new RetrieveAllTopicsErrorAction(); + const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, action); + + expect(newState).toEqual(expectedState); + }); + + it('Action ADD_TOPICS should populate the State with Notifications Broker topics', () => { + const expectedState = { + topics: [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ], + processing: false, + loaded: true, + totalPages: 1, + currentPage: 0, + totalElements: 2 + }; + + const action = new AddTopicsAction( + [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ], + 1, 0, 2 + ); + const newState = notificationsBrokerTopicsReducer(notificationsBrokerTopicInitialState, action); + + expect(newState).toEqual(expectedState); + }); +}); diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts b/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts new file mode 100644 index 00000000000..2a7be1bf13d --- /dev/null +++ b/src/app/notifications/broker/topics/notifications-broker-topics.reducer.ts @@ -0,0 +1,72 @@ +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/openaire/broker/topics/openaire-broker-topics.service.spec.ts b/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts similarity index 56% rename from src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts rename to src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts index 3daed2c3bf4..3b780fc173d 100644 --- a/src/app/openaire/broker/topics/openaire-broker-topics.service.spec.ts +++ b/src/app/notifications/broker/topics/notifications-broker-topics.service.spec.ts @@ -1,27 +1,27 @@ import { TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; -import { OpenaireBrokerTopicsService } from './openaire-broker-topics.service'; +import { NotificationsBrokerTopicsService } from './notifications-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 { NotificationsBrokerTopicRestService } from '../../../core/notifications/broker/topics/notifications-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'; + getMockNotificationsBrokerTopicRestService, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMorePid +} 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'; -describe('OpenaireBrokerTopicsService', () => { - let service: OpenaireBrokerTopicsService; - let restService: OpenaireBrokerTopicRestService; +describe('NotificationsBrokerTopicsService', () => { + let service: NotificationsBrokerTopicsService; + let restService: NotificationsBrokerTopicRestService; let serviceAsAny: any; let restServiceAsAny: any; const pageInfo = new PageInfo(); - const array = [ openaireBrokerTopicObjectMorePid, openaireBrokerTopicObjectMoreAbstract ]; + const array = [ notificationsBrokerTopicObjectMorePid, notificationsBrokerTopicObjectMoreAbstract ]; const paginatedList = buildPaginatedList(pageInfo, array); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); const elementsPerPage = 3; @@ -30,22 +30,22 @@ describe('OpenaireBrokerTopicsService', () => { beforeEach(async () => { TestBed.configureTestingModule({ providers: [ - { provide: OpenaireBrokerTopicRestService, useClass: getMockOpenaireBrokerTopicRestService }, - { provide: OpenaireBrokerTopicsService, useValue: service } + { provide: NotificationsBrokerTopicRestService, useClass: getMockNotificationsBrokerTopicRestService }, + { provide: NotificationsBrokerTopicsService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { - restService = TestBed.get(OpenaireBrokerTopicRestService); + restService = TestBed.get(NotificationsBrokerTopicRestService); restServiceAsAny = restService; restServiceAsAny.getTopics.and.returnValue(observableOf(paginatedListRD)); - service = new OpenaireBrokerTopicsService(restService); + service = new NotificationsBrokerTopicsService(restService); serviceAsAny = service; }); describe('getTopics', () => { - it('Should proxy the call to openaireBrokerTopicRestService.getTopics', () => { + it('Should proxy the call to notificationsBrokerTopicRestService.getTopics', () => { const sortOptions = new SortOptions('name', SortDirection.ASC); const findListOptions: FindListOptions = { elementsPerPage: elementsPerPage, @@ -53,10 +53,10 @@ describe('OpenaireBrokerTopicsService', () => { sort: sortOptions }; const result = service.getTopics(elementsPerPage, currentPage); - expect((service as any).openaireBrokerTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); + expect((service as any).notificationsBrokerTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions); }); - it('Should return a paginated list of OpenAIRE Broker topics', () => { + it('Should return a paginated list of Notifications Broker topics', () => { const expected = cold('(a|)', { a: paginatedList }); diff --git a/src/app/notifications/broker/topics/notifications-broker-topics.service.ts b/src/app/notifications/broker/topics/notifications-broker-topics.service.ts new file mode 100644 index 00000000000..b04229e0d9d --- /dev/null +++ b/src/app/notifications/broker/topics/notifications-broker-topics.service.ts @@ -0,0 +1,55 @@ +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 { 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'; + +/** + * The service handling all Notifications Broker topic requests to the REST service. + */ +@Injectable() +export class NotificationsBrokerTopicsService { + + /** + * Initialize the service variables. + * @param {NotificationsBrokerTopicRestService} notificationsBrokerTopicRestService + */ + constructor( + private notificationsBrokerTopicRestService: NotificationsBrokerTopicRestService + ) { } + + /** + * Return the list of Notifications Broker topics managing pagination and errors. + * + * @param elementsPerPage + * The number of the topics per page + * @param currentPage + * The page number to retrieve + * @return Observable<PaginatedList<NotificationsBrokerTopicObject>> + * The list of Notifications Broker topics. + */ + public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<NotificationsBrokerTopicObject>> { + const sortOptions = new SortOptions('name', SortDirection.ASC); + + const findListOptions: FindListOptions = { + elementsPerPage: elementsPerPage, + currentPage: currentPage, + sort: sortOptions + }; + + return this.notificationsBrokerTopicRestService.getTopics(findListOptions).pipe( + find((rd: RemoteData<PaginatedList<NotificationsBrokerTopicObject>>) => !rd.isResponsePending), + map((rd: RemoteData<PaginatedList<NotificationsBrokerTopicObject>>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + throw new Error('Can\'t retrieve Notifications Broker topics from the Broker topics REST service'); + } + }) + ); + } +} diff --git a/src/app/openaire/openaire-state.service.spec.ts b/src/app/notifications/notifications-state.service.spec.ts similarity index 59% rename from src/app/openaire/openaire-state.service.spec.ts rename to src/app/notifications/notifications-state.service.spec.ts index 874d4b4e1a7..97d958e2435 100644 --- a/src/app/openaire/openaire-state.service.spec.ts +++ b/src/app/notifications/notifications-state.service.spec.ts @@ -2,17 +2,17 @@ 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 { notificationsReducers } from './notifications.reducer'; +import { NotificationsStateService } from './notifications-state.service'; import { - openaireBrokerTopicObjectMissingPid, - openaireBrokerTopicObjectMoreAbstract, - openaireBrokerTopicObjectMorePid -} from '../shared/mocks/openaire.mock'; -import { RetrieveAllTopicsAction } from './broker/topics/openaire-broker-topics.actions'; + notificationsBrokerTopicObjectMissingPid, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMorePid +} from '../shared/mocks/notifications.mock'; +import { RetrieveAllTopicsAction } from './broker/topics/notifications-broker-topics.actions'; -describe('OpenaireStateService', () => { - let service: OpenaireStateService; +describe('NotificationsStateService', () => { + let service: NotificationsStateService; let serviceAsAny: any; let store: any; let initialState: any; @@ -20,7 +20,7 @@ describe('OpenaireStateService', () => { function init(mode: string) { if (mode === 'empty') { initialState = { - openaire: { + notifications: { brokerTopic: { topics: [], processing: false, @@ -34,12 +34,12 @@ describe('OpenaireStateService', () => { }; } else { initialState = { - openaire: { + notifications: { brokerTopic: { topics: [ - openaireBrokerTopicObjectMorePid, - openaireBrokerTopicObjectMoreAbstract, - openaireBrokerTopicObjectMissingPid + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMissingPid ], processing: false, loaded: true, @@ -58,25 +58,25 @@ describe('OpenaireStateService', () => { init('empty'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ openaire: openaireReducers } as any), + StoreModule.forRoot({ notifications: notificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: OpenaireStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new OpenaireStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); - describe('getOpenaireBrokerTopics', () => { + describe('getNotificationsBrokerTopics', () => { it('Should return an empty array', () => { - const result = service.getOpenaireBrokerTopics(); + const result = service.getNotificationsBrokerTopics(); const expected = cold('(a)', { a: [] }); @@ -84,9 +84,9 @@ describe('OpenaireStateService', () => { }); }); - describe('getOpenaireBrokerTopicsTotalPages', () => { + describe('getNotificationsBrokerTopicsTotalPages', () => { it('Should return zero (0)', () => { - const result = service.getOpenaireBrokerTopicsTotalPages(); + const result = service.getNotificationsBrokerTopicsTotalPages(); const expected = cold('(a)', { a: 0 }); @@ -94,9 +94,9 @@ describe('OpenaireStateService', () => { }); }); - describe('getOpenaireBrokerTopicsCurrentPage', () => { + describe('getNotificationsBrokerTopicsCurrentPage', () => { it('Should return minus one (0)', () => { - const result = service.getOpenaireBrokerTopicsCurrentPage(); + const result = service.getNotificationsBrokerTopicsCurrentPage(); const expected = cold('(a)', { a: 0 }); @@ -104,9 +104,9 @@ describe('OpenaireStateService', () => { }); }); - describe('getOpenaireBrokerTopicsTotals', () => { + describe('getNotificationsBrokerTopicsTotals', () => { it('Should return zero (0)', () => { - const result = service.getOpenaireBrokerTopicsTotals(); + const result = service.getNotificationsBrokerTopicsTotals(); const expected = cold('(a)', { a: 0 }); @@ -114,9 +114,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsLoading', () => { + describe('isNotificationsBrokerTopicsLoading', () => { it('Should return TRUE', () => { - const result = service.isOpenaireBrokerTopicsLoading(); + const result = service.isNotificationsBrokerTopicsLoading(); const expected = cold('(a)', { a: true }); @@ -124,9 +124,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsLoaded', () => { + describe('isNotificationsBrokerTopicsLoaded', () => { it('Should return FALSE', () => { - const result = service.isOpenaireBrokerTopicsLoaded(); + const result = service.isNotificationsBrokerTopicsLoaded(); const expected = cold('(a)', { a: false }); @@ -134,9 +134,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsProcessing', () => { + describe('isNotificationsBrokerTopicsProcessing', () => { it('Should return FALSE', () => { - const result = service.isOpenaireBrokerTopicsProcessing(); + const result = service.isNotificationsBrokerTopicsProcessing(); const expected = cold('(a)', { a: false }); @@ -150,39 +150,39 @@ describe('OpenaireStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ openaire: openaireReducers } as any), + StoreModule.forRoot({ notifications: notificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: OpenaireStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new OpenaireStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); - describe('getOpenaireBrokerTopics', () => { + describe('getNotificationsBrokerTopics', () => { it('Should return an array of topics', () => { - const result = service.getOpenaireBrokerTopics(); + const result = service.getNotificationsBrokerTopics(); const expected = cold('(a)', { a: [ - openaireBrokerTopicObjectMorePid, - openaireBrokerTopicObjectMoreAbstract, - openaireBrokerTopicObjectMissingPid + notificationsBrokerTopicObjectMorePid, + notificationsBrokerTopicObjectMoreAbstract, + notificationsBrokerTopicObjectMissingPid ] }); expect(result).toBeObservable(expected); }); }); - describe('getOpenaireBrokerTopicsTotalPages', () => { + describe('getNotificationsBrokerTopicsTotalPages', () => { it('Should return one (1)', () => { - const result = service.getOpenaireBrokerTopicsTotalPages(); + const result = service.getNotificationsBrokerTopicsTotalPages(); const expected = cold('(a)', { a: 1 }); @@ -190,9 +190,9 @@ describe('OpenaireStateService', () => { }); }); - describe('getOpenaireBrokerTopicsCurrentPage', () => { + describe('getNotificationsBrokerTopicsCurrentPage', () => { it('Should return minus zero (1)', () => { - const result = service.getOpenaireBrokerTopicsCurrentPage(); + const result = service.getNotificationsBrokerTopicsCurrentPage(); const expected = cold('(a)', { a: 1 }); @@ -200,9 +200,9 @@ describe('OpenaireStateService', () => { }); }); - describe('getOpenaireBrokerTopicsTotals', () => { + describe('getNotificationsBrokerTopicsTotals', () => { it('Should return three (3)', () => { - const result = service.getOpenaireBrokerTopicsTotals(); + const result = service.getNotificationsBrokerTopicsTotals(); const expected = cold('(a)', { a: 3 }); @@ -210,9 +210,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsLoading', () => { + describe('isNotificationsBrokerTopicsLoading', () => { it('Should return FALSE', () => { - const result = service.isOpenaireBrokerTopicsLoading(); + const result = service.isNotificationsBrokerTopicsLoading(); const expected = cold('(a)', { a: false }); @@ -220,9 +220,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsLoaded', () => { + describe('isNotificationsBrokerTopicsLoaded', () => { it('Should return TRUE', () => { - const result = service.isOpenaireBrokerTopicsLoaded(); + const result = service.isNotificationsBrokerTopicsLoaded(); const expected = cold('(a)', { a: true }); @@ -230,9 +230,9 @@ describe('OpenaireStateService', () => { }); }); - describe('isOpenaireBrokerTopicsProcessing', () => { + describe('isNotificationsBrokerTopicsProcessing', () => { it('Should return FALSE', () => { - const result = service.isOpenaireBrokerTopicsProcessing(); + const result = service.isNotificationsBrokerTopicsProcessing(); const expected = cold('(a)', { a: false }); @@ -246,28 +246,28 @@ describe('OpenaireStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ openaire: openaireReducers } as any), + StoreModule.forRoot({ notifications: notificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: OpenaireStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new OpenaireStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); - describe('dispatchRetrieveOpenaireBrokerTopics', () => { + describe('dispatchRetrieveNotificationsBrokerTopics', () => { it('Should call store.dispatch', () => { const elementsPerPage = 3; const currentPage = 1; const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage); - service.dispatchRetrieveOpenaireBrokerTopics(elementsPerPage, currentPage); + service.dispatchRetrieveNotificationsBrokerTopics(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 new file mode 100644 index 00000000000..c81c924465e --- /dev/null +++ b/src/app/notifications/notifications-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 { + getNotificationsBrokerTopicsCurrentPageSelector, + getNotificationsBrokerTopicsTotalPagesSelector, + getNotificationsBrokerTopicsTotalsSelector, + isNotificationsBrokerTopicsLoadedSelector, + notificationsBrokerTopicsObjectSelector, + isNotificationsBrokerTopicsProcessingSelector +} 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'; + +/** + * The service handling the Notifications State. + */ +@Injectable() +export class NotificationsStateService { + + /** + * Initialize the service variables. + * @param {Store<NotificationsState>} store + */ + constructor(private store: Store<NotificationsState>) { } + + // Notifications Broker topics + // -------------------------------------------------------------------------- + + /** + * Returns the list of Notifications Broker topics from the state. + * + * @return Observable<NotificationsBrokerTopicObject> + * The list of Notifications Broker topics. + */ + public getNotificationsBrokerTopics(): Observable<NotificationsBrokerTopicObject[]> { + return this.store.pipe(select(notificationsBrokerTopicsObjectSelector())); + } + + /** + * Returns the information about the loading status of the Notifications Broker topics (if it's running or not). + * + * @return Observable<boolean> + * 'true' if the topics are loading, 'false' otherwise. + */ + public isNotificationsBrokerTopicsLoading(): Observable<boolean> { + return this.store.pipe( + select(isNotificationsBrokerTopicsLoadedSelector), + map((loaded: boolean) => !loaded) + ); + } + + /** + * Returns the information about the loading status of the Notifications Broker topics (whether or not they were loaded). + * + * @return Observable<boolean> + * 'true' if the topics are loaded, 'false' otherwise. + */ + public isNotificationsBrokerTopicsLoaded(): Observable<boolean> { + return this.store.pipe(select(isNotificationsBrokerTopicsLoadedSelector)); + } + + /** + * Returns the information about the processing status of the Notifications Broker topics (if it's running or not). + * + * @return Observable<boolean> + * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. + */ + public isNotificationsBrokerTopicsProcessing(): Observable<boolean> { + return this.store.pipe(select(isNotificationsBrokerTopicsProcessingSelector)); + } + + /** + * Returns, from the state, the total available pages of the Notifications Broker topics. + * + * @return Observable<number> + * The number of the Notifications Broker topics pages. + */ + public getNotificationsBrokerTopicsTotalPages(): Observable<number> { + return this.store.pipe(select(getNotificationsBrokerTopicsTotalPagesSelector)); + } + + /** + * Returns the current page of the Notifications Broker topics, from the state. + * + * @return Observable<number> + * The number of the current Notifications Broker topics page. + */ + public getNotificationsBrokerTopicsCurrentPage(): Observable<number> { + return this.store.pipe(select(getNotificationsBrokerTopicsCurrentPageSelector)); + } + + /** + * Returns the total number of the Notifications Broker topics. + * + * @return Observable<number> + * The number of the Notifications Broker topics. + */ + public getNotificationsBrokerTopicsTotals(): Observable<number> { + return this.store.pipe(select(getNotificationsBrokerTopicsTotalsSelector)); + } + + /** + * Dispatch a request to change the Notifications 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 dispatchRetrieveNotificationsBrokerTopics(elementsPerPage: number, currentPage: number): void { + this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage)); + } +} diff --git a/src/app/notifications/notifications.effects.ts b/src/app/notifications/notifications.effects.ts new file mode 100644 index 00000000000..cbc76a5b3eb --- /dev/null +++ b/src/app/notifications/notifications.effects.ts @@ -0,0 +1,5 @@ +import { NotificationsBrokerTopicsEffects } from './broker/topics/notifications-broker-topics.effects'; + +export const notificationsEffects = [ + NotificationsBrokerTopicsEffects +]; diff --git a/src/app/openaire/openaire.module.ts b/src/app/notifications/notifications.module.ts similarity index 50% rename from src/app/openaire/openaire.module.ts rename to src/app/notifications/notifications.module.ts index ac5d4e72872..4b0ba3cfd18 100644 --- a/src/app/openaire/openaire.module.ts +++ b/src/app/notifications/notifications.module.ts @@ -6,14 +6,14 @@ 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 { NotificationsBrokerTopicsComponent } from './broker/topics/notifications-broker-topics.component'; +import { NotificationsBrokerEventsComponent } from './broker/events/notifications-broker-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 { TranslateModule } from '@ngx-translate/core'; import { SearchModule } from '../shared/search/search.module'; @@ -22,14 +22,14 @@ const MODULES = [ CommonModule, SharedModule, CoreModule.forRoot(), - StoreModule.forFeature('openaire', openaireReducers, storeModuleConfig as StoreConfig<OpenaireState, Action>), - EffectsModule.forFeature(openaireEffects), + StoreModule.forFeature('notifications', notificationsReducers, storeModuleConfig as StoreConfig<NotificationsState, Action>), + EffectsModule.forFeature(notificationsEffects), TranslateModule ]; const COMPONENTS = [ - OpenaireBrokerTopicsComponent, - OpenaireBrokerEventsComponent + NotificationsBrokerTopicsComponent, + NotificationsBrokerEventsComponent ]; const DIRECTIVES = [ ]; @@ -39,10 +39,10 @@ const ENTRY_COMPONENTS = [ ]; const PROVIDERS = [ - OpenaireStateService, - OpenaireBrokerTopicsService, - OpenaireBrokerTopicRestService, - OpenaireBrokerEventRestService + NotificationsStateService, + NotificationsBrokerTopicsService, + NotificationsBrokerTopicRestService, + NotificationsBrokerEventRestService ]; @NgModule({ @@ -70,5 +70,5 @@ const PROVIDERS = [ /** * This module handles all components that are necessary for the OpenAIRE components */ -export class OpenaireModule { +export class NotificationsModule { } diff --git a/src/app/notifications/notifications.reducer.ts b/src/app/notifications/notifications.reducer.ts new file mode 100644 index 00000000000..b3dc54d5249 --- /dev/null +++ b/src/app/notifications/notifications.reducer.ts @@ -0,0 +1,16 @@ +import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; + +import { notificationsBrokerTopicsReducer, NotificationsBrokerTopicState, } from './broker/topics/notifications-broker-topics.reducer'; + +/** + * The OpenAIRE State + */ +export interface NotificationsState { + 'brokerTopic': NotificationsBrokerTopicState; +} + +export const notificationsReducers: ActionReducerMap<NotificationsState> = { + brokerTopic: notificationsBrokerTopicsReducer, +}; + +export const notificationsSelector = createFeatureSelector<NotificationsState>('notifications'); diff --git a/src/app/notifications/selectors.ts b/src/app/notifications/selectors.ts new file mode 100644 index 00000000000..7474aa3adc8 --- /dev/null +++ b/src/app/notifications/selectors.ts @@ -0,0 +1,79 @@ +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'; + +/** + * Returns the Notifications state. + * @function _getNotificationsState + * @param {AppState} state Top level state. + * @return {NotificationsState} + */ +const _getNotificationsState = (state: any) => state.notifications; + +// Notifications Broker topics +// ---------------------------------------------------------------------------- + +/** + * Returns the Notifications Broker topics State. + * @function notificationsBrokerTopicsStateSelector + * @return {NotificationsBrokerTopicState} + */ +export function notificationsBrokerTopicsStateSelector(): MemoizedSelector<NotificationsState, NotificationsBrokerTopicState> { + return subStateSelector<NotificationsState,NotificationsBrokerTopicState>(notificationsSelector, 'brokerTopic'); +} + +/** + * Returns the Notifications Broker topics list. + * @function notificationsBrokerTopicsObjectSelector + * @return {NotificationsBrokerTopicObject[]} + */ +export function notificationsBrokerTopicsObjectSelector(): MemoizedSelector<NotificationsState, NotificationsBrokerTopicObject[]> { + return subStateSelector<NotificationsState, NotificationsBrokerTopicObject[]>(notificationsBrokerTopicsStateSelector(), 'topics'); +} + +/** + * Returns true if the Notifications Broker topics are loaded. + * @function isNotificationsBrokerTopicsLoadedSelector + * @return {boolean} + */ +export const isNotificationsBrokerTopicsLoadedSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerTopic.loaded +); + +/** + * Returns true if the deduplication sets are processing. + * @function isDeduplicationSetsProcessingSelector + * @return {boolean} + */ +export const isNotificationsBrokerTopicsProcessingSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerTopic.processing +); + +/** + * Returns the total available pages of Notifications Broker topics. + * @function getNotificationsBrokerTopicsTotalPagesSelector + * @return {number} + */ +export const getNotificationsBrokerTopicsTotalPagesSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerTopic.totalPages +); + +/** + * Returns the current page of Notifications Broker topics. + * @function getNotificationsBrokerTopicsCurrentPageSelector + * @return {number} + */ +export const getNotificationsBrokerTopicsCurrentPageSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerTopic.currentPage +); + +/** + * Returns the total number of Notifications Broker topics. + * @function getNotificationsBrokerTopicsTotalsSelector + * @return {number} + */ +export const getNotificationsBrokerTopicsTotalsSelector = createSelector(_getNotificationsState, + (state: NotificationsState) => state.brokerTopic.totalElements +); 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 deleted file mode 100644 index b4ee60558bc..00000000000 --- a/src/app/openaire/broker/topics/openaire-broker-topics.reducer.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index 6ae596117f7..00000000000 --- a/src/app/openaire/broker/topics/openaire-broker-topics.reducer.ts +++ /dev/null @@ -1,72 +0,0 @@ -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.ts b/src/app/openaire/broker/topics/openaire-broker-topics.service.ts deleted file mode 100644 index 17f189922f1..00000000000 --- a/src/app/openaire/broker/topics/openaire-broker-topics.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -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<PaginatedList<OpenaireBrokerTopicObject>> - * The list of OpenAIRE Broker topics. - */ - public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<OpenaireBrokerTopicObject>> { - 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<PaginatedList<OpenaireBrokerTopicObject>>) => !rd.isResponsePending), - map((rd: RemoteData<PaginatedList<OpenaireBrokerTopicObject>>) => { - 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.ts b/src/app/openaire/openaire-state.service.ts deleted file mode 100644 index 10dd739ae5c..00000000000 --- a/src/app/openaire/openaire-state.service.ts +++ /dev/null @@ -1,116 +0,0 @@ -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<OpenaireState>} store - */ - constructor(private store: Store<OpenaireState>) { } - - // OpenAIRE Broker topics - // -------------------------------------------------------------------------- - - /** - * Returns the list of OpenAIRE Broker topics from the state. - * - * @return Observable<OpenaireBrokerTopicObject> - * The list of OpenAIRE Broker topics. - */ - public getOpenaireBrokerTopics(): Observable<OpenaireBrokerTopicObject[]> { - 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<boolean> - * 'true' if the topics are loading, 'false' otherwise. - */ - public isOpenaireBrokerTopicsLoading(): Observable<boolean> { - 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<boolean> - * 'true' if the topics are loaded, 'false' otherwise. - */ - public isOpenaireBrokerTopicsLoaded(): Observable<boolean> { - 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<boolean> - * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. - */ - public isOpenaireBrokerTopicsProcessing(): Observable<boolean> { - return this.store.pipe(select(sOpenaireBrokerTopicsProcessingSelector)); - } - - /** - * Returns, from the state, the total available pages of the OpenAIRE Broker topics. - * - * @return Observable<number> - * The number of the OpenAIRE Broker topics pages. - */ - public getOpenaireBrokerTopicsTotalPages(): Observable<number> { - return this.store.pipe(select(getOpenaireBrokerTopicsTotalPagesSelector)); - } - - /** - * Returns the current page of the OpenAIRE Broker topics, from the state. - * - * @return Observable<number> - * The number of the current OpenAIRE Broker topics page. - */ - public getOpenaireBrokerTopicsCurrentPage(): Observable<number> { - return this.store.pipe(select(getOpenaireBrokerTopicsCurrentPageSelector)); - } - - /** - * Returns the total number of the OpenAIRE Broker topics. - * - * @return Observable<number> - * The number of the OpenAIRE Broker topics. - */ - public getOpenaireBrokerTopicsTotals(): Observable<number> { - 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 deleted file mode 100644 index 9861c1a921c..00000000000 --- a/src/app/openaire/openaire.effects.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { OpenaireBrokerTopicsEffects } from './broker/topics/openaire-broker-topics.effects'; - -export const openaireEffects = [ - OpenaireBrokerTopicsEffects -]; diff --git a/src/app/openaire/openaire.reducer.ts b/src/app/openaire/openaire.reducer.ts deleted file mode 100644 index 9ead098329e..00000000000 --- a/src/app/openaire/openaire.reducer.ts +++ /dev/null @@ -1,16 +0,0 @@ -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<OpenaireState> = { - brokerTopic: openaireBrokerTopicsReducer, -}; - -export const openaireSelector = createFeatureSelector<OpenaireState>('openaire'); diff --git a/src/app/openaire/selectors.ts b/src/app/openaire/selectors.ts deleted file mode 100644 index fc3508eef4a..00000000000 --- a/src/app/openaire/selectors.ts +++ /dev/null @@ -1,79 +0,0 @@ -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<OpenaireState, OpenaireBrokerTopicState> { - return subStateSelector<OpenaireState,OpenaireBrokerTopicState>(openaireSelector, 'brokerTopic'); -} - -/** - * Returns the OpenAIRE Broker topics list. - * @function openaireBrokerTopicsObjectSelector - * @return {OpenaireBrokerTopicObject[]} - */ -export function openaireBrokerTopicsObjectSelector(): MemoizedSelector<OpenaireState, OpenaireBrokerTopicObject[]> { - return subStateSelector<OpenaireState, OpenaireBrokerTopicObject[]>(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/notifications.mock.ts similarity index 92% rename from src/app/shared/mocks/openaire.mock.ts rename to src/app/shared/mocks/notifications.mock.ts index 908aae1f679..2e9303c3a35 100644 --- a/src/app/shared/mocks/openaire.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1,11 +1,11 @@ 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 { 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 { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { OpenaireStateService } from '../../openaire/openaire-state.service'; +import { NotificationsStateService } from '../../notifications/notifications-state.service'; import { Item } from '../../core/shared/item.model'; import { createNoContentRemoteDataObject$, @@ -1210,7 +1210,7 @@ export const ItemMockPid10: Item = Object.assign( } ); -export const OpenaireMockDspaceObject: SearchResult<DSpaceObject> = Object.assign( +export const NotificationsMockDspaceObject: SearchResult<DSpaceObject> = Object.assign( new SearchResult<DSpaceObject>(), { handle: '10713/29832', @@ -1332,7 +1332,7 @@ export const OpenaireMockDspaceObject: SearchResult<DSpaceObject> = Object.assig // Topics // ------------------------------------------------------------------------------- -export const openaireBrokerTopicObjectMorePid: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMorePid: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MORE!PID', name: 'ENRICH/MORE/PID', @@ -1345,7 +1345,7 @@ export const openaireBrokerTopicObjectMorePid: OpenaireBrokerTopicObject = { } }; -export const openaireBrokerTopicObjectMoreAbstract: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMoreAbstract: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MORE!ABSTRACT', name: 'ENRICH/MORE/ABSTRACT', @@ -1358,7 +1358,7 @@ export const openaireBrokerTopicObjectMoreAbstract: OpenaireBrokerTopicObject = } }; -export const openaireBrokerTopicObjectMissingPid: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMissingPid: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!PID', name: 'ENRICH/MISSING/PID', @@ -1371,7 +1371,7 @@ export const openaireBrokerTopicObjectMissingPid: OpenaireBrokerTopicObject = { } }; -export const openaireBrokerTopicObjectMissingAbstract: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMissingAbstract: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!ABSTRACT', name: 'ENRICH/MISSING/ABSTRACT', @@ -1384,7 +1384,7 @@ export const openaireBrokerTopicObjectMissingAbstract: OpenaireBrokerTopicObject } }; -export const openaireBrokerTopicObjectMissingAcm: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMissingAcm: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!SUBJECT!ACM', name: 'ENRICH/MISSING/SUBJECT/ACM', @@ -1397,7 +1397,7 @@ export const openaireBrokerTopicObjectMissingAcm: OpenaireBrokerTopicObject = { } }; -export const openaireBrokerTopicObjectMissingProject: OpenaireBrokerTopicObject = { +export const notificationsBrokerTopicObjectMissingProject: NotificationsBrokerTopicObject = { type: new ResourceType('nbtopic'), id: 'ENRICH!MISSING!PROJECT', name: 'ENRICH/MISSING/PROJECT', @@ -1413,7 +1413,7 @@ export const openaireBrokerTopicObjectMissingProject: OpenaireBrokerTopicObject // Events // ------------------------------------------------------------------------------- -export const openaireBrokerEventObjectMissingPid: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174001', uuid: '123e4567-e89b-12d3-a456-426614174001', type: new ResourceType('nbevent'), @@ -1449,10 +1449,10 @@ export const openaireBrokerEventObjectMissingPid: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingPid2: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid2: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174004', uuid: '123e4567-e89b-12d3-a456-426614174004', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), 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, @@ -1485,10 +1485,10 @@ export const openaireBrokerEventObjectMissingPid2: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingPid3: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid3: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174005', uuid: '123e4567-e89b-12d3-a456-426614174005', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), originalId: 'oai:www.openstarts.units.it:10077/554', title: 'Sustainable development', trust: 0.375, @@ -1521,10 +1521,10 @@ export const openaireBrokerEventObjectMissingPid3: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingPid4: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid4: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174006', uuid: '123e4567-e89b-12d3-a456-426614174006', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), originalId: 'oai:www.openstarts.units.it:10077/10787', title: 'Reply to Critics', trust: 1.0, @@ -1557,10 +1557,10 @@ export const openaireBrokerEventObjectMissingPid4: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingPid5: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid5: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174007', uuid: '123e4567-e89b-12d3-a456-426614174007', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), 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, @@ -1593,10 +1593,10 @@ export const openaireBrokerEventObjectMissingPid5: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingPid6: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingPid6: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174008', uuid: '123e4567-e89b-12d3-a456-426614174008', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), originalId: 'oai:www.openstarts.units.it:10077/29860', title: 'Donald Davidson', trust: 0.375, @@ -1629,10 +1629,10 @@ export const openaireBrokerEventObjectMissingPid6: OpenaireBrokerEventObject = { related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingAbstract: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingAbstract: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174009', uuid: '123e4567-e89b-12d3-a456-426614174009', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), originalId: 'oai:www.openstarts.units.it:10077/21110', title: 'Missing abstract article', trust: 0.751, @@ -1665,10 +1665,10 @@ export const openaireBrokerEventObjectMissingAbstract: OpenaireBrokerEventObject related: observableOf(createSuccessfulRemoteDataObject(ItemMockPid10)) }; -export const openaireBrokerEventObjectMissingProjectFound: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingProjectFound: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174002', uuid: '123e4567-e89b-12d3-a456-426614174002', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), 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, @@ -1701,10 +1701,10 @@ export const openaireBrokerEventObjectMissingProjectFound: OpenaireBrokerEventOb related: createSuccessfulRemoteDataObject$(ItemMockPid10) }; -export const openaireBrokerEventObjectMissingProjectNotFound: OpenaireBrokerEventObject = { +export const notificationsBrokerEventObjectMissingProjectNotFound: NotificationsBrokerEventObject = { id: '123e4567-e89b-12d3-a456-426614174003', uuid: '123e4567-e89b-12d3-a456-426614174003', - type: new ResourceType('openaireBrokerEvent'), + type: new ResourceType('notificationsBrokerEvent'), 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, @@ -1741,37 +1741,37 @@ export const openaireBrokerEventObjectMissingProjectNotFound: OpenaireBrokerEven // ------------------------------------------------------------------------------- /** - * Mock for [[OpenaireStateService]] + * Mock for [[NotificationsStateService]] */ -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'), +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'), dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction') }); } /** - * Mock for [[OpenaireBrokerTopicRestService]] + * Mock for [[NotificationsBrokerTopicRestService]] */ -export function getMockOpenaireBrokerTopicRestService(): OpenaireBrokerTopicRestService { - return jasmine.createSpyObj('OpenaireBrokerTopicRestService', { +export function getMockNotificationsBrokerTopicRestService(): NotificationsBrokerTopicRestService { + return jasmine.createSpyObj('NotificationsBrokerTopicRestService', { getTopics: jasmine.createSpy('getTopics'), getTopic: jasmine.createSpy('getTopic'), }); } /** - * Mock for [[OpenaireBrokerEventRestService]] + * Mock for [[NotificationsBrokerEventRestService]] */ -export function getMockOpenaireBrokerEventRestService(): OpenaireBrokerEventRestService { - return jasmine.createSpyObj('OpenaireBrokerEventRestService', { +export function getMockNotificationsBrokerEventRestService(): NotificationsBrokerEventRestService { + return jasmine.createSpyObj('NotificationsBrokerEventRestService', { getEventsByTopic: jasmine.createSpy('getEventsByTopic'), getEvent: jasmine.createSpy('getEvent'), patchEvent: jasmine.createSpy('patchEvent'), @@ -1782,7 +1782,7 @@ export function getMockOpenaireBrokerEventRestService(): OpenaireBrokerEventRest } /** - * Mock for [[OpenaireBrokerEventRestService]] + * Mock for [[NotificationsBrokerEventRestService]] */ export function getMockSuggestionsService(): any { return jasmine.createSpyObj('SuggestionsService', { diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 360e50790a3..674254e6057 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -479,13 +479,13 @@ "admin.access-control.groups.form.return": "Back", - "admin.notifications.openairebroker.breadcrumbs": "OpenAIRE Broker", + "admin.notifications.broker.breadcrumbs": "Notifications Broker", - "admin.notifications.openairebroker.page.title": "OpenAIRE Broker", + "admin.notifications.event.breadcrumbs": "Broker Suggestions", - "admin.notifications.openaireevent.breadcrumbs": "OpenAIRE Broker Suggestions", + "admin.notifications.event.page.title": "Broker Suggestions", - "admin.notifications.openaireevent.page.title": "OpenAIRE Broker Suggestions", + "admin.notifications.broker.page.title": "Notifications Broker", "admin.search.breadcrumbs": "Administrative Search", @@ -2544,7 +2544,7 @@ "menu.section.notifications": "Notifications", - "menu.section.notifications_openaire_broker": "OpenAIRE Broker", + "menu.section.notifications_broker": "Notifications Broker", "menu.section.notifications_reciter": "Publication Claim", @@ -2713,125 +2713,125 @@ "none.listelement.badge": "Item", - "openaire.broker.title": "OpenAIRE Broker", + "notifications.broker.title": "{{source}} Broker", - "openaire.broker.topics.description": "Below you can see all the topics received from the subscriptions to OpenAIRE.", + "notifications.broker.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.", - "openaire.broker.topics": "Current Topics", + "notifications.broker.topics": "Current Topics", - "openaire.broker.table.topic": "Topic", + "notifications.broker.table.topic": "Topic", - "openaire.broker.table.last-event": "Last Event", + "notifications.broker.table.last-event": "Last Event", - "openaire.broker.table.actions": "Actions", + "notifications.broker.table.actions": "Actions", - "openaire.broker.button.detail": "Show details", + "notifications.broker.button.detail": "Show details", - "openaire.broker.noTopics": "No topics found.", + "notifications.broker.noTopics": "No topics found.", - "openaire.broker.topic.error.service.retrieve": "An error occurred while loading the OpenAIRE Broker topics", + "notifications.events.title": "{{source}} Broker Suggestions", - "openaire.broker.loading": "Loading ...", + "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Notifications Broker topics", - "openaire.events.title": "OpenAIRE Broker Suggestions", + "notifications.broker.events.description": "Below the list of all the suggestions, received from {{source}}, for the selected topic.", - "openaire.broker.events.description": "Below the list of all the suggestions, received from OpenAIRE, for the selected topic.", + "notifications.broker.loading": "Loading ...", - "openaire.broker.events.topic": "Topic:", + "notifications.broker.events.topic": "Topic:", - "openaire.broker.noEvents": "No suggestions found.", + "notifications.broker.noEvents": "No suggestions found.", - "openaire.broker.event.table.trust": "Trust", + "notifications.broker.event.table.trust": "Trust", - "openaire.broker.event.table.publication": "Publication", + "notifications.broker.event.table.publication": "Publication", - "openaire.broker.event.table.details": "Details", + "notifications.broker.event.table.details": "Details", - "openaire.broker.event.table.project-details": "Project details", + "notifications.broker.event.table.project-details": "Project details", - "openaire.broker.event.table.actions": "Actions", + "notifications.broker.event.table.actions": "Actions", - "openaire.broker.event.action.accept": "Accept suggestion", + "notifications.broker.event.action.accept": "Accept suggestion", - "openaire.broker.event.action.ignore": "Ignore suggestion", + "notifications.broker.event.action.ignore": "Ignore suggestion", - "openaire.broker.event.action.reject": "Reject suggestion", + "notifications.broker.event.action.reject": "Reject suggestion", - "openaire.broker.event.action.import": "Import project and accept suggestion", + "notifications.broker.event.action.import": "Import project and accept suggestion", - "openaire.broker.event.table.pidtype": "PID Type:", + "notifications.broker.event.table.pidtype": "PID Type:", - "openaire.broker.event.table.pidvalue": "PID Value:", + "notifications.broker.event.table.pidvalue": "PID Value:", - "openaire.broker.event.table.subjectValue": "Subject Value:", + "notifications.broker.event.table.subjectValue": "Subject Value:", - "openaire.broker.event.table.abstract": "Abstract:", + "notifications.broker.event.table.abstract": "Abstract:", - "openaire.broker.event.table.suggestedProject": "OpenAIRE Suggested Project data", + "notifications.broker.event.table.suggestedProject": "OpenAIRE Suggested Project data", - "openaire.broker.event.table.project": "Project title:", + "notifications.broker.event.table.project": "Project title:", - "openaire.broker.event.table.acronym": "Acronym:", + "notifications.broker.event.table.acronym": "Acronym:", - "openaire.broker.event.table.code": "Code:", + "notifications.broker.event.table.code": "Code:", - "openaire.broker.event.table.funder": "Funder:", + "notifications.broker.event.table.funder": "Funder:", - "openaire.broker.event.table.fundingProgram": "Funding program:", + "notifications.broker.event.table.fundingProgram": "Funding program:", - "openaire.broker.event.table.jurisdiction": "Jurisdiction:", + "notifications.broker.event.table.jurisdiction": "Jurisdiction:", - "openaire.broker.events.back": "Back to topics", + "notifications.broker.events.back": "Back to topics", - "openaire.broker.event.table.less": "Show less", + "notifications.broker.event.table.less": "Show less", - "openaire.broker.event.table.more": "Show more", + "notifications.broker.event.table.more": "Show more", - "openaire.broker.event.project.found": "Bound to the local record:", + "notifications.broker.event.project.found": "Bound to the local record:", - "openaire.broker.event.project.notFound": "No local record found", + "notifications.broker.event.project.notFound": "No local record found", - "openaire.broker.event.sure": "Are you sure?", + "notifications.broker.event.sure": "Are you sure?", - "openaire.broker.event.ignore.description": "This operation can't be undone. Ignore this suggestion?", + "notifications.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?", + "notifications.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.", + "notifications.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", + "notifications.broker.event.action.cancel": "Cancel", - "openaire.broker.event.action.saved": "Your decision has been saved successfully.", + "notifications.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.", + "notifications.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", + "notifications.broker.event.modal.project.title": "Choose a project to bound", - "openaire.broker.event.modal.project.publication": "Publication:", + "notifications.broker.event.modal.project.publication": "Publication:", - "openaire.broker.event.modal.project.bountToLocal": "Bound to the local record:", + "notifications.broker.event.modal.project.bountToLocal": "Bound to the local record:", - "openaire.broker.event.modal.project.select": "Project search", + "notifications.broker.event.modal.project.select": "Project search", - "openaire.broker.event.modal.project.search": "Search", + "notifications.broker.event.modal.project.search": "Search", - "openaire.broker.event.modal.project.clear": "Clear", + "notifications.broker.event.modal.project.clear": "Clear", - "openaire.broker.event.modal.project.cancel": "Cancel", + "notifications.broker.event.modal.project.cancel": "Cancel", - "openaire.broker.event.modal.project.bound": "Bound project", + "notifications.broker.event.modal.project.bound": "Bound project", - "openaire.broker.event.modal.project.placeholder": "Enter a project name", + "notifications.broker.event.modal.project.placeholder": "Enter a project name", - "openaire.broker.event.modal.project.notFound": "No project found.", + "notifications.broker.event.modal.project.notFound": "No project found.", - "openaire.broker.event.project.bounded": "The project has been linked successfully.", + "notifications.broker.event.project.bounded": "The project has been linked successfully.", - "openaire.broker.event.project.removed": "The project has been successfully unlinked.", + "notifications.broker.event.project.removed": "The project has been successfully unlinked.", - "openaire.broker.event.project.error": "An error has occurred. No operation performed.", + "notifications.broker.event.project.error": "An error has occurred. No operation performed.", - "openaire.broker.event.reason": "Reason", + "notifications.broker.event.reason": "Reason", "orgunit.listelement.badge": "Organizational Unit", From 8ce3148dea88dc4f8d59e4f01f71bd20ef1c4122 Mon Sep 17 00:00:00 2001 From: Pratik Rajkotiya <pratik.rajkotiya@4science.com> Date: Thu, 3 Mar 2022 12:11:50 +0530 Subject: [PATCH 003/282] [CST-5337] OAIRE-ELD correction service should support multiple providers. --- ...tifications-broker-source-data.reslover.ts | 45 ++++++ ...ons-broker-source-page-resolver.service.ts | 32 ++++ ...ications-broker-source-page.component.html | 1 + ...tions-broker-source-page.component.spec.ts | 25 ++++ ...ifications-broker-source-page.component.ts | 7 + .../admin-notifications-routing.module.ts | 27 +++- .../admin-notifications.module.ts | 4 +- src/app/core/core.module.ts | 4 +- .../notifications-broker-event.model.ts | 2 +- ...ions-broker-source-object.resource-type.ts | 9 ++ .../notifications-broker-source.model.ts | 52 +++++++ ...otifications-broker-source-rest.service.ts | 133 +++++++++++++++++ .../notifications-broker-events.component.ts | 2 +- .../notifications-broker-source.actions.ts | 99 +++++++++++++ ...notifications-broker-source.component.html | 58 ++++++++ ...notifications-broker-source.component.scss | 0 ...ifications-broker-source.component.spec.ts | 25 ++++ .../notifications-broker-source.component.ts | 139 ++++++++++++++++++ .../notifications-broker-source.effects.ts | 87 +++++++++++ .../notifications-broker-source.reducer.ts | 72 +++++++++ .../notifications-broker-source.service.ts | 55 +++++++ ...notifications-broker-topics.component.html | 2 +- .../notifications-broker-topics.component.ts | 22 ++- .../notifications-broker-topics.service.ts | 17 ++- .../notifications-state.service.ts | 98 +++++++++++- .../notifications/notifications.effects.ts | 4 +- src/app/notifications/notifications.module.ts | 8 +- .../notifications/notifications.reducer.ts | 4 +- src/app/notifications/selectors.ts | 68 +++++++++ src/assets/i18n/en.json5 | 14 +- 30 files changed, 1099 insertions(+), 16 deletions(-) create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts create mode 100644 src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts create mode 100644 src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts create mode 100644 src/app/core/notifications/broker/models/notifications-broker-source.model.ts create mode 100644 src/app/core/notifications/broker/source/notifications-broker-source-rest.service.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.actions.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.component.html create mode 100644 src/app/notifications/broker/source/notifications-broker-source.component.scss create mode 100644 src/app/notifications/broker/source/notifications-broker-source.component.spec.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.component.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.effects.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.reducer.ts create mode 100644 src/app/notifications/broker/source/notifications-broker-source.service.ts 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-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts new file mode 100644 index 00000000000..114f5f7df12 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-data.reslover.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot, Router } from '@angular/router'; +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'; +/** + * This class represents a resolver that retrieve the route data before the route is activated. + */ +@Injectable() +export class SourceDataResolver implements Resolve<Observable<NotificationsBrokerSourceObject[]>> { + /** + * Initialize the effect class variables. + * @param {NotificationsBrokerSourceService} notificationsBrokerSourceService + */ + constructor( + private notificationsBrokerSourceService: NotificationsBrokerSourceService, + 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<NotificationsBrokerSourceObject[]> + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<NotificationsBrokerSourceObject[]> { + return this.notificationsBrokerSourceService.getSources(5,0).pipe( + map((sources: PaginatedList<NotificationsBrokerSourceObject>) => { + if (sources.page.length === 1) { + this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]); + } + return sources.page; + })); + } + + /** + * + * @param route url path + * @returns url path + */ + getResolvedUrl(route: ActivatedRouteSnapshot): string { + return route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/'); + } +} 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-notifications-broker-source-page-component/admin-notifications-broker-source-page-resolver.service.ts new file mode 100644 index 00000000000..8450e20c3ce --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-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 AdminNotificationsBrokerSourcePageParams { + pageId?: string; + pageSize?: number; + currentPage?: number; +} + +/** + * This class represents a resolver that retrieve the route data before the route is activated. + */ +@Injectable() +export class AdminNotificationsBrokerSourcePageResolver implements Resolve<AdminNotificationsBrokerSourcePageParams> { + + /** + * 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 + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): AdminNotificationsBrokerSourcePageParams { + 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-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 new file mode 100644 index 00000000000..57f635d5da3 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.html @@ -0,0 +1 @@ +<ds-notifications-broker-source></ds-notifications-broker-source> 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 new file mode 100644 index 00000000000..c4a3611c584 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page.component'; + +describe('AdminNotificationsBrokerSourcePageComponent', () => { + let component: AdminNotificationsBrokerSourcePageComponent; + let fixture: ComponentFixture<AdminNotificationsBrokerSourcePageComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AdminNotificationsBrokerSourcePageComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminNotificationsBrokerSourcePageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + 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 new file mode 100644 index 00000000000..1ec08948270 --- /dev/null +++ b/src/app/admin/admin-notifications/admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component.ts @@ -0,0 +1,7 @@ +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-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts index f1f46ca4f1e..4e5997e2035 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -9,13 +9,16 @@ import { AdminNotificationsBrokerTopicsPageComponent } from './admin-notificatio 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'; @NgModule({ imports: [ RouterModule.forChild([ { canActivate: [ AuthenticatedGuard ], - path: `${NOTIFICATIONS_EDIT_PATH}`, + path: `${NOTIFICATIONS_EDIT_PATH}/:sourceId`, component: AdminNotificationsBrokerTopicsPageComponent, pathMatch: 'full', resolve: { @@ -30,7 +33,23 @@ import { AdminNotificationsBrokerEventsPageResolver } from './admin-notification }, { canActivate: [ AuthenticatedGuard ], - path: `${NOTIFICATIONS_EDIT_PATH}/:id`, + path: `${NOTIFICATIONS_EDIT_PATH}`, + component: AdminNotificationsBrokerSourcePageComponent, + pathMatch: 'full', + resolve: { + breadcrumb: I18nBreadcrumbResolver, + openaireBrokerSourceParams: AdminNotificationsBrokerSourcePageResolver, + sourceData: SourceDataResolver + }, + data: { + title: 'admin.notifications.source.breadcrumbs', + breadcrumbKey: 'admin.notifications.source', + showBreadcrumbsFluid: false + } + }, + { + canActivate: [ AuthenticatedGuard ], + path: `${NOTIFICATIONS_EDIT_PATH}/:sourceId/:topicId`, component: AdminNotificationsBrokerEventsPageComponent, pathMatch: 'full', resolve: { @@ -48,8 +67,10 @@ import { AdminNotificationsBrokerEventsPageResolver } from './admin-notification providers: [ I18nBreadcrumbResolver, I18nBreadcrumbsService, + SourceDataResolver, AdminNotificationsBrokerTopicsPageResolver, - AdminNotificationsBrokerEventsPageResolver + AdminNotificationsBrokerEventsPageResolver, + AdminNotificationsBrokerSourcePageResolver ] }) /** diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts index 350e9de800b..6351498dc57 100644 --- a/src/app/admin/admin-notifications/admin-notifications.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -6,6 +6,7 @@ import { AdminNotificationsRoutingModule } from './admin-notifications-routing.m 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'; +import { AdminNotificationsBrokerSourcePageComponent } from './admin-notifications-broker-source-page-component/admin-notifications-broker-source-page.component'; @NgModule({ imports: [ @@ -17,7 +18,8 @@ import { NotificationsModule } from '../../notifications/notifications.module'; ], declarations: [ AdminNotificationsBrokerTopicsPageComponent, - AdminNotificationsBrokerEventsPageComponent + AdminNotificationsBrokerEventsPageComponent, + AdminNotificationsBrokerSourcePageComponent ], entryComponents: [] }) diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index f5a959592f3..31b405e31c4 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -164,6 +164,7 @@ 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'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -349,7 +350,8 @@ export const models = NotificationsBrokerEventObject, Root, SearchConfig, - SubmissionAccessesModel + SubmissionAccessesModel, + NotificationsBrokerSourceObject ]; @NgModule({ diff --git a/src/app/core/notifications/broker/models/notifications-broker-event.model.ts b/src/app/core/notifications/broker/models/notifications-broker-event.model.ts index ed73168e6d9..4df326f325b 100644 --- a/src/app/core/notifications/broker/models/notifications-broker-event.model.ts +++ b/src/app/core/notifications/broker/models/notifications-broker-event.model.ts @@ -20,7 +20,7 @@ export interface NotificationsBrokerEventMessageObject { /** * The interface representing the Notifications Broker event message */ -export interface OpenaireBrokerEventMessageObject{ +export interface OpenaireBrokerEventMessageObject { /** * The type of 'value' */ diff --git a/src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts b/src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts new file mode 100644 index 00000000000..e3d10dc5abf --- /dev/null +++ b/src/app/core/notifications/broker/models/notifications-broker-source-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../../shared/resource-type'; + +/** + * The resource type for the Notifications Broker source + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const NOTIFICATIONS_BROKER_SOURCE_OBJECT = new ResourceType('nbsource'); diff --git a/src/app/core/notifications/broker/models/notifications-broker-source.model.ts b/src/app/core/notifications/broker/models/notifications-broker-source.model.ts new file mode 100644 index 00000000000..3f18c3affb0 --- /dev/null +++ b/src/app/core/notifications/broker/models/notifications-broker-source.model.ts @@ -0,0 +1,52 @@ +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'; + +/** + * The interface representing the Notifications Broker source model + */ +@typedObject +export class NotificationsBrokerSourceObject implements CacheableObject { + /** + * A string representing the kind of object, e.g. community, item, … + */ + static type = NOTIFICATIONS_BROKER_SOURCE_OBJECT; + + /** + * The Notifications Broker source id + */ + @autoserialize + id: string; + + /** + * The date of the last udate from Notifications + */ + @autoserialize + lastEvent: string; + + /** + * The total number of suggestions provided by Notifications for this source + */ + @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/notifications/broker/source/notifications-broker-source-rest.service.ts b/src/app/core/notifications/broker/source/notifications-broker-source-rest.service.ts new file mode 100644 index 00000000000..ebbbe995d1a --- /dev/null +++ b/src/app/core/notifications/broker/source/notifications-broker-source-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 { NotificationsBrokerSourceObject } from '../models/notifications-broker-source.model'; +import { NOTIFICATIONS_BROKER_SOURCE_OBJECT } from '../models/notifications-broker-source-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<NotificationsBrokerSourceObject> { + /** + * The REST endpoint. + */ + protected linkPath = 'nbsources'; + + /** + * Initialize service variables + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {Store<CoreState>} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {ChangeAnalyzer<NotificationsBrokerSourceObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store<CoreState>, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: ChangeAnalyzer<NotificationsBrokerSourceObject>) { + super(); + } +} + +/** + * The service handling all Notifications Broker source REST requests. + */ +@Injectable() +@dataService(NOTIFICATIONS_BROKER_SOURCE_OBJECT) +export class NotificationsBrokerSourceRestService { + /** + * 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<NotificationsBrokerSourceObject>} comparator + */ + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer<NotificationsBrokerSourceObject>) { + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + } + + /** + * Return the list of Notifications Broker 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<RemoteData<PaginatedList<NotificationsBrokerSourceObject>>> + * The list of Notifications Broker source. + */ + public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerSourceObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerSourceObject>>> { + return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( + take(1), + mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), + ); + } + + /** + * Clear FindAll source requests from cache + */ + public clearFindAllSourceRequests() { + this.requestService.setStaleByHrefSubstring('nbsources'); + } + + /** + * Return a single Notifications Broker source. + * + * @param id + * The Notifications Broker source id + * @param linksToFollow + * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * @return Observable<RemoteData<NotificationsBrokerSourceObject>> + * The Notifications Broker source. + */ + public getSource(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerSourceObject>[]): Observable<RemoteData<NotificationsBrokerSourceObject>> { + const options = {}; + return this.dataService.getBrowseEndpoint(options, 'nbsources').pipe( + take(1), + mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) + ); + } +} diff --git a/src/app/notifications/broker/events/notifications-broker-events.component.ts b/src/app/notifications/broker/events/notifications-broker-events.component.ts index b416664fca5..7639554c55d 100644 --- a/src/app/notifications/broker/events/notifications-broker-events.component.ts +++ b/src/app/notifications/broker/events/notifications-broker-events.component.ts @@ -135,7 +135,7 @@ export class NotificationsBrokerEventsComponent implements OnInit { this.isEventPageLoading.next(true); this.activatedRoute.paramMap.pipe( - map((params) => params.get('id')), + map((params) => params.get('topicId')), take(1) ).subscribe((id: string) => { const regEx = /!/g; diff --git a/src/app/notifications/broker/source/notifications-broker-source.actions.ts b/src/app/notifications/broker/source/notifications-broker-source.actions.ts new file mode 100644 index 00000000000..a3fd9240c81 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.actions.ts @@ -0,0 +1,99 @@ +import { Action } from '@ngrx/store'; +import { type } from '../../../shared/ngrx/type'; +import { NotificationsBrokerSourceObject } from '../../../core/notifications/broker/models/notifications-broker-source.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 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'), +}; + +/* tslint:disable:max-classes-per-file */ + +/** + * An ngrx action to retrieve all the Notifications Broker source. + */ +export class RetrieveAllSourceAction implements Action { + type = NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE; + payload: { + elementsPerPage: number; + currentPage: number; + }; + + /** + * Create a new RetrieveAllSourceAction. + * + * @param elementsPerPage + * the number of source per page + * @param currentPage + * The page number to retrieve + */ + constructor(elementsPerPage: number, currentPage: number) { + this.payload = { + elementsPerPage, + currentPage + }; + } +} + +/** + * An ngrx action for retrieving 'all Notifications Broker source' error. + */ +export class RetrieveAllSourceErrorAction implements Action { + type = NotificationsBrokerSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR; +} + +/** + * An ngrx action to load the Notifications Broker source objects. + * Called by the ??? effect. + */ +export class AddSourceAction implements Action { + type = NotificationsBrokerSourceActionTypes.ADD_SOURCE; + payload: { + source: NotificationsBrokerSourceObject[]; + totalPages: number; + currentPage: number; + totalElements: number; + }; + + /** + * Create a new AddSourceAction. + * + * @param source + * the list of source + * @param totalPages + * the total available pages of source + * @param currentPage + * the current page + * @param totalElements + * the total available Notifications Broker source + */ + constructor(source: NotificationsBrokerSourceObject[], totalPages: number, currentPage: number, totalElements: number) { + this.payload = { + source, + 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 NotificationsBrokerSourceActions + = RetrieveAllSourceAction + |RetrieveAllSourceErrorAction + |AddSourceAction; diff --git a/src/app/notifications/broker/source/notifications-broker-source.component.html b/src/app/notifications/broker/source/notifications-broker-source.component.html new file mode 100644 index 00000000000..a7e1e527483 --- /dev/null +++ b/src/app/notifications/broker/source/notifications-broker-source.component.html @@ -0,0 +1,58 @@ +<div class="container"> + <div class="row"> + <div class="col-12"> + <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> + <p>{{'notifications.broker.source.description'| translate}}</p> + </div> + </div> + <div class="row"> + <div class="col-12"> + <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> + + <ds-loading class="container" *ngIf="(isSourceLoading() | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> + <ds-pagination *ngIf="!(isSourceLoading() | async)" + [paginationOptions]="paginationConfig" + [collectionSize]="(totalElements$ | async)" + [hideGear]="false" + [hideSortOptions]="true" + (paginationChange)="getNotificationsBrokerSource()"> + + <ds-loading class="container" *ngIf="(isSourceProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> + <ng-container *ngIf="!(isSourceProcessing() | async)"> + <div *ngIf="(sources$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> + {{'notifications.broker.noSource' | translate}} + </div> + <div *ngIf="(sources$|async)?.length != 0" class="table-responsive mt-2"> + <table id="epeople" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col">{{'notifications.broker.table.source' | translate}}</th> + <th scope="col">{{'notifications.broker.table.last-event' | translate}}</th> + <th scope="col">{{'notifications.broker.table.actions' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let sourceElement of (sources$ | async); let i = index"> + <td>{{sourceElement.id}}</td> + <td>{{sourceElement.lastEvent}}</td> + <td> + <div class="btn-group edit-field"> + <button + class="btn btn-outline-primary btn-sm" + title="{{'notifications.broker.button.detail' | translate }}" + [routerLink]="[sourceElement.id]"> + <span class="badge badge-info">{{sourceElement.totalEvents}}</span> + <i class="fas fa-info fa-fw"></i> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </ng-container> + </ds-pagination> + </div> + </div> + </div> + 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<NotificationsBrokerSourceComponent>; + + 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<NotificationsBrokerSourceObject[]>; + /** + * The total number of Notifications Broker sources. + */ + public totalElements$: Observable<number>; + /** + * 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<boolean> + * 'true' if the source are loading, 'false' otherwise. + */ + public isSourceLoading(): Observable<boolean> { + return this.notificationsStateService.isNotificationsBrokerSourceLoading(); + } + + /** + * Returns the information about the processing status of the Notifications Broker source (if it's running or not). + * + * @return Observable<boolean> + * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. + */ + public isSourceProcessing(): Observable<boolean> { + 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<NotificationsBrokerSourceObject>) => + 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<any>} store$ + * @param {TranslateService} translate + * @param {NotificationsService} notificationsService + * @param {NotificationsBrokerSourceService} notificationsBrokerSourceService + * @param {NotificationsBrokerSourceRestService} notificationsBrokerSourceDataService + */ + constructor( + private actions$: Actions, + private store$: Store<any>, + 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<PaginatedList<NotificationsBrokerSourceObject>> + * The list of Notifications Broker source. + */ + public getSources(elementsPerPage, currentPage): Observable<PaginatedList<NotificationsBrokerSourceObject>> { + 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<PaginatedList<NotificationsBrokerSourceObject>>) => !rd.isResponsePending), + map((rd: RemoteData<PaginatedList<NotificationsBrokerSourceObject>>) => { + 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 @@ <div class="row"> <div class="col-12"> <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> - <p>{{'notifications.broker.topics.description'| translate}}</p> + <p>{{'notifications.broker.topics.description'| translate:{source: sourceId} }}</p> </div> </div> <div class="row"> 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<NotificationsBrokerSourceObject> + * The list of Notifications Broker source. + */ + public getNotificationsBrokerSource(): Observable<NotificationsBrokerSourceObject[]> { + 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<boolean> + * 'true' if the source are loading, 'false' otherwise. + */ + public isNotificationsBrokerSourceLoading(): Observable<boolean> { + 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<boolean> + * 'true' if the source are loaded, 'false' otherwise. + */ + public isNotificationsBrokerSourceLoaded(): Observable<boolean> { + 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<boolean> + * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. + */ + public isNotificationsBrokerSourceProcessing(): Observable<boolean> { + return this.store.pipe(select(isNotificationsBrokerSourceProcessingSelector)); + } + + /** + * Returns, from the state, the total available pages of the Notifications Broker source. + * + * @return Observable<number> + * The number of the Notifications Broker source pages. + */ + public getNotificationsBrokerSourceTotalPages(): Observable<number> { + return this.store.pipe(select(getNotificationsBrokerSourceTotalPagesSelector)); + } + + /** + * Returns the current page of the Notifications Broker source, from the state. + * + * @return Observable<number> + * The number of the current Notifications Broker source page. + */ + public getNotificationsBrokerSourceCurrentPage(): Observable<number> { + return this.store.pipe(select(getNotificationsBrokerSourceCurrentPageSelector)); + } + + /** + * Returns the total number of the Notifications Broker source. + * + * @return Observable<number> + * The number of the Notifications Broker source. + */ + public getNotificationsBrokerSourceTotals(): Observable<number> { + 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<NotificationsState> = { brokerTopic: notificationsBrokerTopicsReducer, + brokerSource: notificationsBrokerSourceReducer }; export const notificationsSelector = createFeatureSelector<NotificationsState>('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<NotificationsState, NotificationsBrokerSourceState> { + return subStateSelector<NotificationsState,NotificationsBrokerSourceState>(notificationsSelector, 'brokerSource'); +} + +/** + * Returns the Notifications Broker source list. + * @function notificationsBrokerSourceObjectSelector + * @return {NotificationsBrokerSourceObject[]} + */ +export function notificationsBrokerSourceObjectSelector(): MemoizedSelector<NotificationsState, NotificationsBrokerSourceObject[]> { + return subStateSelector<NotificationsState, NotificationsBrokerSourceObject[]>(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 <pratik.rajkotiya@4science.com> Date: Thu, 10 Mar 2022 11:49:12 +0530 Subject: [PATCH 004/282] [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<PaginatedList<NotificationsBrokerSourceObject>> 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<NotificationsBrokerSourceObject> 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<NotificationsBrokerSourceComponent>; + 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<TestComponent>; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + <ds-notifications-broker-source></ds-notifications-broker-source>`; + testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; + 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<NotificationsBrokerTopicsComponent>; @@ -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<DSpaceObject> = 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 <pratik.rajkotiya@4science.com> Date: Thu, 10 Mar 2022 11:56:39 +0530 Subject: [PATCH 005/282] [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 <luca.giamminonni@4science.it> Date: Thu, 17 Mar 2022 16:53:59 +0100 Subject: [PATCH 006/282] [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 <luca.giamminonni@4science.it> Date: Wed, 6 Jul 2022 17:04:11 +0200 Subject: [PATCH 007/282] [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 @@ -<ds-notifications-broker-events></ds-notifications-broker-events> 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<AdminNotificationsBrokerEventsPageComponent>; - - 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 @@ -<ds-notifications-broker-source></ds-notifications-broker-source> 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<AdminNotificationsBrokerSourcePageComponent>; - - 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 @@ -<ds-notifications-broker-topic></ds-notifications-broker-topic> 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<AdminNotificationsBrokerTopicsPageComponent>; - - 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 @@ +<ds-quality-assurance-events></ds-quality-assurance-events> 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<AdminQualityAssuranceEventsPageComponent>; + + 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<AdminNotificationsBrokerEventsPageParams> { +export class AdminQualityAssuranceEventsPageResolver implements Resolve<AdminQualityAssuranceEventsPageParams> { /** * 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<Observable<NotificationsBrokerSourceObject[]>> { +export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSourceObject[]>> { /** * 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<NotificationsBrokerSourceObject[]> + * @returns Observable<QualityAssuranceSourceObject[]> */ - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<NotificationsBrokerSourceObject[]> { - return this.notificationsBrokerSourceService.getSources(5,0).pipe( - map((sources: PaginatedList<NotificationsBrokerSourceObject>) => { + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<QualityAssuranceSourceObject[]> { + return this.qualityAssuranceSourceService.getSources(5,0).pipe( + map((sources: PaginatedList<QualityAssuranceSourceObject>) => { 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<AdminNotificationsBrokerTopicsPageParams> { +export class AdminQualityAssuranceSourcePageResolver implements Resolve<AdminQualityAssuranceSourcePageParams> { /** * 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 @@ +<ds-quality-assurance-source></ds-quality-assurance-source> 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<AdminQualityAssuranceSourcePageComponent>; + + 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<AdminNotificationsBrokerSourcePageParams> { +export class AdminQualityAssuranceTopicsPageResolver implements Resolve<AdminQualityAssuranceTopicsPageParams> { /** * 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 @@ +<ds-quality-assurance-topic></ds-quality-assurance-topic> 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<AdminQualityAssuranceTopicsPageComponent>; + + 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<PaginatedList<NotificationsBrokerEventObject>> for the object with the given Topic', () => { + it('should return a RemoteData<PaginatedList<QualityAssuranceEventObject>> 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<NotificationsBrokerEventObject> for the object with the given URL', () => { - const result = service.getEvent(notificationsBrokerEventObjectMissingPid.id); + it('should return a RemoteData<QualityAssuranceEventObject> 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<NotificationsBrokerEventObject> { +class DataServiceImpl extends DataService<QualityAssuranceEventObject> { /** * The REST endpoint. */ @@ -44,7 +44,7 @@ class DataServiceImpl extends DataService<NotificationsBrokerEventObject> { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer<NotificationsBrokerEventObject>} comparator + * @param {ChangeAnalyzer<QualityAssuranceEventObject>} comparator */ constructor( protected requestService: RequestService, @@ -54,17 +54,17 @@ class DataServiceImpl extends DataService<NotificationsBrokerEventObject> { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer<NotificationsBrokerEventObject>) { + protected comparator: ChangeAnalyzer<QualityAssuranceEventObject>) { 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<NotificationsBrokerEventObject>} comparator + * @param {DefaultChangeAnalyzer<QualityAssuranceEventObject>} comparator */ constructor( protected requestService: RequestService, @@ -87,23 +87,23 @@ export class NotificationsBrokerEventRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<NotificationsBrokerEventObject>) { + protected comparator: DefaultChangeAnalyzer<QualityAssuranceEventObject>) { 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<RemoteData<PaginatedList<NotificationsBrokerEventObject>>> - * The list of Notifications Broker events. + * @return Observable<RemoteData<PaginatedList<QualityAssuranceEventObject>>> + * The list of Quality Assurance events. */ - public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerEventObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerEventObject>>> { + public getEventsByTopic(topic: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceEventObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceEventObject>>> { 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<RemoteData<NotificationsBrokerEventObject>> - * The Notifications Broker event. + * @return Observable<RemoteData<QualityAssuranceEventObject>> + * The Quality Assurance event. */ - public getEvent(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerEventObject>[]): Observable<RemoteData<NotificationsBrokerEventObject>> { + public getEvent(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceEventObject>[]): Observable<RemoteData<QualityAssuranceEventObject>> { 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<RestResponse> * The REST response. */ - public patchEvent(status, dso, reason?: string): Observable<RemoteData<NotificationsBrokerEventObject>> { + public patchEvent(status, dso, reason?: string): Observable<RemoteData<QualityAssuranceEventObject>> { const operation: ReplaceOperation<string>[] = [ { 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<RestResponse> * The REST response. */ - public boundProject(itemId: string, projectId: string): Observable<RemoteData<NotificationsBrokerEventObject>> { + public boundProject(itemId: string, projectId: string): Observable<RemoteData<QualityAssuranceEventObject>> { 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<RestResponse> * 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<PaginatedList<NotificationsBrokerSourceObject>> for the object with the given URL', () => { + it('should return a RemoteData<PaginatedList<QualityAssuranceSourceObject>> 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<NotificationsBrokerSourceObject> for the object with the given URL', () => { - const result = service.getSource(notificationsBrokerSourceObjectMorePid.id); + it('should return a RemoteData<QualityAssuranceSourceObject> 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<NotificationsBrokerSourceObject> { +class DataServiceImpl extends DataService<QualityAssuranceSourceObject> { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService<NotificationsBrokerSourceObject> { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer<NotificationsBrokerSourceObject>} comparator + * @param {ChangeAnalyzer<QualityAssuranceSourceObject>} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService<NotificationsBrokerSourceObject> { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer<NotificationsBrokerSourceObject>) { + protected comparator: ChangeAnalyzer<QualityAssuranceSourceObject>) { 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<NotificationsBrokerSourceObject>} comparator + * @param {DefaultChangeAnalyzer<QualityAssuranceSourceObject>} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class NotificationsBrokerSourceRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<NotificationsBrokerSourceObject>) { + protected comparator: DefaultChangeAnalyzer<QualityAssuranceSourceObject>) { 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<RemoteData<PaginatedList<NotificationsBrokerSourceObject>>> - * The list of Notifications Broker source. + * @return Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> + * The list of Quality Assurance source. */ - public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerSourceObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerSourceObject>>> { + public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { 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<RemoteData<NotificationsBrokerSourceObject>> - * The Notifications Broker source. + * @return Observable<RemoteData<QualityAssuranceSourceObject>> + * The Quality Assurance source. */ - public getSource(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerSourceObject>[]): Observable<RemoteData<NotificationsBrokerSourceObject>> { + public getSource(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { 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<PaginatedList<NotificationsBrokerTopicObject>> for the object with the given URL', () => { + it('should return a RemoteData<PaginatedList<QualityAssuranceTopicObject>> 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<NotificationsBrokerTopicObject> for the object with the given URL', () => { - const result = service.getTopic(notificationsBrokerTopicObjectMorePid.id); + it('should return a RemoteData<QualityAssuranceTopicObject> 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<NotificationsBrokerTopicObject> { +class DataServiceImpl extends DataService<QualityAssuranceTopicObject> { /** * The REST endpoint. */ @@ -42,7 +42,7 @@ class DataServiceImpl extends DataService<NotificationsBrokerTopicObject> { * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService * @param {HttpClient} http - * @param {ChangeAnalyzer<NotificationsBrokerTopicObject>} comparator + * @param {ChangeAnalyzer<QualityAssuranceTopicObject>} comparator */ constructor( protected requestService: RequestService, @@ -52,17 +52,17 @@ class DataServiceImpl extends DataService<NotificationsBrokerTopicObject> { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer<NotificationsBrokerTopicObject>) { + protected comparator: ChangeAnalyzer<QualityAssuranceTopicObject>) { 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<NotificationsBrokerTopicObject>} comparator + * @param {DefaultChangeAnalyzer<QualityAssuranceTopicObject>} comparator */ constructor( protected requestService: RequestService, @@ -85,21 +85,21 @@ export class NotificationsBrokerTopicRestService { protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<NotificationsBrokerTopicObject>) { + protected comparator: DefaultChangeAnalyzer<QualityAssuranceTopicObject>) { 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<RemoteData<PaginatedList<NotificationsBrokerTopicObject>>> - * The list of Notifications Broker topics. + * @return Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> + * The list of Quality Assurance topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<NotificationsBrokerTopicObject>[]): Observable<RemoteData<PaginatedList<NotificationsBrokerTopicObject>>> { + public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { 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<RemoteData<NotificationsBrokerTopicObject>> - * The Notifications Broker topic. + * @return Observable<RemoteData<QualityAssuranceTopicObject>> + * The Quality Assurance topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig<NotificationsBrokerTopicObject>[]): Observable<RemoteData<NotificationsBrokerTopicObject>> { + public getTopic(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { 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<PaginatedList<NotificationsBrokerSourceObject>> - * The list of Notifications Broker source. - */ - public getSources(elementsPerPage, currentPage): Observable<PaginatedList<NotificationsBrokerSourceObject>> { - 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<PaginatedList<NotificationsBrokerSourceObject>>) => !rd.isResponsePending), - map((rd: RemoteData<PaginatedList<NotificationsBrokerSourceObject>>) => { - 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<NotificationsState>) { } - // 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<NotificationsBrokerTopicObject> - * The list of Notifications Broker topics. + * @return Observable<QualityAssuranceTopicObject> + * The list of Quality Assurance topics. */ - public getNotificationsBrokerTopics(): Observable<NotificationsBrokerTopicObject[]> { - return this.store.pipe(select(notificationsBrokerTopicsObjectSelector())); + public getQualityAssuranceTopics(): Observable<QualityAssuranceTopicObject[]> { + 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<boolean> * 'true' if the topics are loading, 'false' otherwise. */ - public isNotificationsBrokerTopicsLoading(): Observable<boolean> { + public isQualityAssuranceTopicsLoading(): Observable<boolean> { 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<boolean> * 'true' if the topics are loaded, 'false' otherwise. */ - public isNotificationsBrokerTopicsLoaded(): Observable<boolean> { - return this.store.pipe(select(isNotificationsBrokerTopicsLoadedSelector)); + public isQualityAssuranceTopicsLoaded(): Observable<boolean> { + 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<boolean> * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. */ - public isNotificationsBrokerTopicsProcessing(): Observable<boolean> { - return this.store.pipe(select(isNotificationsBrokerTopicsProcessingSelector)); + public isQualityAssuranceTopicsProcessing(): Observable<boolean> { + 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<number> - * The number of the Notifications Broker topics pages. + * The number of the Quality Assurance topics pages. */ - public getNotificationsBrokerTopicsTotalPages(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerTopicsTotalPagesSelector)); + public getQualityAssuranceTopicsTotalPages(): Observable<number> { + 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<number> - * The number of the current Notifications Broker topics page. + * The number of the current Quality Assurance topics page. */ - public getNotificationsBrokerTopicsCurrentPage(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerTopicsCurrentPageSelector)); + public getQualityAssuranceTopicsCurrentPage(): Observable<number> { + 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<number> - * The number of the Notifications Broker topics. + * The number of the Quality Assurance topics. */ - public getNotificationsBrokerTopicsTotals(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerTopicsTotalsSelector)); + public getQualityAssuranceTopicsTotals(): Observable<number> { + 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<NotificationsBrokerSourceObject> - * The list of Notifications Broker source. + * @return Observable<QualityAssuranceSourceObject> + * The list of Quality Assurance source. */ - public getNotificationsBrokerSource(): Observable<NotificationsBrokerSourceObject[]> { - return this.store.pipe(select(notificationsBrokerSourceObjectSelector())); + public getQualityAssuranceSource(): Observable<QualityAssuranceSourceObject[]> { + 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<boolean> * 'true' if the source are loading, 'false' otherwise. */ - public isNotificationsBrokerSourceLoading(): Observable<boolean> { + public isQualityAssuranceSourceLoading(): Observable<boolean> { 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<boolean> * 'true' if the source are loaded, 'false' otherwise. */ - public isNotificationsBrokerSourceLoaded(): Observable<boolean> { - return this.store.pipe(select(isNotificationsBrokerSourceLoadedSelector)); + public isQualityAssuranceSourceLoaded(): Observable<boolean> { + 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<boolean> * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. */ - public isNotificationsBrokerSourceProcessing(): Observable<boolean> { - return this.store.pipe(select(isNotificationsBrokerSourceProcessingSelector)); + public isQualityAssuranceSourceProcessing(): Observable<boolean> { + 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<number> - * The number of the Notifications Broker source pages. + * The number of the Quality Assurance source pages. */ - public getNotificationsBrokerSourceTotalPages(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerSourceTotalPagesSelector)); + public getQualityAssuranceSourceTotalPages(): Observable<number> { + 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<number> - * The number of the current Notifications Broker source page. + * The number of the current Quality Assurance source page. */ - public getNotificationsBrokerSourceCurrentPage(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerSourceCurrentPageSelector)); + public getQualityAssuranceSourceCurrentPage(): Observable<number> { + 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<number> - * The number of the Notifications Broker source. + * The number of the Quality Assurance source. */ - public getNotificationsBrokerSourceTotals(): Observable<number> { - return this.store.pipe(select(getNotificationsBrokerSourceTotalsSelector)); + public getQualityAssuranceSourceTotals(): Observable<number> { + 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<NotificationsState> = { - brokerTopic: notificationsBrokerTopicsReducer, - brokerSource: notificationsBrokerSourceReducer + brokerTopic: qualityAssuranceTopicsReducer, + brokerSource: qualityAssuranceSourceReducer }; export const notificationsSelector = createFeatureSelector<NotificationsState>('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 @@ <h2 class="border-bottom pb-2">{{'notifications.events.title'| translate}}</h2> <p>{{'notifications.broker.events.description'| translate}}</p> <p> - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/notifications-broker']"> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> <i class="fas fa-angle-double-left"></i> {{'notifications.broker.events.back' | translate}} </a> @@ -23,7 +23,7 @@ <h3 class="border-bottom pb-2"> [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" [sortOptions]="paginationSortConfig" - (paginationChange)="getNotificationsBrokerEvents()"> + (paginationChange)="getQualityAssuranceEvents()"> <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> <ng-container *ngIf="!(isEventLoading | async)"> @@ -140,7 +140,7 @@ <h3 class="border-bottom pb-2"> </div> <div class="row"> <div class="col-md-12"> - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/notifications-broker']"> + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> <i class="fas fa-angle-double-left"></i> {{'notifications.broker.events.back' | translate}} </a> 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<NotificationsBrokerEventsComponent>; - let comp: NotificationsBrokerEventsComponent; +describe('QualityAssuranceEventsComponent test suite', () => { + let fixture: ComponentFixture<QualityAssuranceEventsComponent>; + 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 = ` - <ds-notifications-broker-event></ds-notifications-broker-event>`; + <ds-quality-assurance-event></ds-quality-assurance-event>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; 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<NotificationsBrokerEventData[]> = new BehaviorSubject([]); + public eventsUpdated$: BehaviorSubject<QualityAssuranceEventData[]> = new BehaviorSubject([]); /** - * The total number of Notifications Broker events. + * The total number of Quality Assurance events. * @type {Observable<number>} */ public totalElements$: Observable<number>; /** - * 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<NotificationsBrokerEventObject>) => { + this.qualityAssuranceEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<QualityAssuranceEventObject>) => { 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<NotificationsBrokerEventObject>) => { + this.qualityAssuranceEventRestService.boundProject(eventData.id, projectId).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<QualityAssuranceEventObject>) => { 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<NotificationsBrokerEventObject>) => { + this.qualityAssuranceEventRestService.removeProject(eventData.id).pipe(getFirstCompletedRemoteData()) + .subscribe((rd: RemoteData<QualityAssuranceEventObject>) => { 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<PaginatedList<NotificationsBrokerEventObject>>) => { + ).subscribe((rd: RemoteData<PaginatedList<QualityAssuranceEventObject>>) => { 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<Item>, RemoteData<Item>]) => { - 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 @@ <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> <div class="row"> <div class="col-12"> <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> - + <ds-loading class="container" *ngIf="(isSourceLoading() | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isSourceLoading() | async)" [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" [hideGear]="false" [hideSortOptions]="true" - (paginationChange)="getNotificationsBrokerSource()"> - + (paginationChange)="getQualityAssuranceSource()"> + <ds-loading class="container" *ngIf="(isSourceProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> <ng-container *ngIf="!(isSourceProcessing() | async)"> <div *ngIf="(sources$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> @@ -55,4 +55,4 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> </div> </div> </div> - + 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<NotificationsBrokerSourceComponent>; - let comp: NotificationsBrokerSourceComponent; +describe('QualityAssuranceSourceComponent test suite', () => { + let fixture: ComponentFixture<QualityAssuranceSourceComponent>; + 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 = ` - <ds-notifications-broker-source></ds-notifications-broker-source>`; + <ds-quality-assurance-source></ds-quality-assurance-source>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; 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<NotificationsBrokerSourceObject[]>; + public sources$: Observable<QualityAssuranceSourceObject[]>; /** - * The total number of Notifications Broker sources. + * The total number of Quality Assurance sources. */ public totalElements$: Observable<number>; /** @@ -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<boolean> * 'true' if the source are loading, 'false' otherwise. */ public isSourceLoading(): Observable<boolean> { - 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<boolean> * 'true' if there are operations running on the source (ex.: a REST call), 'false' otherwise. */ public isSourceProcessing(): Observable<boolean> { - 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<NotificationsBrokerSourceObject>) => + map((sources: PaginatedList<QualityAssuranceSourceObject>) => 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<any>} 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<any>, 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<PaginatedList<QualityAssuranceSourceObject>> + * The list of Quality Assurance source. + */ + public getSources(elementsPerPage, currentPage): Observable<PaginatedList<QualityAssuranceSourceObject>> { + 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<PaginatedList<QualityAssuranceSourceObject>>) => !rd.isResponsePending), + map((rd: RemoteData<PaginatedList<QualityAssuranceSourceObject>>) => { + 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 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.topics'| translate}}</h3> [collectionSize]="(totalElements$ | async)" [hideGear]="false" [hideSortOptions]="true" - (paginationChange)="getNotificationsBrokerTopics()"> + (paginationChange)="getQualityAssuranceTopics()"> <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> <ng-container *ngIf="!(isTopicsProcessing() | async)"> 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<NotificationsBrokerTopicsComponent>; - let comp: NotificationsBrokerTopicsComponent; +describe('QualityAssuranceTopicsComponent test suite', () => { + let fixture: ComponentFixture<QualityAssuranceTopicsComponent>; + 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 = ` - <ds-notifications-broker-topic></ds-notifications-broker-topic>`; + <ds-quality-assurance-topic></ds-quality-assurance-topic>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; 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<NotificationsBrokerTopicObject[]>; + public topics$: Observable<QualityAssuranceTopicObject[]>; /** - * The total number of Notifications Broker topics. + * The total number of Quality Assurance topics. */ public totalElements$: Observable<number>; /** @@ -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<boolean> * 'true' if the topics are loading, 'false' otherwise. */ public isTopicsLoading(): Observable<boolean> { - 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<boolean> * 'true' if there are operations running on the topics (ex.: a REST call), 'false' otherwise. */ public isTopicsProcessing(): Observable<boolean> { - 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<NotificationsBrokerTopicObject>) => + map((topics: PaginatedList<QualityAssuranceTopicObject>) => 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<any>} 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<any>, 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<PaginatedList<NotificationsBrokerTopicObject>> - * The list of Notifications Broker topics. + * @return Observable<PaginatedList<QualityAssuranceTopicObject>> + * The list of Quality Assurance topics. */ - public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<NotificationsBrokerTopicObject>> { + public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<QualityAssuranceTopicObject>> { 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<PaginatedList<NotificationsBrokerTopicObject>>) => !rd.isResponsePending), - map((rd: RemoteData<PaginatedList<NotificationsBrokerTopicObject>>) => { + return this.qualityAssuranceTopicRestService.getTopics(findListOptions).pipe( + find((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => !rd.isResponsePending), + map((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => { 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<NotificationsState, NotificationsBrokerTopicState> { - return subStateSelector<NotificationsState,NotificationsBrokerTopicState>(notificationsSelector, 'brokerTopic'); +export function qualityAssuranceTopicsStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceTopicState> { + return subStateSelector<NotificationsState,QualityAssuranceTopicState>(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<NotificationsState, NotificationsBrokerTopicObject[]> { - return subStateSelector<NotificationsState, NotificationsBrokerTopicObject[]>(notificationsBrokerTopicsStateSelector(), 'topics'); +export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector<NotificationsState, QualityAssuranceTopicObject[]> { + return subStateSelector<NotificationsState, QualityAssuranceTopicObject[]>(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<NotificationsState, NotificationsBrokerSourceState> { - return subStateSelector<NotificationsState,NotificationsBrokerSourceState>(notificationsSelector, 'brokerSource'); + export function qualityAssuranceSourceStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceSourceState> { + return subStateSelector<NotificationsState,QualityAssuranceSourceState>(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<NotificationsState, NotificationsBrokerSourceObject[]> { - return subStateSelector<NotificationsState, NotificationsBrokerSourceObject[]>(notificationsBrokerSourceStateSelector(), 'source'); +export function qualityAssuranceSourceObjectSelector(): MemoizedSelector<NotificationsState, QualityAssuranceSourceObject[]> { + return subStateSelector<NotificationsState, QualityAssuranceSourceObject[]>(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<DSpaceObject> = 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 <giuseppe.digilio@4science.it> Date: Tue, 5 Jul 2022 17:28:14 +0200 Subject: [PATCH 008/282] [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<NotificationsState>('notifications'); // Quality Assurance topics // ---------------------------------------------------------------------------- From a7d2278d993212d60cb8c43fdfe1da000d6f3e5c Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Wed, 6 Jul 2022 17:14:12 +0200 Subject: [PATCH 009/282] [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<QualityAssuranceEventObject> 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<QualityAssuranceEventObject> { /** * 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<QualityAssuranceSourceObject> 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<QualityAssuranceSourceObject> { /** * 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<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { - 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<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { 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<QualityAssuranceTopicObject> 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<QualityAssuranceTopicObject> { /** * 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<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { - 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<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { 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<boolean> { 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<NotificationsState> = { - brokerTopic: qualityAssuranceTopicsReducer, - brokerSource: qualityAssuranceSourceReducer + qaTopic: qualityAssuranceTopicsReducer, + qaSource: qualityAssuranceSourceReducer }; export const notificationsSelector = createFeatureSelector<NotificationsState>('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 @@ <div class="row"> <div class="col-12"> <h2 class="border-bottom pb-2">{{'notifications.events.title'| translate}}</h2> - <p>{{'notifications.broker.events.description'| translate}}</p> + <p>{{'quality-assurance.events.description'| translate}}</p> <p> <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> <i class="fas fa-angle-double-left"></i> - {{'notifications.broker.events.back' | translate}} + {{'quality-assurance.events.back' | translate}} </a> </p> </div> @@ -14,10 +14,10 @@ <h2 class="border-bottom pb-2">{{'notifications.events.title'| translate}}</h2> <div class="row"> <div class="col-12"> <h3 class="border-bottom pb-2"> - {{'notifications.broker.events.topic' | translate}} {{this.showTopic}} + {{'quality-assurance.events.topic' | translate}} {{this.showTopic}} </h3> - <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isEventPageLoading | async)" [paginationOptions]="paginationConfig" @@ -25,20 +25,20 @@ <h3 class="border-bottom pb-2"> [sortOptions]="paginationSortConfig" (paginationChange)="getQualityAssuranceEvents()"> - <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ng-container *ngIf="!(isEventLoading | async)"> <div *ngIf="(eventsUpdated$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> - {{'notifications.broker.noEvents' | translate}} + {{'quality-assurance.noEvents' | translate}} </div> <div *ngIf="(eventsUpdated$|async)?.length != 0" class="table-responsive mt-2"> <table id="events" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'notifications.broker.event.table.trust' | translate}}</th> - <th scope="col">{{'notifications.broker.event.table.publication' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'notifications.broker.event.table.details' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'notifications.broker.event.table.project-details' | translate}}</th> - <th scope="col" class="button-rows">{{'notifications.broker.event.table.actions' | translate}}</th> + <th scope="col">{{'quality-assurance.event.table.trust' | translate}}</th> + <th scope="col">{{'quality-assurance.event.table.publication' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'quality-assurance.event.table.details' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'quality-assurance.event.table.project-details' | translate}}</th> + <th scope="col" class="button-rows">{{'quality-assurance.event.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -51,8 +51,8 @@ <h3 class="border-bottom pb-2"> <span *ngIf="!eventElement?.target">{{eventElement.title}}</span> </td> <td *ngIf="showTopic.indexOf('/PID') !== -1"> - <p><span class="small">{{'notifications.broker.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> - <p><span class="small">{{'notifications.broker.event.table.pidvalue' | translate}}</span><br> + <p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> + <p><span class="small">{{'quality-assurance.event.table.pidvalue' | translate}}</span><br> <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" target="_blank"> {{eventElement.event.message.value}} </a> @@ -60,37 +60,37 @@ <h3 class="border-bottom pb-2"> </p> </td> <td *ngIf="showTopic.indexOf('/SUBJECT') !== -1"> - <p><span class="small">{{'notifications.broker.event.table.subjectValue' | translate}}</span><br><span class="badge badge-info">{{eventElement.event.message.value}}</span></p> + <p><span class="small">{{'quality-assurance.event.table.subjectValue' | translate}}</span><br><span class="badge badge-info">{{eventElement.event.message.value}}</span></p> </td> <td *ngIf="showTopic.indexOf('/ABSTRACT') !== -1"> <p class="abstract-container" [class.show]="showMore"> - <span class="small">{{'notifications.broker.event.table.abstract' | translate}}</span><br> + <span class="small">{{'quality-assurance.event.table.abstract' | translate}}</span><br> <span class="text-ellipsis">{{eventElement.event.message.abstract}}</span> </p> <button class="btn btn-outline-primary btn-sm" (click)="showMore = !showMore"> <i *ngIf="!showMore" class="fas fa-angle-down"></i> <i *ngIf="showMore" class="fas fa-angle-up"></i> - {{ (showMore ? 'notifications.broker.event.table.less': 'notifications.broker.event.table.more') | translate }} + {{ (showMore ? 'quality-assurance.event.table.less': 'quality-assurance.event.table.more') | translate }} </button> </td> <td *ngIf="showTopic.indexOf('/PROJECT') !== -1"> <p> - {{'notifications.broker.event.table.suggestedProject' | translate}} + {{'quality-assurance.event.table.suggestedProject' | translate}} </p> <p> - <span class="small">{{'notifications.broker.event.table.project' | translate}}</span><br> + <span class="small">{{'quality-assurance.event.table.project' | translate}}</span><br> <a href="https://explore.openaire.eu/search/project?projectId={{ eventElement.event.message.openaireId}}" target="_blank">{{eventElement.event.message.title}}</a> </p> <p> - <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'notifications.broker.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> - <span *ngIf="eventElement.event.message.code"><span class="small">{{'notifications.broker.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> - <span *ngIf="eventElement.event.message.funder"><span class="small">{{'notifications.broker.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> - <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'notifications.broker.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> - <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'notifications.broker.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> + <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'quality-assurance.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> + <span *ngIf="eventElement.event.message.code"><span class="small">{{'quality-assurance.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> + <span *ngIf="eventElement.event.message.funder"><span class="small">{{'quality-assurance.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> + <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'quality-assurance.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> + <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'quality-assurance.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> </p> <hr> <div> - {{(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}} <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}}</a> <div class="btn-group"> <button class="btn btn-outline-primary btn-sm" @@ -114,19 +114,19 @@ <h3 class="border-bottom pb-2"> [disabled]="eventElement.isRunning" (click)="modalChoice('ACCEPTED', eventElement, acceptModal)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.import' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.import' | translate}}</span> </button> <button *ngIf="showTopic.indexOf('/PROJECT') == -1" class="btn btn-outline-success btn-sm button-width" [disabled]="eventElement.isRunning" (click)="executeAction('ACCEPTED', eventElement)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.accept' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.accept' | translate}}</span> </button> <button class="btn btn-outline-dark btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('DISCARDED', eventElement, ignoreModal)"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.ignore' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.ignore' | translate}}</span> </button> <button class="btn btn-outline-danger btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('REJECTED', eventElement, rejectModal)"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.reject' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.reject' | translate}}</span> </button> </div> </td> @@ -142,7 +142,7 @@ <h3 class="border-bottom pb-2"> <div class="col-md-12"> <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> <i class="fas fa-angle-double-left"></i> - {{'notifications.broker.events.back' | translate}} + {{'quality-assurance.events.back' | translate}} </a> </div> </div> @@ -150,58 +150,58 @@ <h3 class="border-bottom pb-2"> <ng-template #acceptModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="acceptModal">{{'notifications.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="acceptModal">{{'quality-assurance.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'notifications.broker.event.accept.description' | translate}}</p> + <p>{{'quality-assurance.event.accept.description' | translate}}</p> <button class="btn btn-outline-success float-left" (click)="modal.close('do')"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.import' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.import' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> <ng-template #ignoreModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="ignoreModal">{{'notifications.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="ignoreModal">{{'quality-assurance.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'notifications.broker.event.ignore.description' | translate}}</p> + <p>{{'quality-assurance.event.ignore.description' | translate}}</p> - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'notifications.broker.event.reason' |translate}}"></textarea --> + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'quality-assurance.event.reason' |translate}}"></textarea --> <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.ignore' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.ignore' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> <ng-template #rejectModal let-modal> <div class="modal-header"> - <h4 class="modal-title" id="rejectModal">{{'notifications.broker.event.sure' | translate}}</h4> + <h4 class="modal-title" id="rejectModal">{{'quality-assurance.event.sure' | translate}}</h4> </div> <div class="modal-body"> - <p>{{'notifications.broker.event.reject.description' | translate}}</p> + <p>{{'quality-assurance.event.reject.description' | translate}}</p> - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'notifications.broker.event.reason' |translate}}"></textarea --> + <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'quality-assurance.event.reason' |translate}}"></textarea --> <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.reject' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.reject' | translate}}</span> </button> <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'notifications.broker.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> 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<QualityAssuranceEventObject>) => { 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<QualityAssuranceEventObject>) => { 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<QualityAssuranceEventObject>) => { 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 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> - <p>{{'notifications.broker.source.description'| translate}}</p> + <h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2> + <p>{{'quality-assurance.source.description'| translate}}</p> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> + <h3 class="border-bottom pb-2">{{'quality-assurance.source'| translate}}</h3> - <ds-loading class="container" *ngIf="(isSourceLoading() | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isSourceLoading() | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isSourceLoading() | async)" [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" @@ -17,18 +17,18 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> [hideSortOptions]="true" (paginationChange)="getQualityAssuranceSource()"> - <ds-loading class="container" *ngIf="(isSourceProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> + <ds-loading class="container" *ngIf="(isSourceProcessing() | async)" message="'quality-assurance.loading' | translate"></ds-loading> <ng-container *ngIf="!(isSourceProcessing() | async)"> <div *ngIf="(sources$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> - {{'notifications.broker.noSource' | translate}} + {{'quality-assurance.noSource' | translate}} </div> <div *ngIf="(sources$|async)?.length != 0" class="table-responsive mt-2"> <table id="epeople" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'notifications.broker.table.source' | translate}}</th> - <th scope="col">{{'notifications.broker.table.last-event' | translate}}</th> - <th scope="col">{{'notifications.broker.table.actions' | translate}}</th> + <th scope="col">{{'quality-assurance.table.source' | translate}}</th> + <th scope="col">{{'quality-assurance.table.last-event' | translate}}</th> + <th scope="col">{{'quality-assurance.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -39,7 +39,7 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.source'| translate}}</h3> <div class="btn-group edit-field"> <button class="btn btn-outline-primary btn-sm" - title="{{'notifications.broker.button.detail' | translate }}" + title="{{'quality-assurance.button.detail' | translate }}" [routerLink]="[sourceElement.id]"> <span class="badge badge-info">{{sourceElement.totalEvents}}</span> <i class="fas fa-info fa-fw"></i> diff --git a/src/app/notifications/qa/source/quality-assurance-source.effects.ts b/src/app/notifications/qa/source/quality-assurance-source.effects.ts index 6d8aa275d53..e21b87c8425 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.effects.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.effects.ts @@ -53,7 +53,7 @@ export class QualityAssuranceSourceEffects { @Effect({ dispatch: false }) retrieveAllSourceErrorAction$ = this.actions$.pipe( ofType(QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR), tap(() => { - this.notificationsService.error(null, this.translate.get('notifications.broker.source.error.service.retrieve')); + this.notificationsService.error(null, this.translate.get('quality-assurance.source.error.service.retrieve')); }) ); diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.html b/src/app/notifications/qa/topics/quality-assurance-topics.component.html index b563a355f57..fdc7d554a23 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.html +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.html @@ -1,15 +1,15 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom pb-2">{{'notifications.broker.title'| translate}}</h2> - <p>{{'notifications.broker.topics.description'| translate:{source: sourceId} }}</p> + <h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2> + <p>{{'quality-assurance.topics.description'| translate:{source: sourceId} }}</p> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2">{{'notifications.broker.topics'| translate}}</h3> + <h3 class="border-bottom pb-2">{{'quality-assurance.topics'| translate}}</h3> - <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'notifications.broker.loading' | translate}}"></ds-loading> + <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isTopicsLoading() | async)" [paginationOptions]="paginationConfig" [collectionSize]="(totalElements$ | async)" @@ -17,18 +17,18 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.topics'| translate}}</h3> [hideSortOptions]="true" (paginationChange)="getQualityAssuranceTopics()"> - <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'notifications.broker.loading' | translate"></ds-loading> + <ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'quality-assurance.loading' | translate"></ds-loading> <ng-container *ngIf="!(isTopicsProcessing() | async)"> <div *ngIf="(topics$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> - {{'notifications.broker.noTopics' | translate}} + {{'quality-assurance.noTopics' | translate}} </div> <div *ngIf="(topics$|async)?.length != 0" class="table-responsive mt-2"> <table id="epeople" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'notifications.broker.table.topic' | translate}}</th> - <th scope="col">{{'notifications.broker.table.last-event' | translate}}</th> - <th scope="col">{{'notifications.broker.table.actions' | translate}}</th> + <th scope="col">{{'quality-assurance.table.topic' | translate}}</th> + <th scope="col">{{'quality-assurance.table.last-event' | translate}}</th> + <th scope="col">{{'quality-assurance.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -39,7 +39,7 @@ <h3 class="border-bottom pb-2">{{'notifications.broker.topics'| translate}}</h3> <div class="btn-group edit-field"> <button class="btn btn-outline-primary btn-sm" - title="{{'notifications.broker.button.detail' | translate }}" + title="{{'quality-assurance.button.detail' | translate }}" [routerLink]="[topicElement.id]"> <span class="badge badge-info">{{topicElement.totalEvents}}</span> <i class="fas fa-info fa-fw"></i> diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts index 14c0dacc238..71b5c642562 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts @@ -53,7 +53,7 @@ export class QualityAssuranceTopicsEffects { @Effect({ dispatch: false }) retrieveAllTopicsErrorAction$ = this.actions$.pipe( ofType(QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), tap(() => { - this.notificationsService.error(null, this.translate.get('notifications.broker.topic.error.service.retrieve')); + this.notificationsService.error(null, this.translate.get('quality-assurance.topic.error.service.retrieve')); }) ); diff --git a/src/app/notifications/selectors.ts b/src/app/notifications/selectors.ts index 2b78b947f83..a47495a950e 100644 --- a/src/app/notifications/selectors.ts +++ b/src/app/notifications/selectors.ts @@ -23,7 +23,7 @@ const _getNotificationsState = createFeatureSelector<NotificationsState>('notifi * @return {QualityAssuranceTopicState} */ export function qualityAssuranceTopicsStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceTopicState> { - return subStateSelector<NotificationsState,QualityAssuranceTopicState>(notificationsSelector, 'brokerTopic'); + return subStateSelector<NotificationsState,QualityAssuranceTopicState>(notificationsSelector, 'qaTopic'); } /** @@ -41,7 +41,7 @@ export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector<Notific * @return {boolean} */ export const isQualityAssuranceTopicsLoadedSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerTopic.loaded + (state: NotificationsState) => state.qaTopic.loaded ); /** @@ -50,7 +50,7 @@ export const isQualityAssuranceTopicsLoadedSelector = createSelector(_getNotific * @return {boolean} */ export const isQualityAssuranceTopicsProcessingSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerTopic.processing + (state: NotificationsState) => state.qaTopic.processing ); /** @@ -59,7 +59,7 @@ export const isQualityAssuranceTopicsProcessingSelector = createSelector(_getNot * @return {number} */ export const getQualityAssuranceTopicsTotalPagesSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerTopic.totalPages + (state: NotificationsState) => state.qaTopic.totalPages ); /** @@ -68,7 +68,7 @@ export const getQualityAssuranceTopicsTotalPagesSelector = createSelector(_getNo * @return {number} */ export const getQualityAssuranceTopicsCurrentPageSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerTopic.currentPage + (state: NotificationsState) => state.qaTopic.currentPage ); /** @@ -77,7 +77,7 @@ export const getQualityAssuranceTopicsCurrentPageSelector = createSelector(_getN * @return {number} */ export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerTopic.totalElements + (state: NotificationsState) => state.qaTopic.totalElements ); // Quality Assurance source @@ -89,7 +89,7 @@ export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotifi * @return {QualityAssuranceSourceState} */ export function qualityAssuranceSourceStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceSourceState> { - return subStateSelector<NotificationsState,QualityAssuranceSourceState>(notificationsSelector, 'brokerSource'); + return subStateSelector<NotificationsState,QualityAssuranceSourceState>(notificationsSelector, 'qaSource'); } /** @@ -107,7 +107,7 @@ export function qualityAssuranceSourceObjectSelector(): MemoizedSelector<Notific * @return {boolean} */ export const isQualityAssuranceSourceLoadedSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerSource.loaded + (state: NotificationsState) => state.qaSource.loaded ); /** @@ -116,7 +116,7 @@ export const isQualityAssuranceSourceLoadedSelector = createSelector(_getNotific * @return {boolean} */ export const isQualityAssuranceSourceProcessingSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerSource.processing + (state: NotificationsState) => state.qaSource.processing ); /** @@ -125,7 +125,7 @@ export const isQualityAssuranceSourceProcessingSelector = createSelector(_getNot * @return {number} */ export const getQualityAssuranceSourceTotalPagesSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerSource.totalPages + (state: NotificationsState) => state.qaSource.totalPages ); /** @@ -134,7 +134,7 @@ export const getQualityAssuranceSourceTotalPagesSelector = createSelector(_getNo * @return {number} */ export const getQualityAssuranceSourceCurrentPageSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerSource.currentPage + (state: NotificationsState) => state.qaSource.currentPage ); /** @@ -143,5 +143,5 @@ export const getQualityAssuranceSourceCurrentPageSelector = createSelector(_getN * @return {number} */ export const getQualityAssuranceSourceTotalsSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.brokerSource.totalElements + (state: NotificationsState) => state.qaSource.totalElements ); diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index 845c13a4cee..04cd6f1f246 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1334,37 +1334,37 @@ export const NotificationsMockDspaceObject: SearchResult<DSpaceObject> = Object. // ------------------------------------------------------------------------------- export const qualityAssuranceSourceObjectMorePid: QualityAssuranceSourceObject = { - type: new ResourceType('nbsource'), + type: new ResourceType('qasource'), 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' + href: 'https://rest.api/rest/api/integration/qasources/ENRICH!MORE!PID' } } }; export const qualityAssuranceSourceObjectMoreAbstract: QualityAssuranceSourceObject = { - type: new ResourceType('nbsource'), + type: new ResourceType('qasource'), 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' + href: 'https://rest.api/rest/api/integration/qasources/ENRICH!MORE!ABSTRACT' } } }; export const qualityAssuranceSourceObjectMissingPid: QualityAssuranceSourceObject = { - type: new ResourceType('nbsource'), + type: new ResourceType('qasource'), 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' + href: 'https://rest.api/rest/api/integration/qasources/ENRICH!MISSING!PID' } } }; @@ -1373,79 +1373,79 @@ export const qualityAssuranceSourceObjectMissingPid: QualityAssuranceSourceObjec // ------------------------------------------------------------------------------- export const qualityAssuranceTopicObjectMorePid: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MORE!PID' } } }; export const qualityAssuranceTopicObjectMoreAbstract: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MORE!ABSTRACT' } } }; export const qualityAssuranceTopicObjectMissingPid: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MISSING!PID' } } }; export const qualityAssuranceTopicObjectMissingAbstract: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MISSING!ABSTRACT' } } }; export const qualityAssuranceTopicObjectMissingAcm: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MISSING!SUBJECT!ACM' } } }; export const qualityAssuranceTopicObjectMissingProject: QualityAssuranceTopicObject = { - type: new ResourceType('nbtopic'), + type: new ResourceType('qatopic'), 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' + href: 'https://rest.api/rest/api/integration/qatopics/ENRICH!MISSING!PROJECT' } } }; @@ -1456,7 +1456,7 @@ export const qualityAssuranceTopicObjectMissingProject: QualityAssuranceTopicObj export const qualityAssuranceEventObjectMissingPid: QualityAssuranceEventObject = { id: '123e4567-e89b-12d3-a456-426614174001', uuid: '123e4567-e89b-12d3-a456-426614174001', - type: new ResourceType('nbevent'), + type: new ResourceType('qaevent'), originalId: 'oai:www.openstarts.units.it:10077/21486', title: 'Index nominum et rerum', trust: 0.375, @@ -1476,13 +1476,13 @@ export const qualityAssuranceEventObjectMissingPid: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001', + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174001', }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174001/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174001/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174001/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid1)), @@ -1512,13 +1512,13 @@ export const qualityAssuranceEventObjectMissingPid2: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174004' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174004/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174004/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174004/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid2)), @@ -1548,13 +1548,13 @@ export const qualityAssuranceEventObjectMissingPid3: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174005' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174005/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174005/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174005/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid3)), @@ -1584,13 +1584,13 @@ export const qualityAssuranceEventObjectMissingPid4: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174006' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174006/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174006/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174006/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid4)), @@ -1620,13 +1620,13 @@ export const qualityAssuranceEventObjectMissingPid5: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174007' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174007/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174007/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174007/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid5)), @@ -1656,13 +1656,13 @@ export const qualityAssuranceEventObjectMissingPid6: QualityAssuranceEventObject }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174008' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174008/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174008/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174008/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid6)), @@ -1692,13 +1692,13 @@ export const qualityAssuranceEventObjectMissingAbstract: QualityAssuranceEventOb }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174009' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174009/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174009/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174009/related' } }, target: observableOf(createSuccessfulRemoteDataObject(ItemMockPid7)), @@ -1728,13 +1728,13 @@ export const qualityAssuranceEventObjectMissingProjectFound: QualityAssuranceEve }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174002' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174002/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174002/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174002/related' } }, target: createSuccessfulRemoteDataObject$(ItemMockPid8), @@ -1764,13 +1764,13 @@ export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssurance }, _links: { self: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174003' }, target: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003/target' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174003/target' }, related: { - href: 'https://rest.api/rest/api/integration/nbevents/123e4567-e89b-12d3-a456-426614174003/related' + href: 'https://rest.api/rest/api/integration/qaevents/123e4567-e89b-12d3-a456-426614174003/related' } }, target: createSuccessfulRemoteDataObject$(ItemMockPid9), diff --git a/src/app/shared/selector.util.ts b/src/app/shared/selector.util.ts index 2343e12f1aa..97ddb9af7dc 100644 --- a/src/app/shared/selector.util.ts +++ b/src/app/shared/selector.util.ts @@ -4,7 +4,7 @@ import { hasValue } from './empty.util'; /** * Export a function to return a subset of the state by key */ -export function keySelector<T, V>(parentSelector: Selector<any, any>, subState: string, key: string): MemoizedSelector<T, V> { +export function keySelector<T, V>(parentSelector, subState: string, key: string): MemoizedSelector<T, V> { return createSelector(parentSelector, (state: T) => { if (hasValue(state) && hasValue(state[subState])) { return state[subState][key]; @@ -16,7 +16,7 @@ export function keySelector<T, V>(parentSelector: Selector<any, any>, subState: /** * Export a function to return a subset of the state */ -export function subStateSelector<T, V>(parentSelector: Selector<any, any>, subState: string): MemoizedSelector<T, V> { +export function subStateSelector<T, V>(parentSelector, subState: string): MemoizedSelector<T, V> { return createSelector(parentSelector, (state: T) => { if (hasValue(state) && hasValue(state[subState])) { return state[subState]; diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 0f5db4eb5be..b68545d3219 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -499,15 +499,15 @@ "admin.access-control.groups.form.return": "Back", - "admin.notifications.broker.breadcrumbs": "Quality Assurance", + "admin.quality-assurance.breadcrumbs": "Quality Assurance", - "admin.notifications.event.breadcrumbs": "Broker Suggestions", + "admin.notifications.event.breadcrumbs": "Quality Assurance Suggestions", - "admin.notifications.event.page.title": "Broker Suggestions", + "admin.notifications.event.page.title": "Quality Assurance Suggestions", - "admin.notifications.broker.page.title": "Quality Assurance", + "admin.quality-assurance.page.title": "Quality Assurance", - "admin.notifications.source.breadcrumbs": "Notifications Source", + "admin.notifications.source.breadcrumbs": "Quality Assurance Source", "admin.search.breadcrumbs": "Administrative Search", @@ -2687,7 +2687,7 @@ "menu.section.notifications": "Notifications", - "menu.section.notifications_broker": "Quality Assurance", + "menu.section.quality-assurance": "Quality Assurance", "menu.section.notifications_reciter": "Publication Claim", @@ -2863,135 +2863,135 @@ "none.listelement.badge": "Item", - "notifications.broker.title": "Notifications", + "quality-assurance.title": "Quality Assurance", - "notifications.broker.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.", + "quality-assurance.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 notification's sources.", + "quality-assurance.source.description": "Below you can see all the notification's sources.", - "notifications.broker.topics": "Current Topics", + "quality-assurance.topics": "Current Topics", - "notifications.broker.source": "Current Sources", + "quality-assurance.source": "Current Sources", - "notifications.broker.table.topic": "Topic", + "quality-assurance.table.topic": "Topic", - "notifications.broker.table.source": "Source", + "quality-assurance.table.source": "Source", - "notifications.broker.table.last-event": "Last Event", + "quality-assurance.table.last-event": "Last Event", - "notifications.broker.table.actions": "Actions", + "quality-assurance.table.actions": "Actions", - "notifications.broker.button.detail": "Show details", + "quality-assurance.button.detail": "Show details", - "notifications.broker.noTopics": "No topics found.", + "quality-assurance.noTopics": "No topics found.", - "notifications.broker.noSource": "No sources found.", + "quality-assurance.noSource": "No sources found.", - "notifications.events.title": "Broker Suggestions", + "notifications.events.title": "Quality Assurance Suggestions", - "notifications.broker.topic.error.service.retrieve": "An error occurred while loading the Quality Assurance topics", + "quality-assurance.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 Quality Assurance source", + "quality-assurance.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.", + "quality-assurance.events.description": "Below the list of all the suggestions for the selected topic.", - "notifications.broker.loading": "Loading ...", + "quality-assurance.loading": "Loading ...", - "notifications.broker.events.topic": "Topic:", + "quality-assurance.events.topic": "Topic:", - "notifications.broker.noEvents": "No suggestions found.", + "quality-assurance.noEvents": "No suggestions found.", - "notifications.broker.event.table.trust": "Trust", + "quality-assurance.event.table.trust": "Trust", - "notifications.broker.event.table.publication": "Publication", + "quality-assurance.event.table.publication": "Publication", - "notifications.broker.event.table.details": "Details", + "quality-assurance.event.table.details": "Details", - "notifications.broker.event.table.project-details": "Project details", + "quality-assurance.event.table.project-details": "Project details", - "notifications.broker.event.table.actions": "Actions", + "quality-assurance.event.table.actions": "Actions", - "notifications.broker.event.action.accept": "Accept suggestion", + "quality-assurance.event.action.accept": "Accept suggestion", - "notifications.broker.event.action.ignore": "Ignore suggestion", + "quality-assurance.event.action.ignore": "Ignore suggestion", - "notifications.broker.event.action.reject": "Reject suggestion", + "quality-assurance.event.action.reject": "Reject suggestion", - "notifications.broker.event.action.import": "Import project and accept suggestion", + "quality-assurance.event.action.import": "Import project and accept suggestion", - "notifications.broker.event.table.pidtype": "PID Type:", + "quality-assurance.event.table.pidtype": "PID Type:", - "notifications.broker.event.table.pidvalue": "PID Value:", + "quality-assurance.event.table.pidvalue": "PID Value:", - "notifications.broker.event.table.subjectValue": "Subject Value:", + "quality-assurance.event.table.subjectValue": "Subject Value:", - "notifications.broker.event.table.abstract": "Abstract:", + "quality-assurance.event.table.abstract": "Abstract:", - "notifications.broker.event.table.suggestedProject": "OpenAIRE Suggested Project data", + "quality-assurance.event.table.suggestedProject": "OpenAIRE Suggested Project data", - "notifications.broker.event.table.project": "Project title:", + "quality-assurance.event.table.project": "Project title:", - "notifications.broker.event.table.acronym": "Acronym:", + "quality-assurance.event.table.acronym": "Acronym:", - "notifications.broker.event.table.code": "Code:", + "quality-assurance.event.table.code": "Code:", - "notifications.broker.event.table.funder": "Funder:", + "quality-assurance.event.table.funder": "Funder:", - "notifications.broker.event.table.fundingProgram": "Funding program:", + "quality-assurance.event.table.fundingProgram": "Funding program:", - "notifications.broker.event.table.jurisdiction": "Jurisdiction:", + "quality-assurance.event.table.jurisdiction": "Jurisdiction:", - "notifications.broker.events.back": "Back to topics", + "quality-assurance.events.back": "Back to topics", - "notifications.broker.event.table.less": "Show less", + "quality-assurance.event.table.less": "Show less", - "notifications.broker.event.table.more": "Show more", + "quality-assurance.event.table.more": "Show more", - "notifications.broker.event.project.found": "Bound to the local record:", + "quality-assurance.event.project.found": "Bound to the local record:", - "notifications.broker.event.project.notFound": "No local record found", + "quality-assurance.event.project.notFound": "No local record found", - "notifications.broker.event.sure": "Are you sure?", + "quality-assurance.event.sure": "Are you sure?", - "notifications.broker.event.ignore.description": "This operation can't be undone. Ignore this suggestion?", + "quality-assurance.event.ignore.description": "This operation can't be undone. Ignore this suggestion?", - "notifications.broker.event.reject.description": "This operation can't be undone. Reject this suggestion?", + "quality-assurance.event.reject.description": "This operation can't be undone. Reject this suggestion?", - "notifications.broker.event.accept.description": "No DSpace project selected. A new project will be created based on the suggestion data.", + "quality-assurance.event.accept.description": "No DSpace project selected. A new project will be created based on the suggestion data.", - "notifications.broker.event.action.cancel": "Cancel", + "quality-assurance.event.action.cancel": "Cancel", - "notifications.broker.event.action.saved": "Your decision has been saved successfully.", + "quality-assurance.event.action.saved": "Your decision has been saved successfully.", - "notifications.broker.event.action.error": "An error has occurred. Your decision has not been saved.", + "quality-assurance.event.action.error": "An error has occurred. Your decision has not been saved.", - "notifications.broker.event.modal.project.title": "Choose a project to bound", + "quality-assurance.event.modal.project.title": "Choose a project to bound", - "notifications.broker.event.modal.project.publication": "Publication:", + "quality-assurance.event.modal.project.publication": "Publication:", - "notifications.broker.event.modal.project.bountToLocal": "Bound to the local record:", + "quality-assurance.event.modal.project.bountToLocal": "Bound to the local record:", - "notifications.broker.event.modal.project.select": "Project search", + "quality-assurance.event.modal.project.select": "Project search", - "notifications.broker.event.modal.project.search": "Search", + "quality-assurance.event.modal.project.search": "Search", - "notifications.broker.event.modal.project.clear": "Clear", + "quality-assurance.event.modal.project.clear": "Clear", - "notifications.broker.event.modal.project.cancel": "Cancel", + "quality-assurance.event.modal.project.cancel": "Cancel", - "notifications.broker.event.modal.project.bound": "Bound project", + "quality-assurance.event.modal.project.bound": "Bound project", - "notifications.broker.event.modal.project.placeholder": "Enter a project name", + "quality-assurance.event.modal.project.placeholder": "Enter a project name", - "notifications.broker.event.modal.project.notFound": "No project found.", + "quality-assurance.event.modal.project.notFound": "No project found.", - "notifications.broker.event.project.bounded": "The project has been linked successfully.", + "quality-assurance.event.project.bounded": "The project has been linked successfully.", - "notifications.broker.event.project.removed": "The project has been successfully unlinked.", + "quality-assurance.event.project.removed": "The project has been successfully unlinked.", - "notifications.broker.event.project.error": "An error has occurred. No operation performed.", + "quality-assurance.event.project.error": "An error has occurred. No operation performed.", - "notifications.broker.event.reason": "Reason", + "quality-assurance.event.reason": "Reason", "orgunit.listelement.badge": "Organizational Unit", From 4a996b492ab49d22482461283e850f98dd99ee83 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Wed, 6 Jul 2022 17:57:17 +0200 Subject: [PATCH 010/282] [CST-5249] Renamed notifications module to suggestion-notifications --- .../admin-notifications.module.ts | 4 +- ...-quality-assurance-source-data.reslover.ts | 4 +- src/app/core/core.module.ts | 6 +-- ...ality-assurance-event-rest.service.spec.ts | 0 .../quality-assurance-event-rest.service.ts | 0 ...ty-assurance-event-object.resource-type.ts | 0 .../models/quality-assurance-event.model.ts | 0 ...y-assurance-source-object.resource-type.ts | 0 .../models/quality-assurance-source.model.ts | 0 ...ty-assurance-topic-object.resource-type.ts | 0 .../models/quality-assurance-topic.model.ts | 0 ...lity-assurance-source-rest.service.spec.ts | 0 .../quality-assurance-source-rest.service.ts | 0 ...ality-assurance-topic-rest.service.spec.ts | 0 .../quality-assurance-topic-rest.service.ts | 0 src/app/shared/mocks/notifications.mock.ts | 12 ++--- .../quality-assurance-events.component.html | 0 ...quality-assurance-events.component.spec.ts | 4 +- .../quality-assurance-events.component.ts | 4 +- .../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 | 0 .../project-entry-import-modal.component.ts | 2 +- .../quality-assurance-source.actions.ts | 8 ++-- .../quality-assurance-source.component.html | 0 .../quality-assurance-source.component.scss | 0 ...quality-assurance-source.component.spec.ts | 4 +- .../quality-assurance-source.component.ts | 8 ++-- .../quality-assurance-source.effects.ts | 4 +- .../quality-assurance-source.reducer.spec.ts | 0 .../quality-assurance-source.reducer.ts | 2 +- .../quality-assurance-source.service.spec.ts | 2 +- .../quality-assurance-source.service.ts | 4 +- .../quality-assurance-topics.actions.ts | 8 ++-- .../quality-assurance-topics.component.html | 0 .../quality-assurance-topics.component.scss | 0 ...quality-assurance-topics.component.spec.ts | 4 +- .../quality-assurance-topics.component.ts | 8 ++-- .../quality-assurance-topics.effects.ts | 4 +- .../quality-assurance-topics.reducer.spec.ts | 0 .../quality-assurance-topics.reducer.ts | 2 +- .../quality-assurance-topics.service.spec.ts | 2 +- .../quality-assurance-topics.service.ts | 4 +- .../selectors.ts | 46 +++++++++---------- .../suggestion-notifications-effects.ts} | 2 +- ...stion-notifications-state.service.spec.ts} | 42 ++++++++--------- ...suggestion-notifications-state.service.ts} | 12 ++--- .../suggestion-notifications.module.ts} | 20 ++++---- .../suggestion-notifications.reducer.ts} | 6 +-- 50 files changed, 114 insertions(+), 114 deletions(-) rename src/app/core/{notifications => suggestion-notifications}/qa/events/quality-assurance-event-rest.service.spec.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/events/quality-assurance-event-rest.service.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-event-object.resource-type.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-event.model.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-source-object.resource-type.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-source.model.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-topic-object.resource-type.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/models/quality-assurance-topic.model.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/source/quality-assurance-source-rest.service.spec.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/source/quality-assurance-source-rest.service.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topic-rest.service.spec.ts (100%) rename src/app/core/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topic-rest.service.ts (100%) rename src/app/{notifications => suggestion-notifications}/qa/events/quality-assurance-events.component.html (100%) rename src/app/{notifications => suggestion-notifications}/qa/events/quality-assurance-events.component.spec.ts (98%) rename src/app/{notifications => suggestion-notifications}/qa/events/quality-assurance-events.component.ts (98%) rename src/app/{notifications => suggestion-notifications}/qa/events/quality-assurance-events.scomponent.scss (100%) rename src/app/{notifications => suggestion-notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.html (100%) rename src/app/{notifications => suggestion-notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.scss (100%) rename src/app/{notifications => suggestion-notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts (100%) rename src/app/{notifications => suggestion-notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.ts (98%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.actions.ts (85%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.component.html (100%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.component.scss (100%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.component.spec.ts (96%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.component.ts (92%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.effects.ts (93%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.reducer.spec.ts (100%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.reducer.ts (93%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.service.spec.ts (97%) rename src/app/{notifications => suggestion-notifications}/qa/source/quality-assurance-source.service.ts (90%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.actions.ts (84%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.component.html (100%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.component.scss (100%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.component.spec.ts (96%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.component.ts (93%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.effects.ts (94%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.reducer.spec.ts (100%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.reducer.ts (93%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.service.spec.ts (97%) rename src/app/{notifications => suggestion-notifications}/qa/topics/quality-assurance-topics.service.ts (92%) rename src/app/{notifications => suggestion-notifications}/selectors.ts (66%) rename src/app/{notifications/notifications.effects.ts => suggestion-notifications/suggestion-notifications-effects.ts} (84%) rename src/app/{notifications/notifications-state.service.spec.ts => suggestion-notifications/suggestion-notifications-state.service.spec.ts} (90%) rename src/app/{notifications/notifications-state.service.ts => suggestion-notifications/suggestion-notifications-state.service.ts} (93%) rename src/app/{notifications/notifications.module.ts => suggestion-notifications/suggestion-notifications.module.ts} (66%) rename src/app/{notifications/notifications.reducer.ts => suggestion-notifications/suggestion-notifications.reducer.ts} (66%) diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts index ba0c6eee58a..159baedfecc 100644 --- a/src/app/admin/admin-notifications/admin-notifications.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -5,8 +5,8 @@ import { SharedModule } from '../../shared/shared.module'; import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module'; 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 { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component'; +import {SuggestionNotificationsModule} from '../../suggestion-notifications/suggestion-notifications.module'; @NgModule({ imports: [ @@ -14,7 +14,7 @@ import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assura SharedModule, CoreModule.forRoot(), AdminNotificationsRoutingModule, - NotificationsModule + SuggestionNotificationsModule ], declarations: [ AdminQualityAssuranceTopicsPageComponent, diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts index 6201e0a7435..8475732aeda 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts @@ -3,8 +3,8 @@ 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 { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; -import { QualityAssuranceSourceService } from '../../../notifications/qa/source/quality-assurance-source.service'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceService } from '../../../suggestion-notifications/qa/source/quality-assurance-source.service'; /** * This class represents a resolver that retrieve the route data before the route is activated. */ diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index fcc8160f88b..6832d0b8d2b 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 { 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 { QualityAssuranceTopicObject } from './suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceEventObject } from './suggestion-notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceSourceObject } from './suggestion-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'; diff --git a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.spec.ts similarity index 100% rename from src/app/core/notifications/qa/events/quality-assurance-event-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.spec.ts diff --git a/src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.ts similarity index 100% rename from src/app/core/notifications/qa/events/quality-assurance-event-rest.service.ts rename to src/app/core/suggestion-notifications/qa/events/quality-assurance-event-rest.service.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-event.model.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-source.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-source.model.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts diff --git a/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic.model.ts similarity index 100% rename from src/app/core/notifications/qa/models/quality-assurance-topic.model.ts rename to src/app/core/suggestion-notifications/qa/models/quality-assurance-topic.model.ts diff --git a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.spec.ts similarity index 100% rename from src/app/core/notifications/qa/source/quality-assurance-source-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.spec.ts diff --git a/src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.ts similarity index 100% rename from src/app/core/notifications/qa/source/quality-assurance-source-rest.service.ts rename to src/app/core/suggestion-notifications/qa/source/quality-assurance-source-rest.service.ts diff --git a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts similarity index 100% rename from src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts rename to src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.spec.ts diff --git a/src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.ts similarity index 100% rename from src/app/core/notifications/qa/topics/quality-assurance-topic-rest.service.ts rename to src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service.ts diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index 04cd6f1f246..b423be3f58d 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 { 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 { 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 { 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 { QualityAssuranceSourceObject } from '../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; // REST Mock --------------------------------------------------------------------- // ------------------------------------------------------------------------------- @@ -1781,7 +1781,7 @@ export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssurance // ------------------------------------------------------------------------------- /** - * Mock for [[NotificationsStateService]] + * Mock for [[SuggestionNotificationsStateService]] */ export function getMockNotificationsStateService(): any { return jasmine.createSpyObj('NotificationsStateService', { diff --git a/src/app/notifications/qa/events/quality-assurance-events.component.html b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html similarity index 100% rename from src/app/notifications/qa/events/quality-assurance-events.component.html rename to src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html diff --git a/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts similarity index 98% rename from src/app/notifications/qa/events/quality-assurance-events.component.spec.ts rename to src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts index 976d8540e3a..41358b20a52 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts @@ -5,7 +5,7 @@ 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/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, @@ -22,7 +22,7 @@ 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/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'; diff --git a/src/app/notifications/qa/events/quality-assurance-events.component.ts b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts similarity index 98% rename from src/app/notifications/qa/events/quality-assurance-events.component.ts rename to src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts index 6e3dd8d010a..edac869f8e4 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts @@ -12,8 +12,8 @@ import { RemoteData } from '../../../core/data/remote-data'; import { QualityAssuranceEventObject, OpenaireQualityAssuranceEventMessageObject -} from '../../../core/notifications/qa/models/quality-assurance-event.model'; -import { QualityAssuranceEventRestService } from '../../../core/notifications/qa/events/quality-assurance-event-rest.service'; +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; +import { QualityAssuranceEventRestService } from '../../../core/suggestion-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'; diff --git a/src/app/notifications/qa/events/quality-assurance-events.scomponent.scss b/src/app/suggestion-notifications/qa/events/quality-assurance-events.scomponent.scss similarity index 100% rename from src/app/notifications/qa/events/quality-assurance-events.scomponent.scss rename to src/app/suggestion-notifications/qa/events/quality-assurance-events.scomponent.scss diff --git a/src/app/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 similarity index 100% rename from src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html rename to src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.html diff --git a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss similarity index 100% rename from src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss rename to src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.scss diff --git a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts b/src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts similarity index 100% rename from src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts rename to src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts diff --git a/src/app/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 similarity index 98% rename from src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts rename to src/app/suggestion-notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts index 64a2df30ba1..bde97f364ce 100644 --- a/src/app/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 @@ -16,7 +16,7 @@ import { QualityAssuranceEventObject, QualityAssuranceEventMessageObject, OpenaireQualityAssuranceEventMessageObject, -} from '../../../core/notifications/qa/models/quality-assurance-event.model'; +} 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/notifications/qa/source/quality-assurance-source.actions.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts similarity index 85% rename from src/app/notifications/qa/source/quality-assurance-source.actions.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts index 7a22e7a9ae9..4dcecf7b270 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.actions.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; /** * For each action type in an action group, make a simple @@ -11,9 +11,9 @@ import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/mod * action types in the application are unique. */ 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'), + ADD_SOURCE: type('dspace/integration/suggestion-notifications/qa/ADD_SOURCE'), + RETRIEVE_ALL_SOURCE: type('dspace/integration/suggestion-notifications/qa/RETRIEVE_ALL_SOURCE'), + RETRIEVE_ALL_SOURCE_ERROR: type('dspace/integration/suggestion-notifications/qa/RETRIEVE_ALL_SOURCE_ERROR'), }; /* tslint:disable:max-classes-per-file */ diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.html b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html similarity index 100% rename from src/app/notifications/qa/source/quality-assurance-source.component.html rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.scss b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.scss similarity index 100% rename from src/app/notifications/qa/source/quality-assurance-source.component.scss rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.component.scss diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts similarity index 96% rename from src/app/notifications/qa/source/quality-assurance-source.component.spec.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts index ba3a903cc5e..512530f8de5 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts @@ -11,7 +11,7 @@ import { qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceSourceComponent } from './quality-assurance-source.component'; -import { NotificationsStateService } from '../../notifications-state.service'; +import { SuggestionNotificationsStateService } from '../../notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; @@ -40,7 +40,7 @@ describe('QualityAssuranceSourceComponent test suite', () => { TestComponent, ], providers: [ - { provide: NotificationsStateService, useValue: mockNotificationsStateService }, + { provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, { provide: PaginationService, useValue: paginationService }, QualityAssuranceSourceComponent diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts similarity index 92% rename from src/app/notifications/qa/source/quality-assurance-source.component.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts index fde1afec436..372dc654ff9 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts @@ -3,9 +3,9 @@ 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 { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { NotificationsStateService } from '../../notifications-state.service'; +import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.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'; @@ -47,11 +47,11 @@ export class QualityAssuranceSourceComponent implements OnInit { /** * Initialize the component variables. * @param {PaginationService} paginationService - * @param {NotificationsStateService} notificationsStateService + * @param {SuggestionNotificationsStateService} notificationsStateService */ constructor( private paginationService: PaginationService, - private notificationsStateService: NotificationsStateService, + private notificationsStateService: SuggestionNotificationsStateService, ) { } /** diff --git a/src/app/notifications/qa/source/quality-assurance-source.effects.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts similarity index 93% rename from src/app/notifications/qa/source/quality-assurance-source.effects.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts index e21b87c8425..2d758d26258 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.effects.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts @@ -11,11 +11,11 @@ import { RetrieveAllSourceErrorAction, } from './quality-assurance-source.actions'; -import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; 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/notifications/qa/source/quality-assurance-source-rest.service'; +import { QualityAssuranceSourceRestService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; /** * Provides effect methods for the Quality Assurance source actions. diff --git a/src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.spec.ts similarity index 100% rename from src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.spec.ts diff --git a/src/app/notifications/qa/source/quality-assurance-source.reducer.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts similarity index 93% rename from src/app/notifications/qa/source/quality-assurance-source.reducer.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts index 08e26a177ac..d83a0e43416 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.reducer.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts @@ -1,4 +1,4 @@ -import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; import { QualityAssuranceSourceActionTypes, QualityAssuranceSourceActions } from './quality-assurance-source.actions'; /** diff --git a/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts similarity index 97% rename from src/app/notifications/qa/source/quality-assurance-source.service.spec.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts index 06f020be1d2..208e45e387f 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts @@ -11,7 +11,7 @@ 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/notifications/qa/source/quality-assurance-source-rest.service'; +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'; diff --git a/src/app/notifications/qa/source/quality-assurance-source.service.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts similarity index 90% rename from src/app/notifications/qa/source/quality-assurance-source.service.ts rename to src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts index 30a889d3e2f..2d413a906dc 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.service.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts @@ -1,11 +1,11 @@ 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 { QualityAssuranceSourceRestService } from '../../../core/suggestion-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 { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; import {FindListOptions} from '../../../core/data/find-list-options.model'; /** diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts similarity index 84% rename from src/app/notifications/qa/topics/quality-assurance-topics.actions.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts index 0506806587d..991a40ada15 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; /** * For each action type in an action group, make a simple @@ -11,9 +11,9 @@ import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/mode * action types in the application are unique. */ 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'), + ADD_TOPICS: type('dspace/integration/suggestion-notifications/qa/topic/ADD_TOPICS'), + RETRIEVE_ALL_TOPICS: type('dspace/integration/suggestion-notifications/qa/topic/RETRIEVE_ALL_TOPICS'), + RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/suggestion-notifications/qa/topic/RETRIEVE_ALL_TOPICS_ERROR'), }; /* tslint:disable:max-classes-per-file */ diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.html b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html similarity index 100% rename from src/app/notifications/qa/topics/quality-assurance-topics.component.html rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.scss b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.scss similarity index 100% rename from src/app/notifications/qa/topics/quality-assurance-topics.component.scss rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.scss diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts similarity index 96% rename from src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts index 8e154eca990..01e1cc2fc8c 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts @@ -11,7 +11,7 @@ import { qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceTopicsComponent } from './quality-assurance-topics.component'; -import { NotificationsStateService } from '../../notifications-state.service'; +import { SuggestionNotificationsStateService } from '../../notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; @@ -41,7 +41,7 @@ describe('QualityAssuranceTopicsComponent test suite', () => { TestComponent, ], providers: [ - { provide: NotificationsStateService, useValue: mockNotificationsStateService }, + { provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), snapshot: { paramMap: { get: () => 'openaire', diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts similarity index 93% rename from src/app/notifications/qa/topics/quality-assurance-topics.component.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts index f825358f3bf..a99944af6a0 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts @@ -4,10 +4,10 @@ import { Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, map, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; -import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/suggestion-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 { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.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'; @@ -59,12 +59,12 @@ export class QualityAssuranceTopicsComponent implements OnInit { /** * Initialize the component variables. * @param {PaginationService} paginationService - * @param {NotificationsStateService} notificationsStateService + * @param {SuggestionNotificationsStateService} notificationsStateService */ constructor( private paginationService: PaginationService, private activatedRoute: ActivatedRoute, - private notificationsStateService: NotificationsStateService, + private notificationsStateService: SuggestionNotificationsStateService, private qualityAssuranceTopicsService: QualityAssuranceTopicsService ) { } diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts similarity index 94% rename from src/app/notifications/qa/topics/quality-assurance-topics.effects.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts index 71b5c642562..880a2d2318e 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts @@ -11,11 +11,11 @@ import { RetrieveAllTopicsErrorAction, } from './quality-assurance-topics.actions'; -import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; 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/notifications/qa/topics/quality-assurance-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; /** * Provides effect methods for the Quality Assurance topics actions. diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.spec.ts similarity index 100% rename from src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.spec.ts diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts similarity index 93% rename from src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts index ff94f1b8bb1..355ace977d2 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts @@ -1,4 +1,4 @@ -import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; import { QualityAssuranceTopicActionTypes, QualityAssuranceTopicsActions } from './quality-assurance-topics.actions'; /** diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts similarity index 97% rename from src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts index 6d945446b2f..ba1399fcd43 100644 --- a/src/app/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,7 @@ 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/notifications/qa/topics/quality-assurance-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; import { PageInfo } from '../../../core/shared/page-info.model'; import { getMockQualityAssuranceTopicRestService, diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.service.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts similarity index 92% rename from src/app/notifications/qa/topics/quality-assurance-topics.service.ts rename to src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts index c09a0750e01..e3e4b1aa93a 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.service.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { find, map } from 'rxjs/operators'; -import { QualityAssuranceTopicRestService } from '../../../core/notifications/qa/topics/quality-assurance-topic-rest.service'; +import { QualityAssuranceTopicRestService } from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-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 { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/suggestion-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'; diff --git a/src/app/notifications/selectors.ts b/src/app/suggestion-notifications/selectors.ts similarity index 66% rename from src/app/notifications/selectors.ts rename to src/app/suggestion-notifications/selectors.ts index a47495a950e..c5947e3196d 100644 --- a/src/app/notifications/selectors.ts +++ b/src/app/suggestion-notifications/selectors.ts @@ -1,18 +1,18 @@ 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'; +import { suggestionNotificationsSelector, SuggestionNotificationsState } from './suggestion-notifications.reducer'; +import { QualityAssuranceTopicObject } from '../core/suggestion-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'; +import { QualityAssuranceSourceObject } from '../core/suggestion-notifications/qa/models/quality-assurance-source.model'; /** * Returns the Notifications state. * @function _getNotificationsState * @param {AppState} state Top level state. - * @return {NotificationsState} + * @return {SuggestionNotificationsState} */ -const _getNotificationsState = createFeatureSelector<NotificationsState>('notifications'); +const _getNotificationsState = createFeatureSelector<SuggestionNotificationsState>('notifications'); // Quality Assurance topics // ---------------------------------------------------------------------------- @@ -22,8 +22,8 @@ const _getNotificationsState = createFeatureSelector<NotificationsState>('notifi * @function qualityAssuranceTopicsStateSelector * @return {QualityAssuranceTopicState} */ -export function qualityAssuranceTopicsStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceTopicState> { - return subStateSelector<NotificationsState,QualityAssuranceTopicState>(notificationsSelector, 'qaTopic'); +export function qualityAssuranceTopicsStateSelector(): MemoizedSelector<SuggestionNotificationsState, QualityAssuranceTopicState> { + return subStateSelector<SuggestionNotificationsState,QualityAssuranceTopicState>(suggestionNotificationsSelector, 'qaTopic'); } /** @@ -31,8 +31,8 @@ export function qualityAssuranceTopicsStateSelector(): MemoizedSelector<Notifica * @function qualityAssuranceTopicsObjectSelector * @return {QualityAssuranceTopicObject[]} */ -export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector<NotificationsState, QualityAssuranceTopicObject[]> { - return subStateSelector<NotificationsState, QualityAssuranceTopicObject[]>(qualityAssuranceTopicsStateSelector(), 'topics'); +export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector<SuggestionNotificationsState, QualityAssuranceTopicObject[]> { + return subStateSelector<SuggestionNotificationsState, QualityAssuranceTopicObject[]>(qualityAssuranceTopicsStateSelector(), 'topics'); } /** @@ -41,7 +41,7 @@ export function qualityAssuranceTopicsObjectSelector(): MemoizedSelector<Notific * @return {boolean} */ export const isQualityAssuranceTopicsLoadedSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaTopic.loaded + (state: SuggestionNotificationsState) => state.qaTopic.loaded ); /** @@ -50,7 +50,7 @@ export const isQualityAssuranceTopicsLoadedSelector = createSelector(_getNotific * @return {boolean} */ export const isQualityAssuranceTopicsProcessingSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaTopic.processing + (state: SuggestionNotificationsState) => state.qaTopic.processing ); /** @@ -59,7 +59,7 @@ export const isQualityAssuranceTopicsProcessingSelector = createSelector(_getNot * @return {number} */ export const getQualityAssuranceTopicsTotalPagesSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaTopic.totalPages + (state: SuggestionNotificationsState) => state.qaTopic.totalPages ); /** @@ -68,7 +68,7 @@ export const getQualityAssuranceTopicsTotalPagesSelector = createSelector(_getNo * @return {number} */ export const getQualityAssuranceTopicsCurrentPageSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaTopic.currentPage + (state: SuggestionNotificationsState) => state.qaTopic.currentPage ); /** @@ -77,7 +77,7 @@ export const getQualityAssuranceTopicsCurrentPageSelector = createSelector(_getN * @return {number} */ export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaTopic.totalElements + (state: SuggestionNotificationsState) => state.qaTopic.totalElements ); // Quality Assurance source @@ -88,8 +88,8 @@ export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotifi * @function qualityAssuranceSourceStateSelector * @return {QualityAssuranceSourceState} */ - export function qualityAssuranceSourceStateSelector(): MemoizedSelector<NotificationsState, QualityAssuranceSourceState> { - return subStateSelector<NotificationsState,QualityAssuranceSourceState>(notificationsSelector, 'qaSource'); + export function qualityAssuranceSourceStateSelector(): MemoizedSelector<SuggestionNotificationsState, QualityAssuranceSourceState> { + return subStateSelector<SuggestionNotificationsState,QualityAssuranceSourceState>(suggestionNotificationsSelector, 'qaSource'); } /** @@ -97,8 +97,8 @@ export const getQualityAssuranceTopicsTotalsSelector = createSelector(_getNotifi * @function qualityAssuranceSourceObjectSelector * @return {QualityAssuranceSourceObject[]} */ -export function qualityAssuranceSourceObjectSelector(): MemoizedSelector<NotificationsState, QualityAssuranceSourceObject[]> { - return subStateSelector<NotificationsState, QualityAssuranceSourceObject[]>(qualityAssuranceSourceStateSelector(), 'source'); +export function qualityAssuranceSourceObjectSelector(): MemoizedSelector<SuggestionNotificationsState, QualityAssuranceSourceObject[]> { + return subStateSelector<SuggestionNotificationsState, QualityAssuranceSourceObject[]>(qualityAssuranceSourceStateSelector(), 'source'); } /** @@ -107,7 +107,7 @@ export function qualityAssuranceSourceObjectSelector(): MemoizedSelector<Notific * @return {boolean} */ export const isQualityAssuranceSourceLoadedSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaSource.loaded + (state: SuggestionNotificationsState) => state.qaSource.loaded ); /** @@ -116,7 +116,7 @@ export const isQualityAssuranceSourceLoadedSelector = createSelector(_getNotific * @return {boolean} */ export const isQualityAssuranceSourceProcessingSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaSource.processing + (state: SuggestionNotificationsState) => state.qaSource.processing ); /** @@ -125,7 +125,7 @@ export const isQualityAssuranceSourceProcessingSelector = createSelector(_getNot * @return {number} */ export const getQualityAssuranceSourceTotalPagesSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaSource.totalPages + (state: SuggestionNotificationsState) => state.qaSource.totalPages ); /** @@ -134,7 +134,7 @@ export const getQualityAssuranceSourceTotalPagesSelector = createSelector(_getNo * @return {number} */ export const getQualityAssuranceSourceCurrentPageSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaSource.currentPage + (state: SuggestionNotificationsState) => state.qaSource.currentPage ); /** @@ -143,5 +143,5 @@ export const getQualityAssuranceSourceCurrentPageSelector = createSelector(_getN * @return {number} */ export const getQualityAssuranceSourceTotalsSelector = createSelector(_getNotificationsState, - (state: NotificationsState) => state.qaSource.totalElements + (state: SuggestionNotificationsState) => state.qaSource.totalElements ); diff --git a/src/app/notifications/notifications.effects.ts b/src/app/suggestion-notifications/suggestion-notifications-effects.ts similarity index 84% rename from src/app/notifications/notifications.effects.ts rename to src/app/suggestion-notifications/suggestion-notifications-effects.ts index bf70a058554..ac5d9f8f928 100644 --- a/src/app/notifications/notifications.effects.ts +++ b/src/app/suggestion-notifications/suggestion-notifications-effects.ts @@ -1,7 +1,7 @@ import { QualityAssuranceSourceEffects } from './qa/source/quality-assurance-source.effects'; import { QualityAssuranceTopicsEffects } from './qa/topics/quality-assurance-topics.effects'; -export const notificationsEffects = [ +export const suggestionNotificationsEffects = [ QualityAssuranceTopicsEffects, QualityAssuranceSourceEffects ]; diff --git a/src/app/notifications/notifications-state.service.spec.ts b/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts similarity index 90% rename from src/app/notifications/notifications-state.service.spec.ts rename to src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts index 8c191415b70..b04368cfadb 100644 --- a/src/app/notifications/notifications-state.service.spec.ts +++ b/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts @@ -2,8 +2,8 @@ import { TestBed } from '@angular/core/testing'; import { Store, StoreModule } from '@ngrx/store'; import { provideMockStore } from '@ngrx/store/testing'; import { cold } from 'jasmine-marbles'; -import { notificationsReducers } from './notifications.reducer'; -import { NotificationsStateService } from './notifications-state.service'; +import { suggestionNotificationsReducers } from './suggestion-notifications.reducer'; +import { SuggestionNotificationsStateService } from './suggestion-notifications-state.service'; import { qualityAssuranceSourceObjectMissingPid, qualityAssuranceSourceObjectMoreAbstract, @@ -16,7 +16,7 @@ import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.ac import { RetrieveAllSourceAction } from './qa/source/quality-assurance-source.actions'; describe('NotificationsStateService', () => { - let service: NotificationsStateService; + let service: SuggestionNotificationsStateService; let serviceAsAny: any; let store: any; let initialState: any; @@ -63,18 +63,18 @@ describe('NotificationsStateService', () => { init('empty'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -155,18 +155,18 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -251,18 +251,18 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -321,18 +321,18 @@ describe('NotificationsStateService', () => { init('empty'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -413,18 +413,18 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -509,18 +509,18 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: notificationsReducers } as any), + StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), - { provide: NotificationsStateService, useValue: service } + { provide: SuggestionNotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new NotificationsStateService(store); + service = new SuggestionNotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); diff --git a/src/app/notifications/notifications-state.service.ts b/src/app/suggestion-notifications/suggestion-notifications-state.service.ts similarity index 93% rename from src/app/notifications/notifications-state.service.ts rename to src/app/suggestion-notifications/suggestion-notifications-state.service.ts index 99605a54fa0..ec1ea2e0394 100644 --- a/src/app/notifications/notifications-state.service.ts +++ b/src/app/suggestion-notifications/suggestion-notifications-state.service.ts @@ -16,23 +16,23 @@ import { getQualityAssuranceSourceCurrentPageSelector, getQualityAssuranceSourceTotalsSelector } from './selectors'; -import { QualityAssuranceTopicObject } from '../core/notifications/qa/models/quality-assurance-topic.model'; -import { NotificationsState } from './notifications.reducer'; +import { QualityAssuranceTopicObject } from '../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { SuggestionNotificationsState } from './suggestion-notifications.reducer'; import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.actions'; -import { QualityAssuranceSourceObject } from '../core/notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../core/suggestion-notifications/qa/models/quality-assurance-source.model'; import { RetrieveAllSourceAction } from './qa/source/quality-assurance-source.actions'; /** * The service handling the Notifications State. */ @Injectable() -export class NotificationsStateService { +export class SuggestionNotificationsStateService { /** * Initialize the service variables. - * @param {Store<NotificationsState>} store + * @param {Store<SuggestionNotificationsState>} store */ - constructor(private store: Store<NotificationsState>) { } + constructor(private store: Store<SuggestionNotificationsState>) { } // Quality Assurance topics // -------------------------------------------------------------------------- diff --git a/src/app/notifications/notifications.module.ts b/src/app/suggestion-notifications/suggestion-notifications.module.ts similarity index 66% rename from src/app/notifications/notifications.module.ts rename to src/app/suggestion-notifications/suggestion-notifications.module.ts index 27e34c8d516..f659d27a28e 100644 --- a/src/app/notifications/notifications.module.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.module.ts @@ -8,25 +8,25 @@ import { SharedModule } from '../shared/shared.module'; import { storeModuleConfig } from '../app.reducer'; 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 { SuggestionNotificationsStateService } from './suggestion-notifications-state.service'; +import { suggestionNotificationsReducers, SuggestionNotificationsState } from './suggestion-notifications.reducer'; +import { suggestionNotificationsEffects } from './suggestion-notifications-effects'; 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 { 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 { 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/notifications/qa/source/quality-assurance-source-rest.service'; +import { QualityAssuranceSourceRestService } from '../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; const MODULES = [ CommonModule, SharedModule, CoreModule.forRoot(), - StoreModule.forFeature('notifications', notificationsReducers, storeModuleConfig as StoreConfig<NotificationsState, Action>), - EffectsModule.forFeature(notificationsEffects), + StoreModule.forFeature('notifications', suggestionNotificationsReducers, storeModuleConfig as StoreConfig<SuggestionNotificationsState, Action>), + EffectsModule.forFeature(suggestionNotificationsEffects), TranslateModule ]; @@ -43,7 +43,7 @@ const ENTRY_COMPONENTS = [ ]; const PROVIDERS = [ - NotificationsStateService, + SuggestionNotificationsStateService, QualityAssuranceTopicsService, QualityAssuranceSourceService, QualityAssuranceTopicRestService, @@ -76,5 +76,5 @@ const PROVIDERS = [ /** * This module handles all components that are necessary for the OpenAIRE components */ -export class NotificationsModule { +export class SuggestionNotificationsModule { } diff --git a/src/app/notifications/notifications.reducer.ts b/src/app/suggestion-notifications/suggestion-notifications.reducer.ts similarity index 66% rename from src/app/notifications/notifications.reducer.ts rename to src/app/suggestion-notifications/suggestion-notifications.reducer.ts index 4cce554f95c..cc0cdd71013 100644 --- a/src/app/notifications/notifications.reducer.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.reducer.ts @@ -5,14 +5,14 @@ import { qualityAssuranceTopicsReducer, QualityAssuranceTopicState, } from './qa /** * The OpenAIRE State */ -export interface NotificationsState { +export interface SuggestionNotificationsState { 'qaTopic': QualityAssuranceTopicState; 'qaSource': QualityAssuranceSourceState; } -export const notificationsReducers: ActionReducerMap<NotificationsState> = { +export const suggestionNotificationsReducers: ActionReducerMap<SuggestionNotificationsState> = { qaTopic: qualityAssuranceTopicsReducer, qaSource: qualityAssuranceSourceReducer }; -export const notificationsSelector = createFeatureSelector<NotificationsState>('notifications'); +export const suggestionNotificationsSelector = createFeatureSelector<SuggestionNotificationsState>('notifications'); From f2400a714a65345429fb4e8ec8101b12aa98df79 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Wed, 6 Jul 2022 18:05:47 +0200 Subject: [PATCH 011/282] [CST-5337] Fixed lint and tests --- .../qa/events/quality-assurance-event-rest.service.ts | 2 +- .../qa/models/quality-assurance-event.model.ts | 1 + .../qa/source/quality-assurance-source-rest.service.ts | 3 +-- .../qa/topics/quality-assurance-topic-rest.service.ts | 3 +-- src/app/shared/mocks/notifications.mock.ts | 1 - .../qa/source/quality-assurance-source.actions.ts | 3 +-- .../qa/source/quality-assurance-source.component.spec.ts | 2 +- .../qa/topics/quality-assurance-topics.actions.ts | 3 +-- .../qa/topics/quality-assurance-topics.component.spec.ts | 3 ++- 9 files changed, 9 insertions(+), 12 deletions(-) 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-rest.service.ts index 67863cad745..a7cdd9e786c 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-rest.service.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; @@ -24,7 +25,6 @@ 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. diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts index f070e7303ad..0bf7942f75d 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts +++ b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Observable } from 'rxjs'; import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; import { QUALITY_ASSURANCE_EVENT_OBJECT } from './quality-assurance-event-object.resource-type'; 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-rest.service.ts index 10bcfbe896a..6b5ca806ff0 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-rest.service.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; @@ -22,8 +23,6 @@ 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. */ 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-rest.service.ts index da9d95d290d..a2f2498fcad 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-rest.service.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; @@ -22,8 +23,6 @@ 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. */ diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index b423be3f58d..ef6d99e9ea3 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -5,7 +5,6 @@ import { QualityAssuranceEventObject } from '../../core/suggestion-notifications 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 { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { NotificationsStateService } from '../../notifications/notifications-state.service'; import { Item } from '../../core/shared/item.model'; import { createNoContentRemoteDataObject$, diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts index 4dcecf7b270..06db9dda06c 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; @@ -16,8 +17,6 @@ export const QualityAssuranceSourceActionTypes = { RETRIEVE_ALL_SOURCE_ERROR: type('dspace/integration/suggestion-notifications/qa/RETRIEVE_ALL_SOURCE_ERROR'), }; -/* tslint:disable:max-classes-per-file */ - /** * An ngrx action to retrieve all the Quality Assurance source. */ diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts index 512530f8de5..2f588125b28 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts @@ -11,7 +11,7 @@ import { qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceSourceComponent } from './quality-assurance-source.component'; -import { SuggestionNotificationsStateService } from '../../notifications-state.service'; +import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts index 991a40ada15..2459d4352ab 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; @@ -16,8 +17,6 @@ export const QualityAssuranceTopicActionTypes = { RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/suggestion-notifications/qa/topic/RETRIEVE_ALL_TOPICS_ERROR'), }; -/* tslint:disable:max-classes-per-file */ - /** * An ngrx action to retrieve all the Quality Assurance topics. */ 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 01e1cc2fc8c..6e933a0e803 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,3 +1,4 @@ +/* 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'; @@ -11,7 +12,7 @@ import { qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceTopicsComponent } from './quality-assurance-topics.component'; -import { SuggestionNotificationsStateService } from '../../notifications-state.service'; +import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; import { cold } from 'jasmine-marbles'; import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub'; import { PaginationService } from '../../../core/pagination/pagination.service'; From 530db26587b4faada51a961980f1beea06fdc681 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Wed, 6 Jul 2022 18:12:15 +0200 Subject: [PATCH 012/282] [CST-5337] Fixed lint error --- .../qa/models/quality-assurance-event.model.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts index 0bf7942f75d..c9395bd528e 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts +++ b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts @@ -14,6 +14,7 @@ import {CacheableObject} from '../../../cache/cacheable-object.model'; /** * The interface representing the Quality Assurance event message */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface QualityAssuranceEventMessageObject { } From 5266194d845f74639e8a944ad7a04f80c2568de5 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Thu, 7 Jul 2022 16:29:50 +0200 Subject: [PATCH 013/282] [CST-5337] Update state name --- src/app/suggestion-notifications/selectors.ts | 6 ++++-- ...estion-notifications-state.service.spec.ts | 20 +++++++++---------- .../suggestion-notifications.module.ts | 14 +++++++++---- .../suggestion-notifications.reducer.ts | 12 ++++++++--- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/app/suggestion-notifications/selectors.ts b/src/app/suggestion-notifications/selectors.ts index c5947e3196d..d98c023ee45 100644 --- a/src/app/suggestion-notifications/selectors.ts +++ b/src/app/suggestion-notifications/selectors.ts @@ -4,7 +4,9 @@ import { suggestionNotificationsSelector, SuggestionNotificationsState } from '. import { QualityAssuranceTopicObject } from '../core/suggestion-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/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { + QualityAssuranceSourceObject +} from '../core/suggestion-notifications/qa/models/quality-assurance-source.model'; /** * Returns the Notifications state. @@ -12,7 +14,7 @@ import { QualityAssuranceSourceObject } from '../core/suggestion-notifications/q * @param {AppState} state Top level state. * @return {SuggestionNotificationsState} */ -const _getNotificationsState = createFeatureSelector<SuggestionNotificationsState>('notifications'); +const _getNotificationsState = createFeatureSelector<SuggestionNotificationsState>('suggestionNotifications'); // Quality Assurance topics // ---------------------------------------------------------------------------- diff --git a/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts b/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts index b04368cfadb..ac669ed9548 100644 --- a/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts +++ b/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts @@ -25,7 +25,7 @@ describe('NotificationsStateService', () => { function init(mode: string) { if (mode === 'empty') { initialState = { - notifications: { + suggestionNotifications: { qaTopic: { topics: [], processing: false, @@ -39,7 +39,7 @@ describe('NotificationsStateService', () => { }; } else { initialState = { - notifications: { + suggestionNotifications: { qaTopic: { topics: [ qualityAssuranceTopicObjectMorePid, @@ -63,7 +63,7 @@ describe('NotificationsStateService', () => { init('empty'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), @@ -155,7 +155,7 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), @@ -251,7 +251,7 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), @@ -283,7 +283,7 @@ describe('NotificationsStateService', () => { function init(mode: string) { if (mode === 'empty') { initialState = { - notifications: { + suggestionNotifications: { qaSource: { source: [], processing: false, @@ -297,7 +297,7 @@ describe('NotificationsStateService', () => { }; } else { initialState = { - notifications: { + suggestionNotifications: { qaSource: { source: [ qualityAssuranceSourceObjectMorePid, @@ -321,7 +321,7 @@ describe('NotificationsStateService', () => { init('empty'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), @@ -413,7 +413,7 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), @@ -509,7 +509,7 @@ describe('NotificationsStateService', () => { init('full'); TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({ notifications: suggestionNotificationsReducers } as any), + StoreModule.forRoot({ suggestionNotifications: suggestionNotificationsReducers } as any), ], providers: [ provideMockStore({ initialState }), diff --git a/src/app/suggestion-notifications/suggestion-notifications.module.ts b/src/app/suggestion-notifications/suggestion-notifications.module.ts index f659d27a28e..90e73eb0bef 100644 --- a/src/app/suggestion-notifications/suggestion-notifications.module.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.module.ts @@ -12,20 +12,26 @@ import { SuggestionNotificationsStateService } from './suggestion-notifications- import { suggestionNotificationsReducers, SuggestionNotificationsState } from './suggestion-notifications.reducer'; 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'; -import { QualityAssuranceEventRestService } from '../core/suggestion-notifications/qa/events/quality-assurance-event-rest.service'; +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 { 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'; +import { + QualityAssuranceSourceRestService +} from '../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; const MODULES = [ CommonModule, SharedModule, CoreModule.forRoot(), - StoreModule.forFeature('notifications', suggestionNotificationsReducers, storeModuleConfig as StoreConfig<SuggestionNotificationsState, Action>), + StoreModule.forFeature('suggestionNotifications', suggestionNotificationsReducers, storeModuleConfig as StoreConfig<SuggestionNotificationsState, Action>), EffectsModule.forFeature(suggestionNotificationsEffects), TranslateModule ]; diff --git a/src/app/suggestion-notifications/suggestion-notifications.reducer.ts b/src/app/suggestion-notifications/suggestion-notifications.reducer.ts index cc0cdd71013..289d1e498b8 100644 --- a/src/app/suggestion-notifications/suggestion-notifications.reducer.ts +++ b/src/app/suggestion-notifications/suggestion-notifications.reducer.ts @@ -1,6 +1,12 @@ import { ActionReducerMap, createFeatureSelector } from '@ngrx/store'; -import { qualityAssuranceSourceReducer, QualityAssuranceSourceState } from './qa/source/quality-assurance-source.reducer'; -import { qualityAssuranceTopicsReducer, QualityAssuranceTopicState, } from './qa/topics/quality-assurance-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 @@ -15,4 +21,4 @@ export const suggestionNotificationsReducers: ActionReducerMap<SuggestionNotific qaSource: qualityAssuranceSourceReducer }; -export const suggestionNotificationsSelector = createFeatureSelector<SuggestionNotificationsState>('notifications'); +export const suggestionNotificationsSelector = createFeatureSelector<SuggestionNotificationsState>('suggestionNotifications'); From 92b1ce2d179e8b7a1d31b88c221bbe09ca7ab96b Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Thu, 7 Jul 2022 17:25:56 +0200 Subject: [PATCH 014/282] [CST-5337] Fix issue with list that wasn't updated after last element has been processed --- .../quality-assurance-events.component.ts | 105 +++++++++--------- 1 file changed, 55 insertions(+), 50 deletions(-) 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 edac869f8e4..0f71123d22a 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 @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -10,25 +10,27 @@ import { SortDirection, SortOptions } from '../../../core/cache/models/sort-opti import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { - QualityAssuranceEventObject, - OpenaireQualityAssuranceEventMessageObject + OpenaireQualityAssuranceEventMessageObject, + QualityAssuranceEventObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; -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 { 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 { hasValue, isEmpty } from '../../../shared/empty.util'; import { ItemSearchResult } from '../../../shared/object-collection/shared/item-search-result.model'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { - QualityAssuranceEventData, - ProjectEntryImportModalComponent + ProjectEntryImportModalComponent, + QualityAssuranceEventData } 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'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; /** * Component to display the Quality Assurance event list. @@ -38,7 +40,7 @@ import {FindListOptions} from '../../../core/data/find-list-options.model'; templateUrl: './quality-assurance-events.component.html', styleUrls: ['./quality-assurance-events.scomponent.scss'], }) -export class QualityAssuranceEventsComponent implements OnInit { +export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { /** * The pagination system configuration for HTML listing. * @type {PaginationComponentOptions} @@ -376,47 +378,50 @@ export class QualityAssuranceEventsComponent implements OnInit { * the Quality Assurance event item */ protected setEventUpdated(events: QualityAssuranceEventObject[]): void { - 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<Item>, RemoteData<Item>]) => { - 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); - } - ) - ); + 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<Item>, RemoteData<Item>]) => { + 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 computePIDHref(event: OpenaireQualityAssuranceEventMessageObject) { From 0942a1e474b4751256421450af327338191106e1 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Thu, 7 Jul 2022 17:26:58 +0200 Subject: [PATCH 015/282] [CST-5337] Improve layout --- .../quality-assurance-events.component.html | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html index d7f6129b3b2..209b2cde278 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html @@ -91,7 +91,7 @@ <h3 class="border-bottom pb-2"> <hr> <div> {{(eventElement.hasProject ? 'quality-assurance.event.project.found' : 'quality-assurance.event.project.notFound') | translate}} - <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}}</a> + <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}} </a> <div class="btn-group"> <button class="btn btn-outline-primary btn-sm" [disabled]="eventElement.isRunning" @@ -108,25 +108,36 @@ <h3 class="border-bottom pb-2"> </div> </td> <td> - <div class="btn-group-vertical button-width"> + <div class="btn-group button-width"> <button *ngIf="showTopic.indexOf('/PROJECT') !== -1" class="btn btn-outline-success btn-sm button-width" + ngbTooltip="{{'quality-assurance.event.action.import' | translate}}" + container="body" [disabled]="eventElement.isRunning" (click)="modalChoice('ACCEPTED', eventElement, acceptModal)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.import' | translate}}</span> </button> - <button *ngIf="showTopic.indexOf('/PROJECT') == -1" class="btn btn-outline-success btn-sm button-width" [disabled]="eventElement.isRunning" (click)="executeAction('ACCEPTED', eventElement)"> + <button *ngIf="showTopic.indexOf('/PROJECT') == -1" + class="btn btn-outline-success btn-sm button-width" + ngbTooltip="{{'quality-assurance.event.action.accept' | translate}}" + container="body" + [disabled]="eventElement.isRunning" + (click)="executeAction('ACCEPTED', eventElement)"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.accept' | translate}}</span> </button> - <button class="btn btn-outline-dark btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('DISCARDED', eventElement, ignoreModal)"> - <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.ignore' | translate}}</span> + <button class="btn btn-outline-dark btn-sm button-width" + ngbTooltip="{{'quality-assurance.event.action.ignore' | translate}}" + container="body" + [disabled]="eventElement.isRunning" + (click)="openModal('DISCARDED', eventElement, ignoreModal)"> + <i class="fas fa-ban"></i> </button> - <button class="btn btn-outline-danger btn-sm button-width" [disabled]="eventElement.isRunning" (click)="openModal('REJECTED', eventElement, rejectModal)"> + <button class="btn btn-outline-danger btn-sm button-width" + ngbTooltip="{{'quality-assurance.event.action.reject' | translate}}" + container="body" + [disabled]="eventElement.isRunning" + (click)="openModal('REJECTED', eventElement, rejectModal)"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.reject' | translate}}</span> </button> </div> </td> @@ -155,13 +166,13 @@ <h4 class="modal-title" id="acceptModal">{{'quality-assurance.event.sure' | tran <div class="modal-body"> <p>{{'quality-assurance.event.accept.description' | translate}}</p> - <button class="btn btn-outline-success float-left" (click)="modal.close('do')"> + <button class="btn btn-outline-success float-right" (click)="modal.close('do')"> <i class="fas fa-check"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.import' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.import' | translate}}</span> </button> - <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <button class="btn btn-outline-secondary" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> @@ -172,16 +183,13 @@ <h4 class="modal-title" id="ignoreModal">{{'quality-assurance.event.sure' | tran </div> <div class="modal-body"> <p>{{'quality-assurance.event.ignore.description' | translate}}</p> - - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'quality-assurance.event.reason' |translate}}"></textarea --> - - <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> + <button class="btn btn-outline-danger float-right" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.ignore' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.ignore' | translate}}</span> </button> - <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <button class="btn btn-outline-secondary" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> @@ -192,16 +200,13 @@ <h4 class="modal-title" id="rejectModal">{{'quality-assurance.event.sure' | tran </div> <div class="modal-body"> <p>{{'quality-assurance.event.reject.description' | translate}}</p> - - <!-- textarea class="form-control mb-2" [(ngModel)]="selectedReason" placeholder="{{'quality-assurance.event.reason' |translate}}"></textarea --> - - <button class="btn btn-outline-danger float-left" (click)="modal.close('do')"> + <button class="btn btn-outline-danger float-right" (click)="modal.close('do')"> <i class="fas fa-trash-alt"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.reject' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.reject' | translate}}</span> </button> - <button class="btn btn-outline-secondary float-right" (click)="modal.close('cancel')"> + <button class="btn btn-outline-secondary" (click)="modal.close('cancel')"> <i class="fas fa-close"></i> - <span class="d-none d-sm-inline">{{'quality-assurance.event.action.cancel' | translate}}</span> + <span class="d-none d-sm-inline"> {{'quality-assurance.event.action.cancel' | translate}}</span> </button> </div> </ng-template> From bb357df738ce12c35064434f5663de2932f53546 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Fri, 8 Jul 2022 18:04:42 +0200 Subject: [PATCH 016/282] [CST-5337] Added missing typedocs --- .../admin-quality-assurance-events-page.component.ts | 3 +++ .../admin-quality-assurance-source-page.component.ts | 3 +++ .../admin-quality-assurance-topics-page.component.ts | 3 +++ ...scomponent.scss => quality-assurance-events.component.scss} | 0 .../qa/source/quality-assurance-source.component.ts | 3 +++ 5 files changed, 12 insertions(+) rename src/app/suggestion-notifications/qa/events/{quality-assurance-events.scomponent.scss => quality-assurance-events.component.scss} (100%) 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 index a1e15d5bdb7..bd3470f3012 100644 --- 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 @@ -1,5 +1,8 @@ import { Component } from '@angular/core'; +/** + * Component for the page that show the QA events related to a specific topic. + */ @Component({ selector: 'ds-quality-assurance-events-page', templateUrl: './admin-quality-assurance-events-page.component.html' 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 624e71f281e..20d0356d5f0 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,5 +1,8 @@ import { Component, OnInit } from '@angular/core'; +/** + * Component for the page that show the QA sources. + */ @Component({ selector: 'ds-admin-quality-assurance-source-page-component', templateUrl: './admin-quality-assurance-source-page.component.html', 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 1b4f1d70aa8..f17d3448d5b 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,5 +1,8 @@ import { Component } from '@angular/core'; +/** + * Component for the page that show the QA topics related to a specific source. + */ @Component({ selector: 'ds-notification-qa-page', templateUrl: './admin-quality-assurance-topics-page.component.html' diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.scomponent.scss b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss similarity index 100% rename from src/app/suggestion-notifications/qa/events/quality-assurance-events.scomponent.scss rename to src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts index 372dc654ff9..f6f02d9ab97 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts +++ b/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts @@ -9,6 +9,9 @@ import { SuggestionNotificationsStateService } from '../../suggestion-notificati 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 to display the Quality Assurance source list. + */ @Component({ selector: 'ds-quality-assurance-source', templateUrl: './quality-assurance-source.component.html', From 7808f85a2dea85b347c6bf64531577c5fdce0851 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Fri, 8 Jul 2022 18:20:38 +0200 Subject: [PATCH 017/282] [CST-5337] Moved compute PID href on rest side --- .../models/quality-assurance-event.model.ts | 5 ++ src/app/shared/mocks/notifications.mock.ts | 9 ++++ .../quality-assurance-events.component.ts | 47 +------------------ 3 files changed, 16 insertions(+), 45 deletions(-) diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts index c9395bd528e..7517148def4 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts +++ b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts @@ -73,6 +73,11 @@ export interface OpenaireQualityAssuranceEventMessageObject { */ openaireId: string; + /** + * The PID href. + */ + pidHref: string; + } /** diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index ef6d99e9ea3..bbdf60c083f 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1464,6 +1464,7 @@ export const qualityAssuranceEventObjectMissingPid: QualityAssuranceEventObject message: { type: 'doi', value: '10.18848/1447-9494/cgp/v15i09/45934', + pidHref: 'https://doi.org/10.18848/1447-9494/cgp/v15i09/45934', abstract: null, openaireId: null, acronym: null, @@ -1500,6 +1501,7 @@ export const qualityAssuranceEventObjectMissingPid2: QualityAssuranceEventObject message: { type: 'urn', value: 'http://thesis2.sba.units.it/store/handle/item/12238', + pidHref:'http://thesis2.sba.units.it/store/handle/item/12238', abstract: null, openaireId: null, acronym: null, @@ -1536,6 +1538,7 @@ export const qualityAssuranceEventObjectMissingPid3: QualityAssuranceEventObject message: { type: 'doi', value: '10.4324/9780203408889', + pidHref: 'https://doi.org/10.4324/9780203408889', abstract: null, openaireId: null, acronym: null, @@ -1572,6 +1575,7 @@ export const qualityAssuranceEventObjectMissingPid4: QualityAssuranceEventObject message: { type: 'doi', value: '10.1080/13698230.2018.1430104', + pidHref: 'https://doi.org/10.1080/13698230.2018.1430104', abstract: null, openaireId: null, acronym: null, @@ -1608,6 +1612,7 @@ export const qualityAssuranceEventObjectMissingPid5: QualityAssuranceEventObject message: { type: 'urn', value: 'http://thesis2.sba.units.it/store/handle/item/12477', + pidHref:'http://thesis2.sba.units.it/store/handle/item/12477', abstract: null, openaireId: null, acronym: null, @@ -1644,6 +1649,7 @@ export const qualityAssuranceEventObjectMissingPid6: QualityAssuranceEventObject message: { type: 'doi', value: '10.1111/j.1475-4975.2004.00098.x', + pidHref: 'https://doi.org/10.1111/j.1475-4975.2004.00098.x', abstract: null, openaireId: null, acronym: null, @@ -1680,6 +1686,7 @@ export const qualityAssuranceEventObjectMissingAbstract: QualityAssuranceEventOb message: { type: null, value: null, + pidHref: 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, @@ -1716,6 +1723,7 @@ export const qualityAssuranceEventObjectMissingProjectFound: QualityAssuranceEve message: { type: null, value: null, + pidHref: null, abstract: null, openaireId: null, acronym: 'PAThs', @@ -1752,6 +1760,7 @@ export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssurance message: { type: null, value: null, + pidHref: null, abstract: null, openaireId: null, acronym: 'PAThs', 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 0f71123d22a..9f33a022251 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 @@ -38,7 +38,7 @@ import { FindListOptions } from '../../../core/data/find-list-options.model'; @Component({ selector: 'ds-quality-assurance-events', templateUrl: './quality-assurance-events.component.html', - styleUrls: ['./quality-assurance-events.scomponent.scss'], + styleUrls: ['./quality-assurance-events.component.scss'], }) export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { /** @@ -334,7 +334,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * @param event */ public getPIDHref(event: OpenaireQualityAssuranceEventMessageObject): string { - return this.computePIDHref(event); + return event.pidHref; } @@ -423,47 +423,4 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { ); } } - - protected computePIDHref(event: OpenaireQualityAssuranceEventMessageObject) { - 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; - } } From 3a70b880cbc41b32521d4251e7e912e9bb27b6d8 Mon Sep 17 00:00:00 2001 From: Luca Giamminonni <luca.giamminonni@4science.it> Date: Wed, 9 Nov 2022 15:13:09 +0100 Subject: [PATCH 018/282] [CST-5337] Renamed qa endpoints --- .../events/quality-assurance-event-rest.service.spec.ts | 2 +- .../qa/events/quality-assurance-event-rest.service.ts | 3 +-- .../quality-assurance-source-object.resource-type.ts | 2 +- .../quality-assurance-topic-object.resource-type.ts | 2 +- .../source/quality-assurance-source-rest.service.spec.ts | 2 +- .../qa/source/quality-assurance-source-rest.service.ts | 8 ++++---- .../topics/quality-assurance-topic-rest.service.spec.ts | 2 +- .../qa/topics/quality-assurance-topic-rest.service.ts | 8 ++++---- 8 files changed, 14 insertions(+), 15 deletions(-) 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-rest.service.spec.ts index 3734ae0dd2c..55b2788c8bd 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-rest.service.spec.ts @@ -38,7 +38,7 @@ describe('QualityAssuranceEventRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/qatopics'; + const endpointURL = 'https://rest.api/rest/api/integration/qualityassurancetopics'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const topic = 'ENRICH!MORE!PID'; 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-rest.service.ts index a7cdd9e786c..e4d13670a1e 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-rest.service.ts @@ -12,7 +12,6 @@ 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 { 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'; @@ -33,7 +32,7 @@ class DataServiceImpl extends DataService<QualityAssuranceEventObject> { /** * The REST endpoint. */ - protected linkPath = 'qaevents'; + protected linkPath = 'qualityassuranceevents'; /** * Initialize service variables diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts index 5f4c8dd954a..b4f64b24d14 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts +++ b/src/app/core/suggestion-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('qasource'); +export const QUALITY_ASSURANCE_SOURCE_OBJECT = new ResourceType('qualityassurancesource'); diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts index 7e12dd9ca81..e9fc57a307c 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts +++ b/src/app/core/suggestion-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('qatopic'); +export const QUALITY_ASSURANCE_TOPIC_OBJECT = new ResourceType('qualityassurancetopic'); 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-rest.service.spec.ts index d574b36802a..dc90b581cb7 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-rest.service.spec.ts @@ -32,7 +32,7 @@ describe('QualityAssuranceSourceRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/qasources'; + const endpointURL = 'https://rest.api/rest/api/integration/qualityassurancesources'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); 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-rest.service.ts index 6b5ca806ff0..05d2ba4ae61 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-rest.service.ts @@ -30,7 +30,7 @@ class DataServiceImpl extends DataService<QualityAssuranceSourceObject> { /** * The REST endpoint. */ - protected linkPath = 'qasources'; + protected linkPath = 'qualityassurancesources'; /** * Initialize service variables @@ -99,7 +99,7 @@ export class QualityAssuranceSourceRestService { * The list of Quality Assurance source. */ public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { - return this.dataService.getBrowseEndpoint(options, 'qasources').pipe( + return this.dataService.getBrowseEndpoint(options, 'qualityassurancesources').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), ); @@ -109,7 +109,7 @@ export class QualityAssuranceSourceRestService { * Clear FindAll source requests from cache */ public clearFindAllSourceRequests() { - this.requestService.setStaleByHrefSubstring('qasources'); + this.requestService.setStaleByHrefSubstring('qualityassurancesources'); } /** @@ -124,7 +124,7 @@ export class QualityAssuranceSourceRestService { */ public getSource(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'qasources').pipe( + return this.dataService.getBrowseEndpoint(options, 'qualityassurancesources').pipe( take(1), mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...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-rest.service.spec.ts index 458bc4957d6..babc9d83b33 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-rest.service.spec.ts @@ -32,7 +32,7 @@ describe('QualityAssuranceTopicRestService', () => { let http: HttpClient; let comparator: any; - const endpointURL = 'https://rest.api/rest/api/integration/qatopics'; + const endpointURL = 'https://rest.api/rest/api/integration/qualityassurancetopics'; const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); 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-rest.service.ts index a2f2498fcad..86942a7b5b7 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-rest.service.ts @@ -30,7 +30,7 @@ class DataServiceImpl extends DataService<QualityAssuranceTopicObject> { /** * The REST endpoint. */ - protected linkPath = 'qatopics'; + protected linkPath = 'qualityassurancetopics'; /** * Initialize service variables @@ -99,7 +99,7 @@ export class QualityAssuranceTopicRestService { * The list of Quality Assurance topics. */ public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { - return this.dataService.getBrowseEndpoint(options, 'qatopics').pipe( + return this.dataService.getBrowseEndpoint(options, 'qualityassurancetopics').pipe( take(1), mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), ); @@ -109,7 +109,7 @@ export class QualityAssuranceTopicRestService { * Clear FindAll topics requests from cache */ public clearFindAllTopicsRequests() { - this.requestService.setStaleByHrefSubstring('qatopics'); + this.requestService.setStaleByHrefSubstring('qualityassurancetopics'); } /** @@ -124,7 +124,7 @@ export class QualityAssuranceTopicRestService { */ public getTopic(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'qatopics').pipe( + return this.dataService.getBrowseEndpoint(options, 'qualityassurancetopics').pipe( take(1), mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) ); From 5efe3296c613be48d25251bfbfdd24e3d448556c Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Wed, 9 Nov 2022 19:05:20 +0100 Subject: [PATCH 019/282] [CST-5337] Refactoring in order to comply with new data service --- ...ality-assurance-event-rest.service.spec.ts | 47 +++--- .../quality-assurance-event-rest.service.ts | 137 ++++++++++-------- ...lity-assurance-source-rest.service.spec.ts | 24 ++- .../quality-assurance-source-rest.service.ts | 67 ++------- ...ality-assurance-topic-rest.service.spec.ts | 22 ++- .../quality-assurance-topic-rest.service.ts | 70 ++------- 6 files changed, 146 insertions(+), 221 deletions(-) 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-rest.service.spec.ts index 55b2788c8bd..731c70d6243 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-rest.service.spec.ts @@ -20,8 +20,8 @@ import { 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'; +import { RequestEntry } from '../../../data/request-entry.model'; +import { FindListOptions } from '../../../data/find-list-options.model'; describe('QualityAssuranceEventRestService', () => { let scheduler: TestScheduler; @@ -43,7 +43,7 @@ describe('QualityAssuranceEventRestService', () => { const topic = 'ENRICH!MORE!PID'; const pageInfo = new PageInfo(); - const array = [ qualityAssuranceEventObjectMissingPid, qualityAssuranceEventObjectMissingPid2 ]; + const array = [qualityAssuranceEventObjectMissingPid, qualityAssuranceEventObjectMissingPid2]; const paginatedList = buildPaginatedList(pageInfo, array); const qaEventObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingPid); const qaEventObjectMissingProjectRD = createSuccessfulRemoteDataObject(qualityAssuranceEventObjectMissingProjectFound); @@ -87,12 +87,13 @@ describe('QualityAssuranceEventRestService', () => { buildList: cold('(a)', { a: paginatedListRD }), - buildFromRequestUUID: jasmine.createSpy('buildFromRequestUUID') + buildFromRequestUUID: jasmine.createSpy('buildFromRequestUUID'), + buildFromRequestUUIDAndAwait: jasmine.createSpy('buildFromRequestUUIDAndAwait') }); objectCache = {} as ObjectCacheService; halService = jasmine.createSpyObj('halService', { - getEndpoint: cold('a|', { a: endpointURL }) + getEndpoint: cold('a|', { a: endpointURL }) }); notificationsService = {} as NotificationsService; @@ -105,17 +106,16 @@ describe('QualityAssuranceEventRestService', () => { 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(); + spyOn(serviceASAny.searchData, 'searchBy').and.callThrough(); + spyOn(serviceASAny, 'findById').and.callThrough(); + spyOn(serviceASAny.patchData, 'patch').and.callThrough(); + spyOn(serviceASAny, 'postOnRelated').and.callThrough(); + spyOn(serviceASAny, 'deleteOnRelated').and.callThrough(); }); describe('getEventsByTopic', () => { @@ -125,7 +125,7 @@ describe('QualityAssuranceEventRestService', () => { serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); }); - it('should proxy the call to dataservice.searchBy', () => { + it('should proxy the call to searchData.searchBy', () => { const options: FindListOptions = { searchParams: [ { @@ -135,13 +135,13 @@ describe('QualityAssuranceEventRestService', () => { ] }; service.getEventsByTopic(topic); - expect(serviceASAny.dataService.searchBy).toHaveBeenCalledWith('findByTopic', options, true, true); + expect(serviceASAny.searchData.searchBy).toHaveBeenCalledWith('findByTopic', options, true, true); }); it('should return a RemoteData<PaginatedList<QualityAssuranceEventObject>> for the object with the given Topic', () => { const result = service.getEventsByTopic(topic); const expected = cold('(a)', { - a: paginatedListRD + a: paginatedListRD }); expect(result).toBeObservable(expected); }); @@ -154,15 +154,15 @@ describe('QualityAssuranceEventRestService', () => { serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); }); - it('should proxy the call to dataservice.findById', () => { + it('should call findById', () => { service.getEvent(qualityAssuranceEventObjectMissingPid.id).subscribe( (res) => { - expect(serviceASAny.dataService.findById).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid.id, true, true); + expect(serviceASAny.findById).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid.id, true, true); } ); }); - it('should return a RemoteData<QualityAssuranceEventObject> for the object with the given URL', () => { + it('should return a RemoteData for the object with the given URL', () => { const result = service.getEvent(qualityAssuranceEventObjectMissingPid.id); const expected = cold('(a)', { a: qaEventObjectRD @@ -176,12 +176,13 @@ describe('QualityAssuranceEventRestService', () => { serviceASAny.requestService.getByHref.and.returnValue(observableOf(responseCacheEntry)); serviceASAny.requestService.getByUUID.and.returnValue(observableOf(responseCacheEntry)); serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectRD)); + serviceASAny.rdbService.buildFromRequestUUIDAndAwait.and.returnValue(observableOf(qaEventObjectRD)); }); - it('should proxy the call to dataservice.patch', () => { + it('should proxy the call to patchData.patch', () => { service.patchEvent(status, qualityAssuranceEventObjectMissingPid).subscribe( (res) => { - expect(serviceASAny.dataService.patch).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid, operation); + expect(serviceASAny.patchData.patch).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingPid, operation); } ); }); @@ -202,10 +203,10 @@ describe('QualityAssuranceEventRestService', () => { serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(qaEventObjectMissingProjectRD)); }); - it('should proxy the call to dataservice.postOnRelated', () => { + it('should call postOnRelated', () => { service.boundProject(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID).subscribe( (res) => { - expect(serviceASAny.dataService.postOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID); + expect(serviceASAny.postOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id, requestUUID); } ); }); @@ -226,10 +227,10 @@ describe('QualityAssuranceEventRestService', () => { serviceASAny.rdbService.buildFromRequestUUID.and.returnValue(observableOf(createSuccessfulRemoteDataObject({}))); }); - it('should proxy the call to dataservice.deleteOnRelated', () => { + it('should call deleteOnRelated', () => { service.removeProject(qualityAssuranceEventObjectMissingProjectFound.id).subscribe( (res) => { - expect(serviceASAny.dataService.deleteOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id); + expect(serviceASAny.deleteOnRelated).toHaveBeenCalledWith(qualityAssuranceEventObjectMissingProjectFound.id); } ); }); 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-rest.service.ts index e4d13670a1e..e83c9a8b439 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-rest.service.ts @@ -1,73 +1,42 @@ -/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; +import { find, take } from 'rxjs/operators'; +import { ReplaceOperation } from 'fast-json-patch'; 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 { dataService } from '../../../data/base/data-service.decorator'; import { RequestService } from '../../../data/request.service'; -import { ChangeAnalyzer } from '../../../data/change-analyzer'; -import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; import { RemoteData } from '../../../data/remote-data'; 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'; - - -/** - * A private DataService implementation to delegate specific methods to. - */ -class DataServiceImpl extends DataService<QualityAssuranceEventObject> { - /** - * The REST endpoint. - */ - protected linkPath = 'qualityassuranceevents'; - - /** - * Initialize service variables - * @param {RequestService} requestService - * @param {RemoteDataBuildService} rdbService - * @param {Store<CoreState>} store - * @param {ObjectCacheService} objectCache - * @param {HALEndpointService} halService - * @param {NotificationsService} notificationsService - * @param {HttpClient} http - * @param {ChangeAnalyzer<QualityAssuranceEventObject>} comparator - */ - constructor( - protected requestService: RequestService, - protected rdbService: RemoteDataBuildService, - protected store: Store<CoreState>, - protected objectCache: ObjectCacheService, - protected halService: HALEndpointService, - protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: ChangeAnalyzer<QualityAssuranceEventObject>) { - super(); - } -} +import { FindListOptions } from '../../../data/find-list-options.model'; +import { IdentifiableDataService } from '../../../data/base/identifiable-data.service'; +import { CreateData, CreateDataImpl } from '../../../data/base/create-data'; +import { PatchData, PatchDataImpl } from '../../../data/base/patch-data'; +import { DeleteData, DeleteDataImpl } from '../../../data/base/delete-data'; +import { SearchData, SearchDataImpl } from '../../../data/base/search-data'; +import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service'; +import { hasValue } from '../../../../shared/empty.util'; +import { DeleteByIDRequest, PostRequest } from '../../../data/request.models'; /** * The service handling all Quality Assurance topic REST requests. */ @Injectable() @dataService(QUALITY_ASSURANCE_EVENT_OBJECT) -export class QualityAssuranceEventRestService { - /** - * A private DataService implementation to delegate specific methods to. - */ - private dataService: DataServiceImpl; +export class QualityAssuranceEventRestService extends IdentifiableDataService<QualityAssuranceEventObject> { + + private createData: CreateData<QualityAssuranceEventObject>; + private searchData: SearchData<QualityAssuranceEventObject>; + private patchData: PatchData<QualityAssuranceEventObject>; + private deleteData: DeleteData<QualityAssuranceEventObject>; /** * Initialize service variables @@ -76,7 +45,6 @@ export class QualityAssuranceEventRestService { * @param {ObjectCacheService} objectCache * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService - * @param {HttpClient} http * @param {DefaultChangeAnalyzer<QualityAssuranceEventObject>} comparator */ constructor( @@ -85,9 +53,13 @@ export class QualityAssuranceEventRestService { protected objectCache: ObjectCacheService, protected halService: HALEndpointService, protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<QualityAssuranceEventObject>) { - this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + protected comparator: DefaultChangeAnalyzer<QualityAssuranceEventObject> + ) { + super('qualityassuranceevents', requestService, rdbService, objectCache, halService); + this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive); + this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint); + this.patchData = new PatchDataImpl<QualityAssuranceEventObject>(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint); + this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); } /** @@ -109,14 +81,14 @@ export class QualityAssuranceEventRestService { fieldValue: topic } ]; - return this.dataService.searchBy('findByTopic', options, true, true, ...linksToFollow); + return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow); } /** * Clear findByTopic requests from cache */ public clearFindByTopicRequests() { - this.requestService.removeByHrefSubstring('findByTopic'); + this.requestService.setStaleByHrefSubstring('findByTopic'); } /** @@ -130,7 +102,7 @@ export class QualityAssuranceEventRestService { * The Quality Assurance event. */ public getEvent(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceEventObject>[]): Observable<RemoteData<QualityAssuranceEventObject>> { - return this.dataService.findById(id, true, true, ...linksToFollow); + return this.findById(id, true, true, ...linksToFollow); } /** @@ -153,7 +125,7 @@ export class QualityAssuranceEventRestService { value: status } ]; - return this.dataService.patch(dso, operation); + return this.patchData.patch(dso, operation); } /** @@ -167,7 +139,7 @@ export class QualityAssuranceEventRestService { * The REST response. */ public boundProject(itemId: string, projectId: string): Observable<RemoteData<QualityAssuranceEventObject>> { - return this.dataService.postOnRelated(itemId, projectId); + return this.postOnRelated(itemId, projectId); } /** @@ -179,6 +151,53 @@ export class QualityAssuranceEventRestService { * The REST response. */ public removeProject(itemId: string): Observable<RemoteData<NoContent>> { - return this.dataService.deleteOnRelated(itemId); + return this.deleteOnRelated(itemId); + } + + /** + * Perform a delete operation on an endpoint related item. Ex.: endpoint/<itemId>/related + * @param objectId The item id + * @return the RestResponse as an Observable + */ + private deleteOnRelated(objectId: string): Observable<RemoteData<NoContent>> { + const requestId = this.requestService.generateRequestId(); + + const hrefObs = this.getIDHrefObs(objectId); + + hrefObs.pipe( + find((href: string) => hasValue(href)), + ).subscribe((href: string) => { + const request = new DeleteByIDRequest(requestId, href + '/related', objectId); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.send(request); + }); + + return this.rdbService.buildFromRequestUUID<QualityAssuranceEventObject>(requestId); + } + + /** + * Perform a post on an endpoint related item with ID. Ex.: endpoint/<itemId>/related?item=<relatedItemId> + * @param objectId The item id + * @param relatedItemId The related item Id + * @param body The optional POST body + * @return the RestResponse as an Observable + */ + private postOnRelated(objectId: string, relatedItemId: string, body?: any) { + const requestId = this.requestService.generateRequestId(); + const hrefObs = this.getIDHrefObs(objectId); + + 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<QualityAssuranceEventObject>(requestId); } } 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-rest.service.spec.ts index dc90b581cb7..f4a2d81b367 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-rest.service.spec.ts @@ -17,8 +17,8 @@ import { qualityAssuranceSourceObjectMoreAbstract, qualityAssuranceSourceObjectMorePid } from '../../../../shared/mocks/notifications.mock'; -import {RequestEntry} from '../../../data/request-entry.model'; -import {QualityAssuranceSourceRestService} from './quality-assurance-source-rest.service'; +import { RequestEntry } from '../../../data/request-entry.model'; +import { QualityAssuranceSourceRestService } from './quality-assurance-source-rest.service'; describe('QualityAssuranceSourceRestService', () => { let scheduler: TestScheduler; @@ -36,7 +36,7 @@ describe('QualityAssuranceSourceRestService', () => { const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); - const array = [ qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract ]; + const array = [qualityAssuranceSourceObjectMorePid, qualityAssuranceSourceObjectMoreAbstract]; const paginatedList = buildPaginatedList(pageInfo, array); const qaSourceObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceSourceObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); @@ -65,7 +65,7 @@ describe('QualityAssuranceSourceRestService', () => { objectCache = {} as ObjectCacheService; halService = jasmine.createSpyObj('halService', { - getEndpoint: cold('a|', { a: endpointURL }) + getEndpoint: cold('a|', { a: endpointURL }) }); notificationsService = {} as NotificationsService; @@ -77,20 +77,18 @@ describe('QualityAssuranceSourceRestService', () => { rdbService, objectCache, halService, - notificationsService, - http, - comparator + notificationsService ); - spyOn((service as any).dataService, 'findAllByHref').and.callThrough(); - spyOn((service as any).dataService, 'findByHref').and.callThrough(); + spyOn((service as any), 'findListByHref').and.callThrough(); + spyOn((service as any), 'findByHref').and.callThrough(); }); describe('getSources', () => { - it('should proxy the call to dataservice.findAllByHref', (done) => { + it('should call findListByHref', (done) => { service.getSources().subscribe( (res) => { - expect((service as any).dataService.findAllByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + expect((service as any).findListByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); } ); done(); @@ -106,10 +104,10 @@ describe('QualityAssuranceSourceRestService', () => { }); describe('getSource', () => { - it('should proxy the call to dataservice.findByHref', (done) => { + it('should call findByHref', (done) => { service.getSource(qualityAssuranceSourceObjectMorePid.id).subscribe( (res) => { - expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceSourceObjectMorePid.id, true, true); + expect((service as any).findByHref).toHaveBeenCalledWith(endpointURL + '/' + 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-rest.service.ts index 05d2ba4ae61..8f16347b252 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-rest.service.ts @@ -1,7 +1,5 @@ /* eslint-disable max-classes-per-file */ 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'; @@ -10,62 +8,22 @@ 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 { dataService } from '../../../data/base/data-service.decorator'; import { RequestService } from '../../../data/request.service'; -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 { 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'; - -/** - * A private DataService implementation to delegate specific methods to. - */ -class DataServiceImpl extends DataService<QualityAssuranceSourceObject> { - /** - * The REST endpoint. - */ - protected linkPath = 'qualityassurancesources'; - - /** - * Initialize service variables - * @param {RequestService} requestService - * @param {RemoteDataBuildService} rdbService - * @param {Store<CoreState>} store - * @param {ObjectCacheService} objectCache - * @param {HALEndpointService} halService - * @param {NotificationsService} notificationsService - * @param {HttpClient} http - * @param {ChangeAnalyzer<QualityAssuranceSourceObject>} comparator - */ - constructor( - protected requestService: RequestService, - protected rdbService: RemoteDataBuildService, - protected store: Store<CoreState>, - protected objectCache: ObjectCacheService, - protected halService: HALEndpointService, - protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: ChangeAnalyzer<QualityAssuranceSourceObject>) { - super(); - } -} +import { FindListOptions } from '../../../data/find-list-options.model'; +import { IdentifiableDataService } from '../../../data/base/identifiable-data.service'; /** * The service handling all Quality Assurance source REST requests. */ @Injectable() @dataService(QUALITY_ASSURANCE_SOURCE_OBJECT) -export class QualityAssuranceSourceRestService { - /** - * A private DataService implementation to delegate specific methods to. - */ - private dataService: DataServiceImpl; +export class QualityAssuranceSourceRestService extends IdentifiableDataService<QualityAssuranceSourceObject> { /** * Initialize service variables @@ -74,18 +32,15 @@ export class QualityAssuranceSourceRestService { * @param {ObjectCacheService} objectCache * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService - * @param {HttpClient} http - * @param {DefaultChangeAnalyzer<QualityAssuranceSourceObject>} comparator */ constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, - protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<QualityAssuranceSourceObject>) { - this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + protected notificationsService: NotificationsService + ) { + super('qualityassurancesources', requestService, rdbService, objectCache, halService); } /** @@ -99,9 +54,9 @@ export class QualityAssuranceSourceRestService { * The list of Quality Assurance source. */ public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { - return this.dataService.getBrowseEndpoint(options, 'qualityassurancesources').pipe( + return this.getBrowseEndpoint(options).pipe( take(1), - mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), + mergeMap((href: string) => this.findListByHref(href, options, true, true, ...linksToFollow)), ); } @@ -124,9 +79,9 @@ export class QualityAssuranceSourceRestService { */ public getSource(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'qualityassurancesources').pipe( + return this.getBrowseEndpoint(options, 'qualityassurancesources').pipe( take(1), - mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) + mergeMap((href: string) => this.findByHref(href + '/' + id, true, true, ...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-rest.service.spec.ts index babc9d83b33..d16ccbdb005 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-rest.service.spec.ts @@ -18,7 +18,7 @@ import { qualityAssuranceTopicObjectMoreAbstract, qualityAssuranceTopicObjectMorePid } from '../../../../shared/mocks/notifications.mock'; -import {RequestEntry} from '../../../data/request-entry.model'; +import { RequestEntry } from '../../../data/request-entry.model'; describe('QualityAssuranceTopicRestService', () => { let scheduler: TestScheduler; @@ -36,7 +36,7 @@ describe('QualityAssuranceTopicRestService', () => { const requestUUID = '8b3c913a-5a4b-438b-9181-be1a5b4a1c8a'; const pageInfo = new PageInfo(); - const array = [ qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract ]; + const array = [qualityAssuranceTopicObjectMorePid, qualityAssuranceTopicObjectMoreAbstract]; const paginatedList = buildPaginatedList(pageInfo, array); const qaTopicObjectRD = createSuccessfulRemoteDataObject(qualityAssuranceTopicObjectMorePid); const paginatedListRD = createSuccessfulRemoteDataObject(paginatedList); @@ -65,7 +65,7 @@ describe('QualityAssuranceTopicRestService', () => { objectCache = {} as ObjectCacheService; halService = jasmine.createSpyObj('halService', { - getEndpoint: cold('a|', { a: endpointURL }) + getEndpoint: cold('a|', { a: endpointURL }) }); notificationsService = {} as NotificationsService; @@ -77,20 +77,18 @@ describe('QualityAssuranceTopicRestService', () => { rdbService, objectCache, halService, - notificationsService, - http, - comparator + notificationsService ); - spyOn((service as any).dataService, 'findAllByHref').and.callThrough(); - spyOn((service as any).dataService, 'findByHref').and.callThrough(); + spyOn((service as any), 'findListByHref').and.callThrough(); + spyOn((service as any), 'findByHref').and.callThrough(); }); describe('getTopics', () => { - it('should proxy the call to dataservice.findAllByHref', (done) => { + it('should call findListByHref', (done) => { service.getTopics().subscribe( (res) => { - expect((service as any).dataService.findAllByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); + expect((service as any).findListByHref).toHaveBeenCalledWith(endpointURL, {}, true, true); } ); done(); @@ -106,10 +104,10 @@ describe('QualityAssuranceTopicRestService', () => { }); describe('getTopic', () => { - it('should proxy the call to dataservice.findByHref', (done) => { + it('should call findByHref', (done) => { service.getTopic(qualityAssuranceTopicObjectMorePid.id).subscribe( (res) => { - expect((service as any).dataService.findByHref).toHaveBeenCalledWith(endpointURL + '/' + qualityAssuranceTopicObjectMorePid.id, true, true); + expect((service as any).findByHref).toHaveBeenCalledWith(endpointURL + '/' + 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-rest.service.ts index 86942a7b5b7..2ab715bbbec 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-rest.service.ts @@ -1,7 +1,4 @@ -/* eslint-disable max-classes-per-file */ 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'; @@ -10,62 +7,22 @@ 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 { 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 { 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'; - -/** - * A private DataService implementation to delegate specific methods to. - */ -class DataServiceImpl extends DataService<QualityAssuranceTopicObject> { - /** - * The REST endpoint. - */ - protected linkPath = 'qualityassurancetopics'; - - /** - * Initialize service variables - * @param {RequestService} requestService - * @param {RemoteDataBuildService} rdbService - * @param {Store<CoreState>} store - * @param {ObjectCacheService} objectCache - * @param {HALEndpointService} halService - * @param {NotificationsService} notificationsService - * @param {HttpClient} http - * @param {ChangeAnalyzer<QualityAssuranceTopicObject>} comparator - */ - constructor( - protected requestService: RequestService, - protected rdbService: RemoteDataBuildService, - protected store: Store<CoreState>, - protected objectCache: ObjectCacheService, - protected halService: HALEndpointService, - protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: ChangeAnalyzer<QualityAssuranceTopicObject>) { - super(); - } -} +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'; /** * The service handling all Quality Assurance topic REST requests. */ @Injectable() @dataService(QUALITY_ASSURANCE_TOPIC_OBJECT) -export class QualityAssuranceTopicRestService { - /** - * A private DataService implementation to delegate specific methods to. - */ - private dataService: DataServiceImpl; +export class QualityAssuranceTopicRestService extends IdentifiableDataService<QualityAssuranceTopicObject> { /** * Initialize service variables @@ -74,18 +31,15 @@ export class QualityAssuranceTopicRestService { * @param {ObjectCacheService} objectCache * @param {HALEndpointService} halService * @param {NotificationsService} notificationsService - * @param {HttpClient} http - * @param {DefaultChangeAnalyzer<QualityAssuranceTopicObject>} comparator */ constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, - protected notificationsService: NotificationsService, - protected http: HttpClient, - protected comparator: DefaultChangeAnalyzer<QualityAssuranceTopicObject>) { - this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + protected notificationsService: NotificationsService + ) { + super('qualityassurancetopics', requestService, rdbService, objectCache, halService); } /** @@ -99,9 +53,9 @@ export class QualityAssuranceTopicRestService { * The list of Quality Assurance topics. */ public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { - return this.dataService.getBrowseEndpoint(options, 'qualityassurancetopics').pipe( + return this.getBrowseEndpoint(options).pipe( take(1), - mergeMap((href: string) => this.dataService.findAllByHref(href, options, true, true, ...linksToFollow)), + mergeMap((href: string) => this.findListByHref(href, options, true, true, ...linksToFollow)), ); } @@ -124,9 +78,9 @@ export class QualityAssuranceTopicRestService { */ public getTopic(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { const options = {}; - return this.dataService.getBrowseEndpoint(options, 'qualityassurancetopics').pipe( + return this.getBrowseEndpoint(options).pipe( take(1), - mergeMap((href: string) => this.dataService.findByHref(href + '/' + id, true, true, ...linksToFollow)) + mergeMap((href: string) => this.findByHref(href + '/' + id, true, true, ...linksToFollow)) ); } } From 58db3c7b0efed5aee9e1ec5940a2c306927d71cd Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Thu, 10 Nov 2022 18:28:10 +0100 Subject: [PATCH 020/282] [CST-5337] remove deprecated @Effect decorators --- .../quality-assurance-source.effects.ts | 36 +++++++++++-------- .../quality-assurance-topics.effects.ts | 25 +++++++------ 2 files changed, 36 insertions(+), 25 deletions(-) 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 2d758d26258..b1514171aaf 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 @@ -1,21 +1,26 @@ import { Injectable } from '@angular/core'; + import { Store } from '@ngrx/store'; -import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Actions, createEffect, 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, - QualityAssuranceSourceActionTypes, - RetrieveAllSourceAction, - RetrieveAllSourceErrorAction, + AddSourceAction, + QualityAssuranceSourceActionTypes, + RetrieveAllSourceAction, + RetrieveAllSourceErrorAction, } from './quality-assurance-source.actions'; - -import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { + QualityAssuranceSourceObject +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; 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'; +import { + QualityAssuranceSourceRestService +} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; /** * Provides effect methods for the Quality Assurance source actions. @@ -26,7 +31,7 @@ export class QualityAssuranceSourceEffects { /** * Retrieve all Quality Assurance source managing pagination and errors. */ - @Effect() retrieveAllSource$ = this.actions$.pipe( + retrieveAllSource$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE), withLatestFrom(this.store$), switchMap(([action, currentState]: [RetrieveAllSourceAction, any]) => { @@ -45,27 +50,27 @@ export class QualityAssuranceSourceEffects { }) ); }) - ); + )); /** * Show a notification on error. */ - @Effect({ dispatch: false }) retrieveAllSourceErrorAction$ = this.actions$.pipe( + retrieveAllSourceErrorAction$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceSourceActionTypes.RETRIEVE_ALL_SOURCE_ERROR), tap(() => { this.notificationsService.error(null, this.translate.get('quality-assurance.source.error.service.retrieve')); }) - ); + ), { dispatch: false }); /** * Clear find all source requests from cache. */ - @Effect({ dispatch: false }) addSourceAction$ = this.actions$.pipe( + addSourceAction$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceSourceActionTypes.ADD_SOURCE), tap(() => { this.qualityAssuranceSourceDataService.clearFindAllSourceRequests(); }) - ); + ), { dispatch: false }); /** * Initialize the effect class variables. @@ -83,5 +88,6 @@ export class QualityAssuranceSourceEffects { private notificationsService: NotificationsService, private qualityAssuranceSourceService: QualityAssuranceSourceService, private qualityAssuranceSourceDataService: QualityAssuranceSourceRestService - ) { } + ) { + } } 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 880a2d2318e..11d7e115553 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 @@ -1,21 +1,26 @@ import { Injectable } from '@angular/core'; + import { Store } from '@ngrx/store'; -import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Actions, createEffect, 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, QualityAssuranceTopicActionTypes, RetrieveAllTopicsAction, RetrieveAllTopicsErrorAction, } from './quality-assurance-topics.actions'; - -import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { + QualityAssuranceTopicObject +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; 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'; +import { + QualityAssuranceTopicRestService +} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; /** * Provides effect methods for the Quality Assurance topics actions. @@ -26,7 +31,7 @@ export class QualityAssuranceTopicsEffects { /** * Retrieve all Quality Assurance topics managing pagination and errors. */ - @Effect() retrieveAllTopics$ = this.actions$.pipe( + retrieveAllTopics$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS), withLatestFrom(this.store$), switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => { @@ -45,27 +50,27 @@ export class QualityAssuranceTopicsEffects { }) ); }) - ); + )); /** * Show a notification on error. */ - @Effect({ dispatch: false }) retrieveAllTopicsErrorAction$ = this.actions$.pipe( + retrieveAllTopicsErrorAction$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceTopicActionTypes.RETRIEVE_ALL_TOPICS_ERROR), tap(() => { this.notificationsService.error(null, this.translate.get('quality-assurance.topic.error.service.retrieve')); }) - ); + ), { dispatch: false }); /** * Clear find all topics requests from cache. */ - @Effect({ dispatch: false }) addTopicsAction$ = this.actions$.pipe( + addTopicsAction$ = createEffect(() => this.actions$.pipe( ofType(QualityAssuranceTopicActionTypes.ADD_TOPICS), tap(() => { this.qualityAssuranceTopicDataService.clearFindAllTopicsRequests(); }) - ); + ), { dispatch: false }); /** * Initialize the effect class variables. From 3188374800c46978f530cf2c5aa141c33e393475 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Fri, 11 Nov 2022 12:56:57 +0100 Subject: [PATCH 021/282] [CST-5537] Fix issues and refactoring in order to remove nested subscriptions --- ...ty-assurance-event-object.resource-type.ts | 2 +- .../quality-assurance-events.component.html | 56 +++--- .../quality-assurance-events.component.scss | 11 +- ...quality-assurance-events.component.spec.ts | 54 +++--- .../quality-assurance-events.component.ts | 168 +++++++++--------- .../quality-assurance-source.component.html | 4 +- .../quality-assurance-source.service.ts | 20 ++- .../quality-assurance-topics.component.html | 4 +- .../quality-assurance-topics.component.ts | 12 +- .../quality-assurance-topics.service.ts | 15 +- .../suggestion-notifications.module.ts | 4 +- 11 files changed, 196 insertions(+), 154 deletions(-) diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts b/src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts index 2dedc84d086..84aff6ba2cf 100644 --- a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts +++ b/src/app/core/suggestion-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('qaevent'); +export const QUALITY_ASSURANCE_EVENT_OBJECT = new ResourceType('qualityassuranceevent'); diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html index 209b2cde278..7f1b166d24c 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html @@ -1,21 +1,23 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom pb-2">{{'notifications.events.title'| translate}}</h2> - <p>{{'quality-assurance.events.description'| translate}}</p> - <p> - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> - <i class="fas fa-angle-double-left"></i> - {{'quality-assurance.events.back' | translate}} - </a> - </p> + <h2 class="border-bottom pb-2"> + <div class="d-flex justify-content-between"> + {{'notifications.events.title'| translate}} + <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> + <i class="fas fa-angle-double-left"></i> + {{'quality-assurance.events.back' | translate}} + </a> + </div> + </h2> + <ds-alert [type]="'alert-info'" [content]="'quality-assurance.events.description'"></ds-alert> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2"> + <h4 class="border-bottom pb-2"> {{'quality-assurance.events.topic' | translate}} {{this.showTopic}} - </h3> + </h4> <ds-loading class="container" *ngIf="(isEventPageLoading | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> @@ -25,8 +27,7 @@ <h3 class="border-bottom pb-2"> [sortOptions]="paginationSortConfig" (paginationChange)="getQualityAssuranceEvents()"> - <ds-loading class="container" *ngIf="(isEventLoading | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> - <ng-container *ngIf="!(isEventLoading | async)"> + <ng-container> <div *ngIf="(eventsUpdated$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert"> {{'quality-assurance.noEvents' | translate}} </div> @@ -34,11 +35,15 @@ <h3 class="border-bottom pb-2"> <table id="events" class="table table-striped table-hover table-bordered"> <thead> <tr> - <th scope="col">{{'quality-assurance.event.table.trust' | translate}}</th> - <th scope="col">{{'quality-assurance.event.table.publication' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col">{{'quality-assurance.event.table.details' | translate}}</th> - <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col">{{'quality-assurance.event.table.project-details' | translate}}</th> - <th scope="col" class="button-rows">{{'quality-assurance.event.table.actions' | translate}}</th> + <th scope="col" class="trust-col">{{'quality-assurance.event.table.trust' | translate}}</th> + <th scope="col" class="title-col">{{'quality-assurance.event.table.publication' | translate}}</th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') == -1" scope="col" class="content-col"> + {{'quality-assurance.event.table.details' | translate}} + </th> + <th *ngIf="hasDetailColumn() && showTopic.indexOf('/PROJECT') !== -1" scope="col" class="content-col"> + {{'quality-assurance.event.table.project-details' | translate}} + </th> + <th scope="col" class="button-col">{{'quality-assurance.event.table.actions' | translate}}</th> </tr> </thead> <tbody> @@ -51,7 +56,7 @@ <h3 class="border-bottom pb-2"> <span *ngIf="!eventElement?.target">{{eventElement.title}}</span> </td> <td *ngIf="showTopic.indexOf('/PID') !== -1"> - <p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> + <p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> <p><span class="small">{{'quality-assurance.event.table.pidvalue' | translate}}</span><br> <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" target="_blank"> {{eventElement.event.message.value}} @@ -82,18 +87,19 @@ <h3 class="border-bottom pb-2"> <a href="https://explore.openaire.eu/search/project?projectId={{ eventElement.event.message.openaireId}}" target="_blank">{{eventElement.event.message.title}}</a> </p> <p> - <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'quality-assurance.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> - <span *ngIf="eventElement.event.message.code"><span class="small">{{'quality-assurance.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> - <span *ngIf="eventElement.event.message.funder"><span class="small">{{'quality-assurance.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> - <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'quality-assurance.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> - <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'quality-assurance.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> + <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'quality-assurance.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> + <span *ngIf="eventElement.event.message.code"><span class="small">{{'quality-assurance.event.table.code' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.code}}</span><br></span> + <span *ngIf="eventElement.event.message.funder"><span class="small">{{'quality-assurance.event.table.funder' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.funder}}</span><br></span> + <span *ngIf="eventElement.event.message.fundingProgram"><span class="small">{{'quality-assurance.event.table.fundingProgram' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.fundingProgram}}</span><br></span> + <span *ngIf="eventElement.event.message.jurisdiction"><span class="small">{{'quality-assurance.event.table.jurisdiction' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.jurisdiction}}</span></span> </p> <hr> <div> {{(eventElement.hasProject ? 'quality-assurance.event.project.found' : 'quality-assurance.event.project.notFound') | translate}} <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}} </a> <div class="btn-group"> - <button class="btn btn-outline-primary btn-sm" + <button *ngIf="!eventElement.hasProject" + class="btn btn-outline-primary btn-sm" [disabled]="eventElement.isRunning" (click)="openModalLookup(eventElement); $event.stopPropagation();"> <i class="fas fa-search"></i> @@ -149,7 +155,7 @@ <h3 class="border-bottom pb-2"> </ds-pagination> </div> </div> - <div class="row"> + <div class="row text-right"> <div class="col-md-12"> <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> <i class="fas fa-angle-double-left"></i> 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<QualityAssuranceEventsComponent>; @@ -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<number>} */ - public totalElements$: Observable<number>; + public totalElements$: BehaviorSubject<number> = new BehaviorSubject<number>(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<boolean>} */ public isEventPageLoading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); - /** - * Contains the information about the loading status of the events inside the pagination component. - * @type {Observable<boolean>} - */ - public isEventLoading: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(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<QualityAssuranceEventObject>) => { - if (rd.isSuccess && rd.statusCode === 200) { + this.qualityAssuranceEventRestService.patchEvent(action, eventData.event, eventData.reason).pipe( + getFirstCompletedRemoteData(), + switchMap((rd: RemoteData<QualityAssuranceEventObject>) => { + 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<QualityAssuranceEventObject>) => { - 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<QualityAssuranceEventObject>) => { - 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<QualityAssuranceEventData[]> { + 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<PaginatedList<QualityAssuranceEventObject>>) => { - 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<PaginatedList<QualityAssuranceEventObject>>) => { + 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<Item>, RemoteData<Item>]) => { - 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<QualityAssuranceEventData[]> { + 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<Item>, RemoteData<Item>]) => { + 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 @@ <div class="row"> <div class="col-12"> <h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2> - <p>{{'quality-assurance.source.description'| translate}}</p> + <ds-alert [type]="'alert-info'" [content]="'quality-assurance.source.description'"></ds-alert> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2">{{'quality-assurance.source'| translate}}</h3> + <h4 class="border-bottom pb-2">{{'quality-assurance.source'| translate}}</h4> <ds-loading class="container" *ngIf="(isSourceLoading() | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isSourceLoading() | async)" 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 2d413a906dc..a0556ece8cc 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 @@ -1,12 +1,19 @@ import { Injectable } from '@angular/core'; + import { Observable } from 'rxjs'; -import { find, map } from 'rxjs/operators'; -import { QualityAssuranceSourceRestService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-rest.service'; +import { map } from 'rxjs/operators'; + +import { + QualityAssuranceSourceRestService +} from '../../../core/suggestion-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/suggestion-notifications/qa/models/quality-assurance-source.model'; -import {FindListOptions} from '../../../core/data/find-list-options.model'; +import { + QualityAssuranceSourceObject +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; +import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; /** * The service handling all Quality Assurance source requests to the REST service. @@ -20,7 +27,8 @@ export class QualityAssuranceSourceService { */ constructor( private qualityAssuranceSourceRestService: QualityAssuranceSourceRestService - ) { } + ) { + } /** * Return the list of Quality Assurance source managing pagination and errors. @@ -42,7 +50,7 @@ export class QualityAssuranceSourceService { }; return this.qualityAssuranceSourceRestService.getSources(findListOptions).pipe( - find((rd: RemoteData<PaginatedList<QualityAssuranceSourceObject>>) => !rd.isResponsePending), + getFirstCompletedRemoteData(), map((rd: RemoteData<PaginatedList<QualityAssuranceSourceObject>>) => { 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 @@ <div class="row"> <div class="col-12"> <h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2> - <p>{{'quality-assurance.topics.description'| translate:{source: sourceId} }}</p> + <ds-alert [type]="'alert-info'">{{'quality-assurance.topics.description'| translate:{source: sourceId} }}</ds-alert> </div> </div> <div class="row"> <div class="col-12"> - <h3 class="border-bottom pb-2">{{'quality-assurance.topics'| translate}}</h3> + <h4 class="border-bottom pb-2">{{'quality-assurance.topics'| translate}}</h4> <ds-loading class="container" *ngIf="(isTopicsLoading() | async)" message="{{'quality-assurance.loading' | translate}}"></ds-loading> <ds-pagination *ngIf="!(isTopicsLoading() | async)" diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts index a99944af6a0..3c8b4f8f38a 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts @@ -1,14 +1,18 @@ import { Component, OnInit } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; -import { distinctUntilChanged, map, take } from 'rxjs/operators'; +import { distinctUntilChanged, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; -import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { + QualityAssuranceTopicObject +} from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; import { hasValue } from '../../../shared/empty.util'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; -import { AdminQualityAssuranceTopicsPageParams } from '../../../admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-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 { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; @@ -59,7 +63,9 @@ export class QualityAssuranceTopicsComponent implements OnInit { /** * Initialize the component variables. * @param {PaginationService} paginationService + * @param {ActivatedRoute} activatedRoute * @param {SuggestionNotificationsStateService} notificationsStateService + * @param {QualityAssuranceTopicsService} qualityAssuranceTopicsService */ constructor( private paginationService: PaginationService, 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 e3e4b1aa93a..968e21fb957 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 @@ -1,13 +1,18 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { find, map } from 'rxjs/operators'; -import { QualityAssuranceTopicRestService } from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-rest.service'; +import { map } from 'rxjs/operators'; +import { + QualityAssuranceTopicRestService +} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-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 { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { + QualityAssuranceTopicObject +} from '../../../core/suggestion-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'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; +import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; /** * The service handling all Quality Assurance topic requests to the REST service. @@ -49,7 +54,7 @@ export class QualityAssuranceTopicsService { }; return this.qualityAssuranceTopicRestService.getTopics(findListOptions).pipe( - find((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => !rd.isResponsePending), + getFirstCompletedRemoteData(), map((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => { 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<SuggestionNotificationsState, Action>), 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 <giuseppe.digilio@4science.it> Date: Fri, 11 Nov 2022 13:07:21 +0100 Subject: [PATCH 022/282] [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 @@ <div class="d-flex justify-content-between"> <h2 *ngIf="!disableHeader">{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}</h2> - <ds-search-export-csv [searchConfig]="searchConfig"></ds-search-export-csv> + <ds-search-export-csv *ngIf="showExport" [searchConfig]="searchConfig"></ds-search-export-csv> </div> <div *ngIf="searchResults && searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn> <ds-viewable-collection diff --git a/src/app/shared/search/search-results/search-results.component.ts b/src/app/shared/search/search-results/search-results.component.ts index a11e0768337..34ce2162ea8 100644 --- a/src/app/shared/search/search-results/search-results.component.ts +++ b/src/app/shared/search/search-results/search-results.component.ts @@ -47,6 +47,11 @@ export class SearchResultsComponent { */ @Input() searchConfig: PaginatedSearchOptions; + /** + * A boolean representing if show export button + */ + @Input() showExport = true; + /** * The current sorting configuration of the search */ diff --git a/src/app/shared/search/search-results/themed-search-results.component.ts b/src/app/shared/search/search-results/themed-search-results.component.ts index deb64bf8400..bb48161766d 100644 --- a/src/app/shared/search/search-results/themed-search-results.component.ts +++ b/src/app/shared/search/search-results/themed-search-results.component.ts @@ -21,7 +21,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m templateUrl: '../../theme-support/themed.component.html', }) export class ThemedSearchResultsComponent extends ThemedComponent<SearchResultsComponent> { - 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<SearchResultsC @Input() searchConfig: PaginatedSearchOptions; + @Input() showExport = true; + @Input() sortConfig: SortOptions; @Input() viewMode: ViewMode; diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index cdad62dcbd9..f22ab3802df 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -30,16 +30,17 @@ </button> </div> <ds-themed-search-results [searchResults]="resultsRD$ | async" - [searchConfig]="searchOptions$ | async" - [configuration]="(currentConfiguration$ | async)" - [disableHeader]="!searchEnabled" - [linkType]="linkType" - [context]="(currentContext$ | async)" - [selectable]="selectable" - [selectionConfig]="selectionConfig" - (contentChange)="onContentChange($event)" - (deselectObject)="deselectObject.emit($event)" - (selectObject)="selectObject.emit($event)"></ds-themed-search-results> + [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)"></ds-themed-search-results> </div> </div> </ng-template> 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<SearchComponent> { - 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<SearchComponent> { @Input() selectionConfig: SelectionConfig; + @Input() showExport = true; + @Input() showSidebar = true; @Input() showViewModes = true; From 79cd69fb9421d818b9e33731fc8eb2e47f49f3c7 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Fri, 11 Nov 2022 13:07:52 +0100 Subject: [PATCH 023/282] [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 @@ <h4>{{ (labelPrefix + label + '.select' | translate) }}</h4> </div> <ds-loading *ngIf="(isLoading$ | async)" message="{{'loading.search-results' | translate}}"></ds-loading> - <ds-search-results *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length > 0 && !(isLoading$ | async)" - [searchResults]="(localEntitiesRD$ | async)" - [sortConfig]="this.searchOptions?.sort" - [searchConfig]="this.searchOptions" - [selectable]="true" - [disableHeader]="true" - [hidePaginationDetail]="false" - [selectionConfig]="{ repeatable: false, listId: entityListId }" - [linkType]="linkTypes.ExternalLink" - [context]="context" - (deselectObject)="deselectEntity()" - (selectObject)="selectEntity($event)"> - </ds-search-results> + <ds-themed-search-results *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length > 0 && !(isLoading$ | async)" + [searchResults]="(localEntitiesRD$ | async)" + [sortConfig]="this.searchOptions?.sort" + [searchConfig]="this.searchOptions" + [selectable]="true" + [disableHeader]="true" + [hidePaginationDetail]="false" + [selectionConfig]="{ repeatable: false, listId: entityListId }" + [showExport]="false" + [linkType]="linkTypes.ExternalLink" + [context]="context" + (deselectObject)="deselectEntity()" + (selectObject)="selectEntity($event)"> + </ds-themed-search-results> <div *ngIf="(localEntitiesRD$ | async)?.payload?.page?.length < 1 && !(isLoading$ | async)"> <ds-alert [type]="'alert-info'"> From b8880091e6da2f5168255b8de8a55723cbcb0f94 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.it> Date: Fri, 11 Nov 2022 14:41:50 +0100 Subject: [PATCH 024/282] [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 <giuseppe.digilio@4science.it> Date: Thu, 17 Nov 2022 11:45:59 +0100 Subject: [PATCH 025/282] [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<QualityAssuranceEventObject> { +export class QualityAssuranceEventDataService extends IdentifiableDataService<QualityAssuranceEventObject> { private createData: CreateData<QualityAssuranceEventObject>; private searchData: SearchData<QualityAssuranceEventObject>; 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<QualityAssuranceSourceObject> { +export class QualityAssuranceSourceDataService extends IdentifiableDataService<QualityAssuranceSourceObject> { + + private findAllData: FindAllData<QualityAssuranceSourceObject>; /** * Initialize service variables @@ -41,23 +42,24 @@ export class QualityAssuranceSourceRestService extends IdentifiableDataService<Q protected notificationsService: NotificationsService ) { super('qualityassurancesources', requestService, rdbService, objectCache, halService); + this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); } /** * 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. + * @param options Find list options object. + * @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<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> * The list of Quality Assurance source. */ - public getSources(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { - 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<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> { + return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } /** @@ -70,18 +72,16 @@ export class QualityAssuranceSourceRestService extends IdentifiableDataService<Q /** * Return a single Quality Assurance source. * - * @param id - * The Quality Assurance source id - * @param linksToFollow - * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. - * @return Observable<RemoteData<QualityAssuranceSourceObject>> - * 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<RemoteData<QualityAssuranceSourceObject>> The Quality Assurance source. */ - public getSource(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { - 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<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> { + 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<QualityAssuranceTopicObject> { +export class QualityAssuranceTopicDataService extends IdentifiableDataService<QualityAssuranceTopicObject> { + + private findAllData: FindAllData<QualityAssuranceTopicObject>; /** * Initialize service variables @@ -40,23 +42,24 @@ export class QualityAssuranceTopicRestService extends IdentifiableDataService<Qu protected notificationsService: NotificationsService ) { super('qualityassurancetopics', requestService, rdbService, objectCache, halService); + this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); } /** * 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. + * @param options Find list options object. + * @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<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> * The list of Quality Assurance topics. */ - public getTopics(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { - 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<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> { + return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } /** @@ -69,18 +72,17 @@ export class QualityAssuranceTopicRestService extends IdentifiableDataService<Qu /** * Return a single Quality Assurance topic. * - * @param id - * The Quality Assurance topic id - * @param linksToFollow - * List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved. + * @param id The Quality Assurance topic 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<RemoteData<QualityAssuranceTopicObject>> * The Quality Assurance topic. */ - public getTopic(id: string, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { - 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<QualityAssuranceTopicObject>[]): Observable<RemoteData<QualityAssuranceTopicObject>> { + 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 822db5120ad2d1d663c2c6ff39232e9efad715fe Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 22 May 2023 16:56:13 +0200 Subject: [PATCH 026/282] 101731: Make ConfirmationModalComponent not dependent on DSpaceObject --- .../epeople-registry/epeople-registry.component.ts | 2 +- .../eperson-form/eperson-form.component.ts | 2 +- .../group-registry/group-form/group-form.component.ts | 2 +- .../confirmation-modal/confirmation-modal.component.html | 8 ++++---- .../confirmation-modal/confirmation-modal.component.ts | 5 +---- .../export-batch-selector.component.ts | 4 +++- .../export-metadata-selector.component.ts | 4 +++- 7 files changed, 14 insertions(+), 13 deletions(-) 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 c7b9907b82a..c51070183a3 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.ts +++ b/src/app/access-control/epeople-registry/epeople-registry.component.ts @@ -228,7 +228,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy { deleteEPerson(ePerson: EPerson) { if (hasValue(ePerson.id)) { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = ePerson; + modalRef.componentInstance.name = this.dsoNameService.getName(ePerson); modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header'; modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info'; modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel'; 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 ce30062a692..41408c9e8f3 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 @@ -454,7 +454,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy { delete() { this.epersonService.getActiveEPerson().pipe(take(1)).subscribe((eperson: EPerson) => { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = eperson; + modalRef.componentInstance.name = this.dsoNameService.getName(eperson); modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header'; modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info'; modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel'; diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts index b837d80479d..37d30c218cd 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/access-control/group-registry/group-form/group-form.component.ts @@ -416,7 +416,7 @@ export class GroupFormComponent implements OnInit, OnDestroy { delete() { this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((group: Group) => { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = group; + modalRef.componentInstance.name = this.dsoNameService.getName(group); modalRef.componentInstance.headerLabel = this.messagePrefix + '.delete-group.modal.header'; modalRef.componentInstance.infoLabel = this.messagePrefix + '.delete-group.modal.info'; modalRef.componentInstance.cancelLabel = this.messagePrefix + '.delete-group.modal.cancel'; diff --git a/src/app/shared/confirmation-modal/confirmation-modal.component.html b/src/app/shared/confirmation-modal/confirmation-modal.component.html index 02434b1fa1e..ff82f5bc83d 100644 --- a/src/app/shared/confirmation-modal/confirmation-modal.component.html +++ b/src/app/shared/confirmation-modal/confirmation-modal.component.html @@ -1,18 +1,18 @@ <div> - <div class="modal-header">{{ headerLabel | translate:{ dsoName: dsoNameService.getName(dso) } }} + <div class="modal-header">{{ headerLabel | translate:{ dsoName: name } }} <button type="button" class="close" (click)="close()" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> - <p>{{ infoLabel | translate:{ dsoName: dsoNameService.getName(dso) } }}</p> + <p>{{ infoLabel | translate:{ dsoName: name } }}</p> </div> <div class="modal-footer"> <button type="button" class="cancel btn btn-outline-secondary" (click)="cancelPressed()" aria-label="Cancel"> - <i class="fas fa-times"></i> {{ cancelLabel | translate:{ dsoName: dsoNameService.getName(dso) } }} + <i class="fas fa-times"></i> {{ cancelLabel | translate:{ dsoName: name } }} </button> <button type="button" class="confirm btn btn-{{brandColor}}" (click)="confirmPressed()" aria-label="Confirm" ngbAutofocus> - <i *ngIf="confirmIcon" class="{{confirmIcon}}"></i> {{ confirmLabel | translate:{ dsoName: dsoNameService.getName(dso) } }} + <i *ngIf="confirmIcon" class="{{confirmIcon}}"></i> {{ confirmLabel | translate:{ dsoName: name } }} </button> </div> </div> diff --git a/src/app/shared/confirmation-modal/confirmation-modal.component.ts b/src/app/shared/confirmation-modal/confirmation-modal.component.ts index 46eb4cedc5a..e48986d880a 100644 --- a/src/app/shared/confirmation-modal/confirmation-modal.component.ts +++ b/src/app/shared/confirmation-modal/confirmation-modal.component.ts @@ -1,7 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; @Component({ selector: 'ds-confirmation-modal', @@ -18,7 +16,7 @@ export class ConfirmationModalComponent { */ @Input() brandColor = 'primary'; - @Input() dso: DSpaceObject; + @Input() name: string; /** * An event fired when the cancel or confirm button is clicked, with respectively false or true @@ -28,7 +26,6 @@ export class ConfirmationModalComponent { constructor( protected activeModal: NgbActiveModal, - public dsoNameService: DSONameService, ) { } diff --git a/src/app/shared/dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component.ts index 0645e09029d..e5f5eca350b 100644 --- a/src/app/shared/dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/export-batch-selector/export-batch-selector.component.ts @@ -20,6 +20,7 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths'; import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../../../core/data/feature-authorization/feature-id'; +import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; /** * Component to wrap a list of existing dso's inside a modal @@ -38,6 +39,7 @@ export class ExportBatchSelectorComponent extends DSOSelectorModalWrapperCompone protected notificationsService: NotificationsService, protected translationService: TranslateService, protected scriptDataService: ScriptDataService, protected authorizationDataService: AuthorizationDataService, + protected dsoNameService: DSONameService, private modalService: NgbModal) { super(activeModal, route); } @@ -49,7 +51,7 @@ export class ExportBatchSelectorComponent extends DSOSelectorModalWrapperCompone navigate(dso: DSpaceObject): Observable<boolean> { if (dso instanceof Collection) { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = dso; + modalRef.componentInstance.name = this.dsoNameService.getName(dso); modalRef.componentInstance.headerLabel = 'confirmation-modal.export-batch.header'; modalRef.componentInstance.infoLabel = 'confirmation-modal.export-batch.info'; modalRef.componentInstance.cancelLabel = 'confirmation-modal.export-batch.cancel'; diff --git a/src/app/shared/dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component.ts index d4b4314a991..d1252bf485b 100644 --- a/src/app/shared/dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/export-metadata-selector/export-metadata-selector.component.ts @@ -21,6 +21,7 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths'; import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../../../core/data/feature-authorization/feature-id'; +import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; /** * Component to wrap a list of existing dso's inside a modal @@ -39,6 +40,7 @@ export class ExportMetadataSelectorComponent extends DSOSelectorModalWrapperComp protected notificationsService: NotificationsService, protected translationService: TranslateService, protected scriptDataService: ScriptDataService, protected authorizationDataService: AuthorizationDataService, + protected dsoNameService: DSONameService, private modalService: NgbModal) { super(activeModal, route); } @@ -50,7 +52,7 @@ export class ExportMetadataSelectorComponent extends DSOSelectorModalWrapperComp navigate(dso: DSpaceObject): Observable<boolean> { if (dso instanceof Collection || dso instanceof Community) { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = dso; + modalRef.componentInstance.name = this.dsoNameService.getName(dso); modalRef.componentInstance.headerLabel = 'confirmation-modal.export-metadata.header'; modalRef.componentInstance.infoLabel = 'confirmation-modal.export-metadata.info'; modalRef.componentInstance.cancelLabel = 'confirmation-modal.export-metadata.cancel'; From 884aa0743096b4bfe946679aa48ad3f5727575df Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 23 Jun 2023 13:04:19 -0500 Subject: [PATCH 027/282] Update version tag for development of next release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 719b13b23b6..06d7063240f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dspace-angular", - "version": "7.6.0", + "version": "7.6.1-next", "scripts": { "ng": "ng", "config:watch": "nodemon", From 7998ef489cc4e30dc0f058d481329e2f39096caa Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 23 Jun 2023 23:38:06 +0200 Subject: [PATCH 028/282] 101731: Make ConfirmationModalComponent not dependent on DSpaceObject --- .../workspace-item-admin-workflow-actions.component.ts | 2 +- .../subscription-view/subscription-view.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts index 36678460da1..8db862dd5aa 100644 --- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts +++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/workspace-item-admin-workflow-actions.component.ts @@ -124,7 +124,7 @@ export class WorkspaceItemAdminWorkflowActionsComponent implements OnInit { */ deleteSupervisionOrder(supervisionOrderEntry: SupervisionOrderListEntry) { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = supervisionOrderEntry.group; + modalRef.componentInstance.name = this.dsoNameService.getName(supervisionOrderEntry.group); modalRef.componentInstance.headerLabel = this.messagePrefix + '.delete-supervision.modal.header'; modalRef.componentInstance.infoLabel = this.messagePrefix + '.delete-supervision.modal.info'; modalRef.componentInstance.cancelLabel = this.messagePrefix + '.delete-supervision.modal.cancel'; diff --git a/src/app/shared/subscriptions/subscription-view/subscription-view.component.ts b/src/app/shared/subscriptions/subscription-view/subscription-view.component.ts index 072b8d78281..0362ae6695e 100644 --- a/src/app/shared/subscriptions/subscription-view/subscription-view.component.ts +++ b/src/app/shared/subscriptions/subscription-view/subscription-view.component.ts @@ -82,7 +82,7 @@ export class SubscriptionViewComponent { deleteSubscriptionPopup(subscription: Subscription) { if (hasValue(subscription.id)) { const modalRef = this.modalService.open(ConfirmationModalComponent); - modalRef.componentInstance.dso = this.dso; + modalRef.componentInstance.name = this.dsoNameService.getName(this.dso); modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-subscription.header'; modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-subscription.info'; modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-subscription.cancel'; From 928d7a45a372003547b86be1ff3725288da43ad4 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 27 Jun 2023 15:26:49 +0200 Subject: [PATCH 029/282] 103176: Fix vcr not being defined yet in OnInit hook --- src/app/shared/theme-support/themed.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 2ff0713f460..920fbba6e56 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -1,10 +1,10 @@ import { + AfterViewInit, Component, ViewChild, ViewContainerRef, ComponentRef, SimpleChanges, - OnInit, OnDestroy, ComponentFactoryResolver, ChangeDetectorRef, @@ -21,7 +21,7 @@ import { GenericConstructor } from '../../core/shared/generic-constructor'; styleUrls: ['./themed.component.scss'], templateUrl: './themed.component.html', }) -export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges { +export abstract class ThemedComponent<T> implements AfterViewInit, OnDestroy, OnChanges { @ViewChild('vcr', { read: ViewContainerRef }) vcr: ViewContainerRef; protected compRef: ComponentRef<T>; @@ -49,7 +49,7 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges } } - ngOnInit(): void { + ngAfterViewInit(): void { this.destroyComponentInstance(); this.themeSub = this.themeService.getThemeName$().subscribe(() => { this.renderComponentInstance(); From a35b7d8356e17f4cdd8568389695b1685b27eb84 Mon Sep 17 00:00:00 2001 From: Kim Shepherd <kim@shepherd.nz> Date: Thu, 29 Jun 2023 16:09:54 +0200 Subject: [PATCH 030/282] catch and handle unsuccessful "convert rels to items" responses --- .../shared/item-relationships-utils.ts | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/app/item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/item-page/simple/item-types/shared/item-relationships-utils.ts index b4c3da2cdc3..0c4e82178f5 100644 --- a/src/app/item-page/simple/item-types/shared/item-relationships-utils.ts +++ b/src/app/item-page/simple/item-types/shared/item-relationships-utils.ts @@ -5,8 +5,7 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { Item } from '../../../../core/shared/item.model'; import { - getFirstSucceededRemoteDataPayload, - getFirstSucceededRemoteData + getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { hasValue } from '../../../../shared/empty.util'; import { InjectionToken } from '@angular/core'; @@ -77,24 +76,42 @@ export const relationsToItems = (thisId: string) => * @param {string} thisId The item's id of which the relations belong to * @returns {(source: Observable<Relationship[]>) => Observable<Item[]>} */ -export const paginatedRelationsToItems = (thisId: string) => - (source: Observable<RemoteData<PaginatedList<Relationship>>>): Observable<RemoteData<PaginatedList<Item>>> => +export const paginatedRelationsToItems = (thisId: string) => (source: Observable<RemoteData<PaginatedList<Relationship>>>): Observable<RemoteData<PaginatedList<Item>>> => source.pipe( - getFirstSucceededRemoteData(), + getFirstCompletedRemoteData(), switchMap((relationshipsRD: RemoteData<PaginatedList<Relationship>>) => { return observableCombineLatest( relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest([ - rel.leftItem.pipe(getFirstSucceededRemoteDataPayload()), - rel.rightItem.pipe(getFirstSucceededRemoteDataPayload())] + rel.leftItem.pipe( + getFirstCompletedRemoteData(), + map((rd: RemoteData<Item>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + return null; + } + }) + ), + rel.rightItem.pipe( + getFirstCompletedRemoteData(), + map((rd: RemoteData<Item>) => { + if (rd.hasSucceeded) { + return rd.payload; + } else { + return null; + } + }) + ), + ] ) - )).pipe( + ) + ).pipe( map((arr) => - arr - .map(([leftItem, rightItem]) => { - if (leftItem.id === thisId) { + arr.map(([leftItem, rightItem]) => { + if (hasValue(leftItem) && leftItem.id === thisId) { return rightItem; - } else if (rightItem.id === thisId) { + } else if (hasValue(rightItem) && rightItem.id === thisId) { return leftItem; } }) From ae6b183faec9cda0d2932143a52e14ef94bd945c Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Wed, 14 Jun 2023 18:51:42 +0200 Subject: [PATCH 031/282] 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<boolean> { - 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 <alexandre@atmire.com> Date: Fri, 30 Jun 2023 16:56:37 +0200 Subject: [PATCH 032/282] 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<boolean> = 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<boolean> = service.setStaleByHrefSubstring('https://rest.api/endpoint/selfLink'); + expect(done$).toBeObservable(cold('-----(a|)', { a: true })); + }); + }); + }); }); From c4342d3238b73d03cb92e8ce160884e66d14b49a Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 30 Jun 2023 14:57:09 -0500 Subject: [PATCH 033/282] Update version tag for development of next major release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06d7063240f..977a4bdc5ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dspace-angular", - "version": "7.6.1-next", + "version": "8.0.0-next", "scripts": { "ng": "ng", "config:watch": "nodemon", From b2b1782cd8505cf079782811bab4238e5cc0a359 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 30 Jun 2023 20:23:51 +0200 Subject: [PATCH 034/282] Hide entity field in collection form when entities aren't initialized --- .../collection-form/collection-form.component.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/collection-page/collection-form/collection-form.component.ts b/src/app/collection-page/collection-form/collection-form.component.ts index 23698de84e9..b52d282f634 100644 --- a/src/app/collection-page/collection-form/collection-form.component.ts +++ b/src/app/collection-page/collection-form/collection-form.component.ts @@ -79,9 +79,8 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp // retrieve all entity types to populate the dropdowns selection entities$.subscribe((entityTypes: ItemType[]) => { - entityTypes - .filter((type: ItemType) => type.label !== NONE_ENTITY_TYPE) - .forEach((type: ItemType, index: number) => { + entityTypes = entityTypes.filter((type: ItemType) => type.label !== NONE_ENTITY_TYPE); + entityTypes.forEach((type: ItemType, index: number) => { this.entityTypeSelection.add({ disabled: false, label: type.label, @@ -93,7 +92,7 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp } }); - this.formModel = [...collectionFormModels, this.entityTypeSelection]; + this.formModel = entityTypes.length === 0 ? collectionFormModels : [...collectionFormModels, this.entityTypeSelection]; super.ngOnInit(); }); From cf777268666587d5980408d7bc3872260606ae71 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 30 Jun 2023 22:41:07 +0200 Subject: [PATCH 035/282] Fix enter not submitting collection form correctly Fixed it for communities, collections, ePersons & groups --- .../eperson-form/eperson-form.component.html | 10 +++++----- .../group-form/group-form.component.html | 4 ++-- .../comcol-form/comcol-form.component.html | 2 +- 3 files changed, 8 insertions(+), 8 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 e9cc48aee3d..156f2e776da 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 @@ -15,23 +15,23 @@ <h4>{{messagePrefix + '.edit' | translate}}</h4> [displayCancel]="false" (submitForm)="onSubmit()"> <div before class="btn-group"> - <button (click)="onCancel()" + <button (click)="onCancel()" type="button" class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> </div> <div between class="btn-group"> - <button class="btn btn-primary" [disabled]="!(canReset$ | async)" (click)="resetPassword()"> + <button class="btn btn-primary" [disabled]="!(canReset$ | async)" type="button" (click)="resetPassword()"> <i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}} </button> </div> <div between class="btn-group ml-1"> - <button *ngIf="!isImpersonated" class="btn btn-primary" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" (click)="impersonate()"> + <button *ngIf="!isImpersonated" class="btn btn-primary" type="button" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" (click)="impersonate()"> <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}} </button> - <button *ngIf="isImpersonated" class="btn btn-primary" (click)="stopImpersonating()"> + <button *ngIf="isImpersonated" class="btn btn-primary" type="button" (click)="stopImpersonating()"> <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}} </button> </div> - <button after class="btn btn-danger delete-button" [disabled]="!(canDelete$ | async)" (click)="delete()"> + <button after class="btn btn-danger delete-button" type="button" [disabled]="!(canDelete$ | async)" (click)="delete()"> <i class="fas fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}} </button> </ds-form> 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 0fc5a574b7d..e50a4790904 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 @@ -25,12 +25,12 @@ <h2 class="border-bottom pb-2">{{messagePrefix + '.head.edit' | translate}}</h2> [displayCancel]="false" (submitForm)="onSubmit()"> <div before class="btn-group"> - <button (click)="onCancel()" + <button (click)="onCancel()" type="button" class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> </div> <div after *ngIf="groupBeingEdited != null" class="btn-group"> <button class="btn btn-danger delete-button" [disabled]="!(canEdit$ | async) || groupBeingEdited.permanent" - (click)="delete()"> + (click)="delete()" type="button"> <i class="fa fa-trash"></i> {{ messagePrefix + '.actions.delete' | translate}} </button> </div> diff --git a/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html index 5d7b092f740..b7b3d344b1e 100644 --- a/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol/comcol-forms/comcol-form/comcol-form.component.html @@ -42,7 +42,7 @@ [formModel]="formModel" [displayCancel]="false" (submitForm)="onSubmit()"> - <button before (click)="back.emit()" class="btn btn-outline-secondary"> + <button before (click)="back.emit()" class="btn btn-outline-secondary" type="button"> <i class="fas fa-arrow-left"></i> {{ type.value + '.edit.return' | translate }} </button> </ds-form> From 8ac1e9a2838ba24f73b3617190efb942406c9883 Mon Sep 17 00:00:00 2001 From: Alan Orth <alan.orth@gmail.com> Date: Wed, 5 Jul 2023 18:03:25 +0300 Subject: [PATCH 036/282] src/app: fix path to deny-request-copy component The themed-deny-request-copy.component erroneously includes the cus- tom theme's deny-request-copy component instead of its own. Closes: https://github.com/DSpace/dspace-angular/issues/2351 --- .../deny-request-copy/themed-deny-request-copy.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts b/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts index 664e4c541b4..1539d496225 100644 --- a/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts +++ b/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { ThemedComponent } from 'src/app/shared/theme-support/themed.component'; -import { DenyRequestCopyComponent } from 'src/themes/custom/app/request-copy/deny-request-copy/deny-request-copy.component'; +import { DenyRequestCopyComponent } from './deny-request-copy.component'; /** * Themed wrapper for deny-request-copy.component From 5208008f9558cbec4882b08852da118a29a6bfbc Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 7 Jul 2023 11:56:47 -0500 Subject: [PATCH 037/282] Enable Pull Request Opened action to assign PRs to their creator --- .../pull_request_opened.yml | 26 ------------------- .github/workflows/pull_request_opened.yml | 24 +++++++++++++++++ 2 files changed, 24 insertions(+), 26 deletions(-) delete mode 100644 .github/disabled-workflows/pull_request_opened.yml create mode 100644 .github/workflows/pull_request_opened.yml diff --git a/.github/disabled-workflows/pull_request_opened.yml b/.github/disabled-workflows/pull_request_opened.yml deleted file mode 100644 index 0dc718c0b9a..00000000000 --- a/.github/disabled-workflows/pull_request_opened.yml +++ /dev/null @@ -1,26 +0,0 @@ -# This workflow runs whenever a new pull request is created -# TEMPORARILY DISABLED. Unfortunately this doesn't work for PRs created from forked repositories (which is how we tend to create PRs). -# There is no known workaround yet. See https://github.community/t/how-to-use-github-token-for-prs-from-forks/16818 -name: Pull Request opened - -# Only run for newly opened PRs against the "main" branch -on: - pull_request: - types: [opened] - branches: - - main - -jobs: - automation: - runs-on: ubuntu-latest - steps: - # Assign the PR to whomever created it. This is useful for visualizing assignments on project boards - # See https://github.com/marketplace/actions/pull-request-assigner - - name: Assign PR to creator - uses: thomaseizinger/assign-pr-creator-action@v1.0.0 - # Note, this authentication token is created automatically - # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - # Ignore errors. It is possible the PR was created by someone who cannot be assigned - continue-on-error: true diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml new file mode 100644 index 00000000000..9b61af72d18 --- /dev/null +++ b/.github/workflows/pull_request_opened.yml @@ -0,0 +1,24 @@ +# This workflow runs whenever a new pull request is created +name: Pull Request opened + +# Only run for newly opened PRs against the "main" or maintenance branches +# We allow this to run for `pull_request_target` so that github secrets are available +# (This is required to assign a PR back to the creator when the PR comes from a forked repo) +on: + pull_request_target: + types: [ opened ] + branches: + - main + - 'dspace-**' + +permissions: + pull-requests: write + +jobs: + automation: + runs-on: ubuntu-latest + steps: + # Assign the PR to whomever created it. This is useful for visualizing assignments on project boards + # See https://github.com/toshimaru/auto-author-assign + - name: Assign PR to creator + uses: toshimaru/auto-author-assign@v1.6.2 From 15be060665e9f517f75afbede082cbf6fa749cf1 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 7 Jul 2023 11:56:54 -0500 Subject: [PATCH 038/282] Ensure codescan and label_merge_conflicts run on maintenance branches --- .github/workflows/codescan.yml | 10 +++++++--- .github/workflows/label_merge_conflicts.yml | 7 ++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codescan.yml b/.github/workflows/codescan.yml index 35a2e2d24aa..8b415296c71 100644 --- a/.github/workflows/codescan.yml +++ b/.github/workflows/codescan.yml @@ -5,12 +5,16 @@ # because CodeQL requires a fresh build with all tests *disabled*. name: "Code Scanning" -# Run this code scan for all pushes / PRs to main branch. Also run once a week. +# Run this code scan for all pushes / PRs to main or maintenance branches. Also run once a week. on: push: - branches: [ main ] + branches: + - main + - 'dspace-**' pull_request: - branches: [ main ] + branches: + - main + - 'dspace-**' # Don't run if PR is only updating static documentation paths-ignore: - '**/*.md' diff --git a/.github/workflows/label_merge_conflicts.yml b/.github/workflows/label_merge_conflicts.yml index c1396b6f45c..7ea33277411 100644 --- a/.github/workflows/label_merge_conflicts.yml +++ b/.github/workflows/label_merge_conflicts.yml @@ -1,11 +1,12 @@ # This workflow checks open PRs for merge conflicts and labels them when conflicts are found name: Check for merge conflicts -# Run whenever the "main" branch is updated -# NOTE: This means merge conflicts are only checked for when a PR is merged to main. +# Run this for all pushes (i.e. merges) to 'main' or maintenance branches on: push: - branches: [ main ] + branches: + - main + - 'dspace-**' # So that the `conflict_label_name` is removed if conflicts are resolved, # we allow this to run for `pull_request_target` so that github secrets are available. pull_request_target: From effe1816962b569134eea83c75704bba1721e2ae Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 7 Jul 2023 12:05:56 -0500 Subject: [PATCH 039/282] Split docker images into separate jobs to run in parallel. Ensure 'main' codebase is tagged as 'latest' --- .github/workflows/docker.yml | 84 ++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 9a2c838d83f..0c36d5af987 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,29 +15,35 @@ on: permissions: contents: read # to fetch code (actions/checkout) + +env: + # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) + # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. + # For a new commit on other branches, use the branch name as the tag for Docker image. + # For a new tag, copy that tag name as the tag for Docker image. + IMAGE_TAGS: | + type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} + type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }} + type=ref,event=tag + # Define default tag "flavor" for docker/metadata-action per + # https://github.com/docker/metadata-action#flavor-input + # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) + TAGS_FLAVOR: | + latest=false + # Architectures / Platforms for which we will build Docker images + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. + PLATFORMS: linux/amd64${{ github.event_name != 'pull_request' && ', linux/arm64' || '' }} + + jobs: - docker: + ############################################### + # Build/Push the 'dspace/dspace-angular' image + ############################################### + dspace-angular: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' if: github.repository == 'dspace/dspace-angular' runs-on: ubuntu-latest - env: - # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) - # For a new commit on default branch (main), use the literal tag 'dspace-7_x' on Docker image. - # For a new commit on other branches, use the branch name as the tag for Docker image. - # For a new tag, copy that tag name as the tag for Docker image. - IMAGE_TAGS: | - type=raw,value=dspace-7_x,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} - type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }} - type=ref,event=tag - # Define default tag "flavor" for docker/metadata-action per - # https://github.com/docker/metadata-action#flavor-input - # We turn off 'latest' tag by default. - TAGS_FLAVOR: | - latest=false - # Architectures / Platforms for which we will build Docker images - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. - PLATFORMS: linux/amd64${{ github.event_name != 'pull_request' && ', linux/arm64' || '' }} steps: # https://github.com/actions/checkout @@ -61,9 +67,6 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - ############################################### - # Build/Push the 'dspace/dspace-angular' image - ############################################### # https://github.com/docker/metadata-action # Get Metadata for docker_build step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular' image @@ -77,7 +80,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push 'dspace-angular' image id: docker_build - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: ./Dockerfile @@ -89,9 +92,36 @@ jobs: tags: ${{ steps.meta_build.outputs.tags }} labels: ${{ steps.meta_build.outputs.labels }} - ##################################################### - # Build/Push the 'dspace/dspace-angular' image ('-dist' tag) - ##################################################### + ############################################################# + # Build/Push the 'dspace/dspace-angular' image ('-dist' tag) + ############################################################# + dspace-angular-dist: + # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' + if: github.repository == 'dspace/dspace-angular' + runs-on: ubuntu-latest + + steps: + # https://github.com/actions/checkout + - name: Checkout codebase + uses: actions/checkout@v3 + + # https://github.com/docker/setup-buildx-action + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + # https://github.com/docker/setup-qemu-action + - name: Set up QEMU emulation to build for multiple architectures + uses: docker/setup-qemu-action@v2 + + # https://github.com/docker/login-action + - name: Login to DockerHub + # Only login if not a PR, as PRs only trigger a Docker build and not a push + if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + # https://github.com/docker/metadata-action # Get Metadata for docker_build_dist step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular-dist' image @@ -107,7 +137,7 @@ jobs: - name: Build and push 'dspace-angular-dist' image id: docker_build_dist - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: ./Dockerfile.dist From b5a70e8f95d1046bed0e33d5b0bdc8109d645676 Mon Sep 17 00:00:00 2001 From: Nona Luypaert <nona.luypaert@atmire.com> Date: Sat, 8 Jul 2023 00:20:30 +0200 Subject: [PATCH 040/282] Fix VocabularyTreeview not updating + i18n for nsi --- .../vocabulary-treeview/vocabulary-treeview.component.ts | 9 +++++++-- src/assets/i18n/en.json5 | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts index 017416e8c25..13d4495e614 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts @@ -1,5 +1,5 @@ import { FlatTreeControl } from '@angular/cdk/tree'; -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, OnChanges, SimpleChanges } from '@angular/core'; import { map } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; @@ -28,7 +28,7 @@ import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operato templateUrl: './vocabulary-treeview.component.html', styleUrls: ['./vocabulary-treeview.component.scss'] }) -export class VocabularyTreeviewComponent implements OnDestroy, OnInit { +export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges { /** * The {@link VocabularyOptions} object @@ -322,4 +322,9 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit { private getEntryId(entry: VocabularyEntry): string { return entry.authority || entry.otherInformation.id || undefined; } + + ngOnChanges(changes: SimpleChanges): void { + this.reset(); + this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.selectedItems, null); + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..ee594a9cb29 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -782,6 +782,8 @@ "browse.comcol.by.srsc": "By Subject Category", + "browse.comcol.by.nsi": "By Norwegian Science Index", + "browse.comcol.by.title": "By Title", "browse.comcol.head": "Browse", @@ -804,6 +806,8 @@ "browse.metadata.srsc.breadcrumbs": "Browse by Subject Category", + "browse.metadata.nsi.breadcrumbs": "Browse by Norwegian Science Index", + "browse.metadata.title.breadcrumbs": "Browse by Title", "pagination.next.button": "Next", @@ -2826,6 +2830,8 @@ "menu.section.browse_global_by_srsc": "By Subject Category", + "menu.section.browse_global_by_nsi": "By Norwegian Science Index", + "menu.section.browse_global_by_title": "By Title", "menu.section.browse_global_communities_and_collections": "Communities & Collections", From 23aefb7385a987c5cb3f3eb169b37037f032a126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= <eike.loehden@ub.uni-marburg.de> Date: Mon, 10 Jul 2023 15:29:14 +0200 Subject: [PATCH 041/282] 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<UserMenuComponent>{ + + /** + * 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<any> { + return import((`../../../../themes/${themeName}/app/shared/auth-nav-menu/user-menu/user-menu.component`)); + } + + protected importUnthemedComponent(): Promise<any> { + 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?= <eike.loehden@ub.uni-marburg.de> Date: Mon, 10 Jul 2023 15:34:25 +0200 Subject: [PATCH 042/282] 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?= <eike.loehden@ub.uni-marburg.de> Date: Mon, 10 Jul 2023 15:38:32 +0200 Subject: [PATCH 043/282] 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 @@ <div id="collapsingNav"> <ul class="navbar-nav navbar-navigation mr-auto shadow-none"> <li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)"> - <ds-user-menu [inExpandableNavbar]="true"></ds-user-menu> + <ds-themed-user-menu [inExpandableNavbar]="true"></ds-themed-user-menu> </li> <ng-container *ngFor="let section of (sections | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container> 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..3972cf288c1 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 @@ -22,7 +22,7 @@ <a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="dropdownLogout px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle> <i class="fas fa-user-circle fa-lg fa-fw"></i></a> <div class="logoutDropdownMenu" ngbDropdownMenu [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate"> - <ds-user-menu></ds-user-menu> + <ds-themed-user-menu></ds-themed-user-menu> </div> </div> </li> 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?= <eike.loehden@ub.uni-marburg.de> Date: Mon, 10 Jul 2023 15:54:09 +0200 Subject: [PATCH 044/282] 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 cac1407f08290adbc1a827fb1769011d3ecba803 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe <kristof.delanghe@atmire.com> Date: Wed, 12 Jul 2023 15:11:38 +0200 Subject: [PATCH 045/282] 104189: Allow CSV export on related entity search --- .../related-entities-search.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html index 2a08efeb2ca..36340bebfa0 100644 --- a/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html +++ b/src/app/item-page/simple/related-entities/related-entities-search/related-entities-search.component.html @@ -2,5 +2,6 @@ [fixedFilterQuery]="fixedFilter" [configuration]="configuration" [searchEnabled]="searchEnabled" - [sideBarWidth]="sideBarWidth"> + [sideBarWidth]="sideBarWidth" + [showCsvExport]="true"> </ds-configuration-search-page> From 45ad5f73168ccdf3d4f7ab617d44a0e28c94545a Mon Sep 17 00:00:00 2001 From: Kristof De Langhe <kristof.delanghe@atmire.com> Date: Wed, 12 Jul 2023 16:32:56 +0200 Subject: [PATCH 046/282] 104189: CSV export add fixedFilter --- .../search-export-csv.component.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app/shared/search/search-export-csv/search-export-csv.component.ts b/src/app/shared/search/search-export-csv/search-export-csv.component.ts index 6ad105342f6..1997a663a13 100644 --- a/src/app/shared/search/search-export-csv/search-export-csv.component.ts +++ b/src/app/shared/search/search-export-csv/search-export-csv.component.ts @@ -94,6 +94,19 @@ export class SearchExportCsvComponent implements OnInit { } }); } + if (isNotEmpty(this.searchConfig.fixedFilter)) { + const fixedFilter = this.searchConfig.fixedFilter.substring(2); + const keyAndValue = fixedFilter.split('='); + if (keyAndValue.length > 1) { + const key = keyAndValue[0]; + const valueAndOperator = keyAndValue[1].split(','); + if (valueAndOperator.length > 1) { + const value = valueAndOperator[0]; + const operator = valueAndOperator[1]; + parameters.push({name: '-f', value: `${key},${operator}=${value}`}); + } + } + } } this.scriptDataService.invoke('metadata-export-search', parameters, []).pipe( From 03e1f677b610498b6dbb54b1f3e6310bef5a1407 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe <kristof.delanghe@atmire.com> Date: Mon, 17 Jul 2023 15:08:54 +0200 Subject: [PATCH 047/282] 104126: ProcessDetailComponent test improvement --- .../detail/process-detail.component.spec.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/process-page/detail/process-detail.component.spec.ts b/src/app/process-page/detail/process-detail.component.spec.ts index 9552f9a092a..9a0d89a8827 100644 --- a/src/app/process-page/detail/process-detail.component.spec.ts +++ b/src/app/process-page/detail/process-detail.component.spec.ts @@ -147,7 +147,7 @@ describe('ProcessDetailComponent', () => { providers: [ { provide: ActivatedRoute, - useValue: { data: observableOf({ process: createSuccessfulRemoteDataObject(process) }) } + useValue: { data: observableOf({ process: createSuccessfulRemoteDataObject(process) }), snapshot: { params: { id: 1 } } }, }, { provide: ProcessDataService, useValue: processService }, { provide: BitstreamDataService, useValue: bitstreamDataService }, @@ -310,10 +310,11 @@ describe('ProcessDetailComponent', () => { }); it('should call refresh method every 5 seconds, until process is completed', fakeAsync(() => { - spyOn(component, 'refresh'); - spyOn(component, 'stopRefreshTimer'); + spyOn(component, 'refresh').and.callThrough(); + spyOn(component, 'stopRefreshTimer').and.callThrough(); - process.processStatus = ProcessStatus.COMPLETED; + // start off with a running process in order for the refresh counter starts counting up + process.processStatus = ProcessStatus.RUNNING; // set findbyId to return a completed process (processService.findById as jasmine.Spy).and.returnValue(observableOf(createSuccessfulRemoteDataObject(process))); @@ -336,6 +337,10 @@ describe('ProcessDetailComponent', () => { tick(1001); // 1 second + 1 ms by the setTimeout expect(component.refreshCounter$.value).toBe(0); // 1 - 1 + // set the process to completed right before the counter checks the process + process.processStatus = ProcessStatus.COMPLETED; + (processService.findById as jasmine.Spy).and.returnValue(observableOf(createSuccessfulRemoteDataObject(process))); + tick(1000); // 1 second expect(component.refresh).toHaveBeenCalledTimes(1); From 648925f3e1c0a51fc3eb61b7257e7a44ea57fee6 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 19 Jul 2023 14:01:41 +0200 Subject: [PATCH 048/282] 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 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat [collection]="collection" [relationship]="relationshipOptions" [context]="context" + [query]="query" [externalSource]="source" (importedObject)="imported($event)" class="d-block pt-3"> diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts index ca2535cb914..ef646c28eb2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts @@ -74,6 +74,12 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit * The context to displaying lists for */ @Input() context: Context; + + /** + * The search query + */ + @Input() query: string; + @Input() repeatable: boolean; /** * Emit an event when an object has been imported (or selected from similar local entries) @@ -147,8 +153,12 @@ export class DsDynamicLookupRelationExternalSourceTabComponent implements OnInit this.resetRoute(); this.entriesRD$ = this.searchConfigService.paginatedSearchOptions.pipe( - switchMap((searchOptions: PaginatedSearchOptions) => - this.externalSourceService.getExternalSourceEntries(this.externalSource.id, searchOptions).pipe(startWith(undefined))) + switchMap((searchOptions: PaginatedSearchOptions) => { + if (searchOptions.query === '') { + searchOptions.query = this.query; + } + return this.externalSourceService.getExternalSourceEntries(this.externalSource.id, searchOptions).pipe(startWith(undefined)); + }) ); this.currentPagination$ = this.paginationService.getCurrentPagination(this.searchConfigService.paginationID, this.initialPagination); this.importConfig = { From 8bf4ba812614e5ed34b2808b79d7e364fd01c2db Mon Sep 17 00:00:00 2001 From: Mirko Scherf <mscherf@uni-mainz.de> Date: Thu, 20 Jul 2023 14:53:28 +0200 Subject: [PATCH 049/282] refactor: rename aletr-type.ts to alert-type.ts --- .../group-registry/group-form/group-form.component.ts | 2 +- .../edit-item-template-page.component.ts | 2 +- .../dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts | 2 +- .../health-panel/health-component/health-component.component.ts | 2 +- src/app/item-page/alerts/item-alerts.component.ts | 2 +- .../item-version-history/item-version-history.component.ts | 2 +- .../item-page/orcid-page/orcid-queue/orcid-queue.component.ts | 2 +- src/app/item-page/versions/item-versions.component.ts | 2 +- .../item-page/versions/notice/item-versions-notice.component.ts | 2 +- src/app/process-page/detail/process-detail.component.ts | 2 +- src/app/register-email-form/register-email-form.component.ts | 2 +- .../access-control-form-container.component.ts | 2 +- src/app/shared/alert/{aletr-type.ts => alert-type.ts} | 0 src/app/shared/alert/alert.component.spec.ts | 2 +- src/app/shared/alert/alert.component.ts | 2 +- src/app/shared/error/error.component.ts | 2 +- .../sections/container/section-container.component.ts | 2 +- .../sections/identifiers/section-identifiers.component.ts | 2 +- .../publisher-policy/publisher-policy.component.ts | 2 +- .../sherpa-policies/section-sherpa-policies.component.ts | 2 +- src/app/submission/sections/upload/section-upload.component.ts | 2 +- 21 files changed, 20 insertions(+), 20 deletions(-) rename src/app/shared/alert/{aletr-type.ts => alert-type.ts} (100%) diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts index 3c0547cca50..693e283b4a0 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/access-control/group-registry/group-form/group-form.component.ts @@ -37,7 +37,7 @@ import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { ConfirmationModalComponent } from '../../../shared/confirmation-modal/confirmation-modal.component'; import { hasValue, isNotEmpty, hasValueOperator } from '../../../shared/empty.util'; import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts index 6425996fd2b..238ec5e37a2 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts @@ -8,7 +8,7 @@ import { ItemTemplateDataService } from '../../core/data/item-template-data.serv import { getCollectionEditRoute } from '../collection-page-routing-paths'; import { Item } from '../../core/shared/item.model'; import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators'; -import { AlertType } from '../../shared/alert/aletr-type'; +import { AlertType } from '../../shared/alert/alert-type'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; @Component({ diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts index d67a7ea738d..d44817be842 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, Injector, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { AlertType } from '../../shared/alert/aletr-type'; +import { AlertType } from '../../shared/alert/alert-type'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DsoEditMetadataForm } from './dso-edit-metadata-form'; import { map } from 'rxjs/operators'; diff --git a/src/app/health-page/health-panel/health-component/health-component.component.ts b/src/app/health-page/health-panel/health-component/health-component.component.ts index e212a072891..f2391c9c4cf 100644 --- a/src/app/health-page/health-panel/health-component/health-component.component.ts +++ b/src/app/health-page/health-panel/health-component/health-component.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { HealthComponent } from '../../models/health-component.model'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; /** * A component to render a "health component" object. diff --git a/src/app/item-page/alerts/item-alerts.component.ts b/src/app/item-page/alerts/item-alerts.component.ts index d7a84db015c..2b1df58c9f7 100644 --- a/src/app/item-page/alerts/item-alerts.component.ts +++ b/src/app/item-page/alerts/item-alerts.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { Item } from '../../core/shared/item.model'; -import { AlertType } from '../../shared/alert/aletr-type'; +import { AlertType } from '../../shared/alert/alert-type'; @Component({ selector: 'ds-item-alerts', diff --git a/src/app/item-page/edit-item-page/item-version-history/item-version-history.component.ts b/src/app/item-page/edit-item-page/item-version-history/item-version-history.component.ts index 18878109c29..3845c03578a 100644 --- a/src/app/item-page/edit-item-page/item-version-history/item-version-history.component.ts +++ b/src/app/item-page/edit-item-page/item-version-history/item-version-history.component.ts @@ -5,7 +5,7 @@ import { Item } from '../../../core/shared/item.model'; import { map } from 'rxjs/operators'; import { getFirstSucceededRemoteData } from '../../../core/shared/operators'; import { ActivatedRoute } from '@angular/router'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; @Component({ selector: 'ds-item-version-history', diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index 6079287f711..3e88826952e 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -15,7 +15,7 @@ import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { hasValue } from '../../../shared/empty.util'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { Item } from '../../../core/shared/item.model'; import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; diff --git a/src/app/item-page/versions/item-versions.component.ts b/src/app/item-page/versions/item-versions.component.ts index 700a35552c2..e7ee9d5ea29 100644 --- a/src/app/item-page/versions/item-versions.component.ts +++ b/src/app/item-page/versions/item-versions.component.ts @@ -23,7 +23,7 @@ import { PaginatedList } from '../../core/data/paginated-list.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { VersionHistoryDataService } from '../../core/data/version-history-data.service'; import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model'; -import { AlertType } from '../../shared/alert/aletr-type'; +import { AlertType } from '../../shared/alert/alert-type'; import { followLink } from '../../shared/utils/follow-link-config.model'; import { hasValue, hasValueOperator } from '../../shared/empty.util'; import { PaginationService } from '../../core/pagination/pagination.service'; diff --git a/src/app/item-page/versions/notice/item-versions-notice.component.ts b/src/app/item-page/versions/notice/item-versions-notice.component.ts index 8a8f5ff76f7..0e5e45806b7 100644 --- a/src/app/item-page/versions/notice/item-versions-notice.component.ts +++ b/src/app/item-page/versions/notice/item-versions-notice.component.ts @@ -12,7 +12,7 @@ import { } from '../../../core/shared/operators'; import { map, startWith, switchMap } from 'rxjs/operators'; import { VersionHistoryDataService } from '../../../core/data/version-history-data.service'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { getItemPageRoute } from '../../item-page-routing-paths'; @Component({ diff --git a/src/app/process-page/detail/process-detail.component.ts b/src/app/process-page/detail/process-detail.component.ts index a379dfe3376..be0b6ad0f64 100644 --- a/src/app/process-page/detail/process-detail.component.ts +++ b/src/app/process-page/detail/process-detail.component.ts @@ -17,7 +17,7 @@ import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; -import { AlertType } from '../../shared/alert/aletr-type'; +import { AlertType } from '../../shared/alert/alert-type'; import { hasValue } from '../../shared/empty.util'; import { ProcessStatus } from '../processes/process-status.model'; import { Process } from '../processes/process.model'; diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts index ddb77b669cb..df7e9bea5ef 100644 --- a/src/app/register-email-form/register-email-form.component.ts +++ b/src/app/register-email-form/register-email-form.component.ts @@ -13,7 +13,7 @@ import {isNotEmpty} from '../shared/empty.util'; import {BehaviorSubject, combineLatest, Observable, of, switchMap} from 'rxjs'; import {map, startWith, take} from 'rxjs/operators'; import {CAPTCHA_NAME, GoogleRecaptchaService} from '../core/google-recaptcha/google-recaptcha.service'; -import {AlertType} from '../shared/alert/aletr-type'; +import {AlertType} from '../shared/alert/alert-type'; import {KlaroService} from '../shared/cookies/klaro.service'; import {CookieService} from '../core/services/cookie.service'; import { Subscription } from 'rxjs'; diff --git a/src/app/shared/access-control-form-container/access-control-form-container.component.ts b/src/app/shared/access-control-form-container/access-control-form-container.component.ts index 69a598f7ce8..cddd1b1a29d 100644 --- a/src/app/shared/access-control-form-container/access-control-form-container.component.ts +++ b/src/app/shared/access-control-form-container/access-control-form-container.component.ts @@ -15,7 +15,7 @@ import { import { BulkAccessConfigDataService } from '../../core/config/bulk-access-config-data.service'; import { getFirstCompletedRemoteData } from '../../core/shared/operators'; import { BulkAccessConditionOptions } from '../../core/config/models/bulk-access-condition-options.model'; -import { AlertType } from '../alert/aletr-type'; +import { AlertType } from '../alert/alert-type'; import { createAccessControlInitialFormState } from './access-control-form-container-intial-state'; diff --git a/src/app/shared/alert/aletr-type.ts b/src/app/shared/alert/alert-type.ts similarity index 100% rename from src/app/shared/alert/aletr-type.ts rename to src/app/shared/alert/alert-type.ts diff --git a/src/app/shared/alert/alert.component.spec.ts b/src/app/shared/alert/alert.component.spec.ts index 21e4d197b7f..11411c7de02 100644 --- a/src/app/shared/alert/alert.component.spec.ts +++ b/src/app/shared/alert/alert.component.spec.ts @@ -8,7 +8,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { AlertComponent } from './alert.component'; import { createTestComponent } from '../testing/utils.test'; -import { AlertType } from './aletr-type'; +import { AlertType } from './alert-type'; describe('AlertComponent test suite', () => { diff --git a/src/app/shared/alert/alert.component.ts b/src/app/shared/alert/alert.component.ts index 93535d20575..07a8efbd7df 100644 --- a/src/app/shared/alert/alert.component.ts +++ b/src/app/shared/alert/alert.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; import { trigger } from '@angular/animations'; -import { AlertType } from './aletr-type'; +import { AlertType } from './alert-type'; import { fadeOutLeave, fadeOutState } from '../animations/fade'; /** diff --git a/src/app/shared/error/error.component.ts b/src/app/shared/error/error.component.ts index 9a6b0660bb3..6572598c8b1 100644 --- a/src/app/shared/error/error.component.ts +++ b/src/app/shared/error/error.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { AlertType } from '../alert/aletr-type'; +import { AlertType } from '../alert/alert-type'; @Component({ selector: 'ds-error', diff --git a/src/app/submission/sections/container/section-container.component.ts b/src/app/submission/sections/container/section-container.component.ts index 8f9ebfbfda7..3331629f332 100644 --- a/src/app/submission/sections/container/section-container.component.ts +++ b/src/app/submission/sections/container/section-container.component.ts @@ -3,7 +3,7 @@ import { Component, Injector, Input, OnInit, ViewChild } from '@angular/core'; import { SectionsDirective } from '../sections.directive'; import { SectionDataObject } from '../models/section-data.model'; import { rendersSectionType } from '../sections-decorator'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; /** * This component represents a section that contains the submission license form. diff --git a/src/app/submission/sections/identifiers/section-identifiers.component.ts b/src/app/submission/sections/identifiers/section-identifiers.component.ts index 2dc70f668e5..ac4af63adb2 100644 --- a/src/app/submission/sections/identifiers/section-identifiers.component.ts +++ b/src/app/submission/sections/identifiers/section-identifiers.component.ts @@ -7,7 +7,7 @@ import { SectionModelComponent } from '../models/section.model'; import { renderSectionFor } from '../sections-decorator'; import { SectionDataObject } from '../models/section-data.model'; import { SubmissionService } from '../../submission.service'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { SectionsService } from '../sections.service'; import { WorkspaceitemSectionIdentifiersObject } from '../../../core/submission/models/workspaceitem-section-identifiers.model'; diff --git a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts index 96ada3904c2..25407f5a7bb 100644 --- a/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts +++ b/src/app/submission/sections/sherpa-policies/publisher-policy/publisher-policy.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core'; import { Policy } from '../../../../core/submission/models/sherpa-policies-details.model'; -import { AlertType } from '../../../../shared/alert/aletr-type'; +import { AlertType } from '../../../../shared/alert/alert-type'; /** * This component represents a section that contains the publisher policy informations. diff --git a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts index e55b75146f6..eb273a84202 100644 --- a/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts +++ b/src/app/submission/sections/sherpa-policies/section-sherpa-policies.component.ts @@ -1,4 +1,4 @@ -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { Component, Inject } from '@angular/core'; import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'; diff --git a/src/app/submission/sections/upload/section-upload.component.ts b/src/app/submission/sections/upload/section-upload.component.ts index eefed8a36b5..10203adbc0d 100644 --- a/src/app/submission/sections/upload/section-upload.component.ts +++ b/src/app/submission/sections/upload/section-upload.component.ts @@ -21,7 +21,7 @@ import { SectionsType } from '../sections-type'; import { renderSectionFor } from '../sections-decorator'; import { SectionDataObject } from '../models/section-data.model'; import { SubmissionObjectEntry } from '../../objects/submission-objects.reducer'; -import { AlertType } from '../../../shared/alert/aletr-type'; +import { AlertType } from '../../../shared/alert/alert-type'; import { RemoteData } from '../../../core/data/remote-data'; import { Group } from '../../../core/eperson/models/group.model'; import { SectionsService } from '../sections.service'; From c9558167b2dc2df22428b8d1fcfbd9b77e4b855e Mon Sep 17 00:00:00 2001 From: Yury Bondarenko <ybnd@tuta.io> Date: Thu, 20 Jul 2023 18:19:48 +0200 Subject: [PATCH 050/282] Move subscription button to DSO edit menu --- .../collection-page.component.html | 3 - .../community-page.component.html | 3 - .../shared/dso-page/dso-edit-menu.resolver.ts | 37 +++++++++ ...so-page-subscription-button.component.html | 8 -- ...so-page-subscription-button.component.scss | 0 ...page-subscription-button.component.spec.ts | 83 ------------------- .../dso-page-subscription-button.component.ts | 57 ------------- src/app/shared/shared.module.ts | 4 - 8 files changed, 37 insertions(+), 158 deletions(-) delete mode 100644 src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.html delete mode 100644 src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.scss delete mode 100644 src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.spec.ts delete mode 100644 src/app/shared/dso-page/dso-page-subscription-button/dso-page-subscription-button.component.ts diff --git a/src/app/collection-page/collection-page.component.html b/src/app/collection-page/collection-page.component.html index 02c63d316d8..3cbd08f1325 100644 --- a/src/app/collection-page/collection-page.component.html +++ b/src/app/collection-page/collection-page.component.html @@ -34,9 +34,6 @@ </ds-comcol-page-content> </header> <ds-dso-edit-menu></ds-dso-edit-menu> - <div class="pl-2 space-children-mr"> - <ds-dso-page-subscription-button [dso]="collection"></ds-dso-page-subscription-button> - </div> </div> <section class="comcol-page-browse-section"> <!-- Browse-By Links --> 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 @@ </ds-comcol-page-content> </header> <ds-dso-edit-menu></ds-dso-edit-menu> - <div class="pl-2 space-children-mr"> - <ds-dso-page-subscription-button [dso]="communityPayload"></ds-dso-page-subscription-button> - </div> </div> <section class="comcol-page-browse-section"> 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<MenuSection[]>[] { 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<MenuSection[]> { + 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 @@ -<button *ngIf="isAuthorized$ | async" data-test="subscription-button" - (click)="openSubscriptionModal()" - [ngbTooltip]="'subscriptions.tooltip' | translate" - [title]="'subscriptions.tooltip' | translate" - [attr.aria-label]="'subscriptions.tooltip' | translate" - class="subscription-button btn btn-dark btn-sm"> - <i class="fas fa-bell fa-fw"></i> -</button> 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<DsoPageSubscriptionButtonComponent>; - 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<boolean> = 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 b1df1251663b162a6fbc3555bcb5e7cfca4c12b4 Mon Sep 17 00:00:00 2001 From: Mirko Scherf <mscherf@uni-mainz.de> Date: Fri, 21 Jul 2023 10:43:13 +0200 Subject: [PATCH 051/282] fix(i18n): add and update missing status strings New strings for status filter entries: search.filters.namedresourcetype.* Refactored strings introduced with #2068 (refactor badged), e.g. mydspace.status.archived -> mydspace.status.mydspaceArchived --- src/assets/i18n/ar.json5 | 20 ++++++++++---------- src/assets/i18n/bn.json5 | 20 ++++++++++---------- src/assets/i18n/ca.json5 | 20 ++++++++++---------- src/assets/i18n/cs.json5 | 20 ++++++++++---------- src/assets/i18n/de.json5 | 35 +++++++++++++++++++++++++---------- src/assets/i18n/el.json5 | 10 +++++----- src/assets/i18n/en.json5 | 10 ++++++++++ src/assets/i18n/es.json5 | 20 ++++++++++---------- src/assets/i18n/fi.json5 | 20 ++++++++++---------- src/assets/i18n/fr.json5 | 20 ++++++++++---------- src/assets/i18n/gd.json5 | 20 ++++++++++---------- src/assets/i18n/hi.json5 | 10 +++++----- src/assets/i18n/hu.json5 | 20 ++++++++++---------- src/assets/i18n/it.json5 | 20 ++++++++++---------- src/assets/i18n/ja.json5 | 20 ++++++++++---------- src/assets/i18n/kk.json5 | 20 ++++++++++---------- src/assets/i18n/lv.json5 | 20 ++++++++++---------- src/assets/i18n/nl.json5 | 20 ++++++++++---------- src/assets/i18n/pl.json5 | 10 +++++----- src/assets/i18n/pt-BR.json5 | 20 ++++++++++---------- src/assets/i18n/pt-PT.json5 | 20 ++++++++++---------- src/assets/i18n/sv.json5 | 20 ++++++++++---------- src/assets/i18n/sw.json5 | 20 ++++++++++---------- src/assets/i18n/tr.json5 | 20 ++++++++++---------- src/assets/i18n/uk.json5 | 20 ++++++++++---------- src/assets/i18n/vi.json5 | 10 +++++----- 26 files changed, 255 insertions(+), 230 deletions(-) diff --git a/src/assets/i18n/ar.json5 b/src/assets/i18n/ar.json5 index 70f5fdadb1d..3069104dd9a 100644 --- a/src/assets/i18n/ar.json5 +++ b/src/assets/i18n/ar.json5 @@ -4276,25 +4276,25 @@ // TODO New key - Add a translation "mydspace.show.workspace": "Your Submissions", - // "mydspace.status.archived": "Archived", + // "mydspace.status.mydspaceArchived": "Archived", // TODO New key - Add a translation - "mydspace.status.archived": "Archived", + "mydspace.status.mydspaceArchived": "Archived", - // "mydspace.status.validation": "Validation", + // "mydspace.status.mydspaceValidation": "Validation", // TODO New key - Add a translation - "mydspace.status.validation": "Validation", + "mydspace.status.mydspaceValidation": "Validation", - // "mydspace.status.waiting-for-controller": "Waiting for controller", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", // TODO New key - Add a translation - "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Waiting for controller", - // "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", // TODO New key - Add a translation - "mydspace.status.workflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", // TODO New key - Add a translation - "mydspace.status.workspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", // TODO New key - Add a translation diff --git a/src/assets/i18n/bn.json5 b/src/assets/i18n/bn.json5 index cc05d128287..c70cc6f4595 100644 --- a/src/assets/i18n/bn.json5 +++ b/src/assets/i18n/bn.json5 @@ -3880,20 +3880,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "আপনার জমাগুলো", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "সংরক্ষণাগারভুক্ত", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "সংরক্ষণাগারভুক্ত", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "বৈধতা", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "বৈধতা", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "নিয়ামক জন্য অপেক্ষা করছে", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "নিয়ামক জন্য অপেক্ষা করছে", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "ওয়ার্কফ্লো", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "ওয়ার্কফ্লো", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "কর্মক্ষেত্র", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "কর্মক্ষেত্র", // "mydspace.title": "MyDSpace", "mydspace.title": "আমার ডিস্পেস", diff --git a/src/assets/i18n/ca.json5 b/src/assets/i18n/ca.json5 index 34279548bb2..ad8fe49424e 100644 --- a/src/assets/i18n/ca.json5 +++ b/src/assets/i18n/ca.json5 @@ -4190,20 +4190,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Els seus enviaments", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arxivat", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arxivat", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validació", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validació", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Esperant el controlador", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Esperant el controlador", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Flux de treball", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Flux de treball", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Espai de treball", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Espai de treball", // "mydspace.title": "MyDSpace", "mydspace.title": "El meu DSpace", diff --git a/src/assets/i18n/cs.json5 b/src/assets/i18n/cs.json5 index f3155e9f57a..7f9583a50eb 100644 --- a/src/assets/i18n/cs.json5 +++ b/src/assets/i18n/cs.json5 @@ -4187,25 +4187,25 @@ // TODO New key - Add a translation "mydspace.show.workspace": "Your Submissions", - // "mydspace.status.archived": "Archived", + // "mydspace.status.mydspaceArchived": "Archived", // TODO New key - Add a translation - "mydspace.status.archived": "Archived", + "mydspace.status.mydspaceArchived": "Archived", - // "mydspace.status.validation": "Validation", + // "mydspace.status.mydspaceValidation": "Validation", // TODO New key - Add a translation - "mydspace.status.validation": "Validation", + "mydspace.status.mydspaceValidation": "Validation", - // "mydspace.status.waiting-for-controller": "Waiting for controller", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", // TODO New key - Add a translation - "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Waiting for controller", - // "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", // TODO New key - Add a translation - "mydspace.status.workflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", // TODO New key - Add a translation - "mydspace.status.workspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", // TODO New key - Add a translation diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index b03dc21e5a5..4ebce8012d6 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -3484,20 +3484,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Ihre Veröffentlichungen", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Archiviert", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Archiviert", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validierung", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validierung", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Warten auf die Überprüfung", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Warten auf die Überprüfung", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Geschäftsgang", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Geschäftsgang", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Arbeitsbereich", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Arbeitsbereich", // "mydspace.title": "MyDSpace", "mydspace.title": "Mein DSpace", @@ -4487,6 +4487,21 @@ // "search.filters.discoverable.false": "Yes", "search.filters.discoverable.false": "Ja", + // "search.filters.namedresourcetype.Archived": "Archived", + "search.filters.namedresourcetype.Archived": "Archiviert", + + // "search.filters.namedresourcetype.Validation": "Validation", + "search.filters.namedresourcetype.Validation": "Validierung", + + // "search.filters.namedresourcetype.Waiting for Controller": "Waiting for Controller", + "search.filters.namedresourcetype.Waiting for Controller": "Warten auf die Überprüfung", + + // "search.filters.namedresourcetype.Workflow": "Workflow", + "search.filters.namedresourcetype.Workflow": "Geschäftsgang", + + // "search.filters.namedresourcetype.Workspace": "Workspace", + "search.filters.namedresourcetype.Workspace": "Arbeitsbereich", + // "search.filters.withdrawn.true": "Yes", "search.filters.withdrawn.true": "Ja", diff --git a/src/assets/i18n/el.json5 b/src/assets/i18n/el.json5 index af8a4fce490..176eadff628 100644 --- a/src/assets/i18n/el.json5 +++ b/src/assets/i18n/el.json5 @@ -1315,11 +1315,11 @@ "mydspace.search-form.placeholder": "Αναζήτηση στο mydspace...", "mydspace.show.workflow": "Εργασίες ροής εργασιών", "mydspace.show.workspace": "Οι Υποβολές σας", - "mydspace.status.archived": "Αρχειοθετημένα", - "mydspace.status.validation": "Επικύρωση", - "mydspace.status.waiting-for-controller": "Αναμονή για τον ελεγκτή", - "mydspace.status.workflow": "Ροή εργασιών", - "mydspace.status.workspace": "Χώρος εργασίας", + "mydspace.status.mydspaceArchived": "Αρχειοθετημένα", + "mydspace.status.mydspaceValidation": "Επικύρωση", + "mydspace.status.mydspaceWaitingController": "Αναμονή για τον ελεγκτή", + "mydspace.status.mydspaceWorkflow": "Ροή εργασιών", + "mydspace.status.mydspaceWorkspace": "Χώρος εργασίας", "mydspace.title": "MyDSpace", "mydspace.upload.upload-failed": "Σφάλμα κατά τη δημιουργία νέου χώρου εργασίας. Επαληθεύστε το περιεχόμενο που ανεβάσατε πριν δοκιμάσετε ξανά.", "mydspace.upload.upload-failed-manyentries": "Μη επεξεργάσιμο αρχείο. Εντοπίστηκαν πάρα πολλές καταχωρίσεις, αλλά επιτρέπεται μόνο μία για αρχείο.", diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..5c17fc8e426 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3812,6 +3812,16 @@ "search.filters.discoverable.false": "Yes", + "search.filters.namedresourcetype.Archived": "Archived", + + "search.filters.namedresourcetype.Validation": "Validation", + + "search.filters.namedresourcetype.Waiting for Controller": "Waiting for Controller", + + "search.filters.namedresourcetype.Workflow": "Workflow", + + "search.filters.namedresourcetype.Workspace": "Workspace", + "search.filters.withdrawn.true": "Yes", "search.filters.withdrawn.false": "No", diff --git a/src/assets/i18n/es.json5 b/src/assets/i18n/es.json5 index 7a2f2fa3db9..5a0e40af42b 100644 --- a/src/assets/i18n/es.json5 +++ b/src/assets/i18n/es.json5 @@ -4560,20 +4560,20 @@ // "mydspace.show.supervisedWorkspace": "Supervised items", "mydspace.show.supervisedWorkspace": "Ítems supervisados", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Archivado", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Archivado", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validación", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validación", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Esperando al controlador", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Esperando al controlador", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Flujo de trabajo", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Flujo de trabajo", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Espacio de trabajo", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Espacio de trabajo", // "mydspace.title": "MyDSpace", "mydspace.title": "Mi DSpace", diff --git a/src/assets/i18n/fi.json5 b/src/assets/i18n/fi.json5 index 62e7e6bffe2..4c6116276e3 100644 --- a/src/assets/i18n/fi.json5 +++ b/src/assets/i18n/fi.json5 @@ -3261,20 +3261,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Tallennuksesi", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arkistoitu", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arkistoitu", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Tarkastaminen", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Tarkastaminen", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Odotetaan tarkastajaa", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Odotetaan tarkastajaa", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Työnkulku", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Työnkulku", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Työtila", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Työtila", // "mydspace.title": "MyDSpace", "mydspace.title": "Oma DSpace", diff --git a/src/assets/i18n/fr.json5 b/src/assets/i18n/fr.json5 index 8ee4dc7d224..699ca5cc27b 100644 --- a/src/assets/i18n/fr.json5 +++ b/src/assets/i18n/fr.json5 @@ -3822,20 +3822,20 @@ //"mydspace.show.supervisedWorkspace": "Supervised items", "mydspace.show.supervisedWorkspace": "Items supervisés", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Archivés", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Archivés", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "En cours de validation", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "En cours de validation", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "En attente d'assignation", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "En attente d'assignation", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "En traitement", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "En traitement", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Dépôts en cours", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Dépôts en cours", // "mydspace.title": "MyDSpace", "mydspace.title": "Mon compte DSpace", diff --git a/src/assets/i18n/gd.json5 b/src/assets/i18n/gd.json5 index 6096073d56e..55a53bc6f1b 100644 --- a/src/assets/i18n/gd.json5 +++ b/src/assets/i18n/gd.json5 @@ -3867,20 +3867,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Do Chur-a-steachan", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "San Tasglann", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "San Tasglann", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Dearbhadh", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Dearbhadh", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "A' feitheamh riaghladair", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "A' feitheamh riaghladair", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Sruth-obrach", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Sruth-obrach", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Raon-obrach", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Raon-obrach", // "mydspace.title": "MyDSpace", "mydspace.title": "MoDSpace", diff --git a/src/assets/i18n/hi.json5 b/src/assets/i18n/hi.json5 index 53fc106187c..68eb6c1f127 100644 --- a/src/assets/i18n/hi.json5 +++ b/src/assets/i18n/hi.json5 @@ -2677,15 +2677,15 @@ "mydspace.show.workspace": "आपकी प्रस्तुतियां", - "mydspace.status.archived": "संग्रहीत", + "mydspace.status.mydspaceArchived": "संग्रहीत", - "mydspace.status.validation": "सत्यापन", + "mydspace.status.mydspaceValidation": "सत्यापन", - "mydspace.status.waiting-for-controller": "नियंत्रक की प्रतीक्षा कर रहा है", + "mydspace.status.mydspaceWaitingController": "नियंत्रक की प्रतीक्षा कर रहा है", - "mydspace.status.workflow": "कार्यप्रवाह", + "mydspace.status.mydspaceWorkflow": "कार्यप्रवाह", - "mydspace.status.workspace": "कार्यस्थान", + "mydspace.status.mydspaceWorkspace": "कार्यस्थान", "mydspace.title": "मेरा डीस्पेस", diff --git a/src/assets/i18n/hu.json5 b/src/assets/i18n/hu.json5 index 373d73aec53..e1076c75122 100644 --- a/src/assets/i18n/hu.json5 +++ b/src/assets/i18n/hu.json5 @@ -4983,20 +4983,20 @@ // TODO New key - Add a translation "mydspace.show.supervisedWorkspace": "Supervised items", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Tárolva", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Tárolva", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Érvényesítés", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Érvényesítés", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Várakozás a kontrollerre", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Várakozás a kontrollerre", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Munkafolyamat", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Munkafolyamat", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Munkafelület", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Munkafelület", // "mydspace.title": "MyDSpace", "mydspace.title": "MyDSpace", diff --git a/src/assets/i18n/it.json5 b/src/assets/i18n/it.json5 index 4131d0bee66..1a97eca501e 100644 --- a/src/assets/i18n/it.json5 +++ b/src/assets/i18n/it.json5 @@ -4813,20 +4813,20 @@ // TODO New key - Add a translation "mydspace.show.supervisedWorkspace": "Supervised items", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Archiviati", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Archiviati", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Convalida", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Convalida", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "In attesa del controllo", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "In attesa del controllo", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", "mydspace.title": "MyDSpace", diff --git a/src/assets/i18n/ja.json5 b/src/assets/i18n/ja.json5 index 94dfc9aa98a..da2385fd62f 100644 --- a/src/assets/i18n/ja.json5 +++ b/src/assets/i18n/ja.json5 @@ -4276,25 +4276,25 @@ // TODO New key - Add a translation "mydspace.show.workspace": "Your Submissions", - // "mydspace.status.archived": "Archived", + // "mydspace.status.mydspaceArchived": "Archived", // TODO New key - Add a translation - "mydspace.status.archived": "Archived", + "mydspace.status.mydspaceArchived": "Archived", - // "mydspace.status.validation": "Validation", + // "mydspace.status.mydspaceValidation": "Validation", // TODO New key - Add a translation - "mydspace.status.validation": "Validation", + "mydspace.status.mydspaceValidation": "Validation", - // "mydspace.status.waiting-for-controller": "Waiting for controller", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", // TODO New key - Add a translation - "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Waiting for controller", - // "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", // TODO New key - Add a translation - "mydspace.status.workflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", // TODO New key - Add a translation - "mydspace.status.workspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", // TODO New key - Add a translation diff --git a/src/assets/i18n/kk.json5 b/src/assets/i18n/kk.json5 index 354eb1104a1..d23dc23c475 100644 --- a/src/assets/i18n/kk.json5 +++ b/src/assets/i18n/kk.json5 @@ -4139,20 +4139,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Сіздің өтініштеріңіз", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Мұрағатталған", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Мұрағатталған", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Валидация", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Валидация", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Контроллерді күтуде", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Контроллерді күтуде", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Жұмыс барысы", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Жұмыс барысы", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Жұмыс кеңістігі", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Жұмыс кеңістігі", // "mydspace.title": "MyDSpace", "mydspace.title": "MyDSpace", diff --git a/src/assets/i18n/lv.json5 b/src/assets/i18n/lv.json5 index 9b4058a3e66..81e2383a1f8 100644 --- a/src/assets/i18n/lv.json5 +++ b/src/assets/i18n/lv.json5 @@ -3492,20 +3492,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Jūsu Iesniegumi", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arhivēts", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arhivēts", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validācija", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validācija", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Gaida kontrolieri", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Gaida kontrolieri", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Darba plūsma", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Darba plūsma", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Darbavieta", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Darbavieta", // "mydspace.title": "MyDSpace", "mydspace.title": "Mans DSpace", diff --git a/src/assets/i18n/nl.json5 b/src/assets/i18n/nl.json5 index 520a8ca427d..280a87b96fe 100644 --- a/src/assets/i18n/nl.json5 +++ b/src/assets/i18n/nl.json5 @@ -3764,20 +3764,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Uw Submissions", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Opgeslagen", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Opgeslagen", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validatie", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validatie", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Wachten op controlleur", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Wachten op controlleur", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", "mydspace.title": "MyDSpace", diff --git a/src/assets/i18n/pl.json5 b/src/assets/i18n/pl.json5 index d748b94888c..35126537055 100644 --- a/src/assets/i18n/pl.json5 +++ b/src/assets/i18n/pl.json5 @@ -1207,11 +1207,11 @@ "mydspace.search-form.placeholder": "Wyszukaj w mydspace...", "mydspace.show.workflow": "Wszystkie zadania", "mydspace.show.workspace": "Twoje zadania", - "mydspace.status.archived": "Zarchiwizowano", - "mydspace.status.validation": "Walidacja", - "mydspace.status.waiting-for-controller": "Oczekiwanie na redaktora", - "mydspace.status.workflow": "Workflow", - "mydspace.status.workspace": "Wersja robocza", + "mydspace.status.mydspaceArchived": "Zarchiwizowano", + "mydspace.status.mydspaceValidation": "Walidacja", + "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redaktora", + "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkspace": "Wersja robocza", "mydspace.title": "Mój DSpace", "mydspace.upload.upload-failed": "Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", "mydspace.upload.upload-failed-manyentries": "Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", diff --git a/src/assets/i18n/pt-BR.json5 b/src/assets/i18n/pt-BR.json5 index 25f1e0fb7c9..5d852129bc3 100644 --- a/src/assets/i18n/pt-BR.json5 +++ b/src/assets/i18n/pt-BR.json5 @@ -3972,20 +3972,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Minhas Submissões", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arquivado", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arquivado", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validação", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validação", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Esperando pelo controlador", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Esperando pelo controlador", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Fluxo de trabalho", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Fluxo de trabalho", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Espaço de trabalho", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Espaço de trabalho", // "mydspace.title": "MyDSpace", "mydspace.title": "MeuDSpace", diff --git a/src/assets/i18n/pt-PT.json5 b/src/assets/i18n/pt-PT.json5 index a187ff927c0..622f8cc48b3 100644 --- a/src/assets/i18n/pt-PT.json5 +++ b/src/assets/i18n/pt-PT.json5 @@ -7713,20 +7713,20 @@ // "browse.metadata.srsc": "Subject Category", "browse.metadata.srsc": "vocabulário controlado (SRSC)", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Depositado", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Depositado", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Em validação", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Em validação", - // "mydspace.status.waiting-for-controller": "Waiting for Controller", - "mydspace.status.waiting-for-controller": "Aguarda validador", + // "mydspace.status.mydspaceWaitingController": "Waiting for Controller", + "mydspace.status.mydspaceWaitingController": "Aguarda validador", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Em fluxo de trabalho", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Em fluxo de trabalho", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Depósito por terminar", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Depósito por terminar", // "search.filters.namedresourcetype.Archived": "Archived", "search.filters.namedresourcetype.Archived": "Depositado", diff --git a/src/assets/i18n/sv.json5 b/src/assets/i18n/sv.json5 index c988577c920..4e3576ccfc0 100644 --- a/src/assets/i18n/sv.json5 +++ b/src/assets/i18n/sv.json5 @@ -3934,20 +3934,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Dina registreringar", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "I arkivet", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "I arkivet", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Validering", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validering", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Väntar på kontrollant", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Väntar på kontrollant", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Arbetsflöde", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Arbetsflöde", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "I arbetsflödet", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "I arbetsflödet", // "mydspace.title": "MyDSpace", "mydspace.title": "Mitt DSpace", diff --git a/src/assets/i18n/sw.json5 b/src/assets/i18n/sw.json5 index 47253dea9f8..a470ee4b587 100644 --- a/src/assets/i18n/sw.json5 +++ b/src/assets/i18n/sw.json5 @@ -4276,25 +4276,25 @@ // TODO New key - Add a translation "mydspace.show.workspace": "Your Submissions", - // "mydspace.status.archived": "Archived", + // "mydspace.status.mydspaceArchived": "Archived", // TODO New key - Add a translation - "mydspace.status.archived": "Archived", + "mydspace.status.mydspaceArchived": "Archived", - // "mydspace.status.validation": "Validation", + // "mydspace.status.mydspaceValidation": "Validation", // TODO New key - Add a translation - "mydspace.status.validation": "Validation", + "mydspace.status.mydspaceValidation": "Validation", - // "mydspace.status.waiting-for-controller": "Waiting for controller", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", // TODO New key - Add a translation - "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Waiting for controller", - // "mydspace.status.workflow": "Workflow", + // "mydspace.status.mydspaceWorkflow": "Workflow", // TODO New key - Add a translation - "mydspace.status.workflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Workflow", - // "mydspace.status.workspace": "Workspace", + // "mydspace.status.mydspaceWorkspace": "Workspace", // TODO New key - Add a translation - "mydspace.status.workspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Workspace", // "mydspace.title": "MyDSpace", // TODO New key - Add a translation diff --git a/src/assets/i18n/tr.json5 b/src/assets/i18n/tr.json5 index e9869e00196..153eaa1281a 100644 --- a/src/assets/i18n/tr.json5 +++ b/src/assets/i18n/tr.json5 @@ -3257,20 +3257,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Gönderimleriniz", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arşivlendi", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arşivlendi", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Doğrulama", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Doğrulama", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Kontrolör bekleniyor", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Kontrolör bekleniyor", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "İş akışı", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "İş akışı", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Çalışma alanı", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Çalışma alanı", // "mydspace.title": "MyDSpace", "mydspace.title": "MyDSpace", diff --git a/src/assets/i18n/uk.json5 b/src/assets/i18n/uk.json5 index 5cbb480179e..7df55fa2369 100644 --- a/src/assets/i18n/uk.json5 +++ b/src/assets/i18n/uk.json5 @@ -3383,20 +3383,20 @@ // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Ваші надіслані документи ", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Заархівовані", + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Заархівовані", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Перевірка", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Перевірка", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Чекаємо контролера", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Чекаємо контролера", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Робочий процес", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Робочий процес", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Робоче середовище", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Робоче середовище", // "mydspace.title": "MyDSpace", "mydspace.title": "Моє середовище", diff --git a/src/assets/i18n/vi.json5 b/src/assets/i18n/vi.json5 index 7627818978f..f254df34fed 100644 --- a/src/assets/i18n/vi.json5 +++ b/src/assets/i18n/vi.json5 @@ -1449,11 +1449,11 @@ "mydspace.search-form.placeholder": "Tìm kiếm trong trang cá nhân của tôi...", "mydspace.show.workflow": "Tất cả nhiệm vụ", "mydspace.show.workspace": "Tài liệu của tôi", - "mydspace.status.archived": "Đã lưu trữ", - "mydspace.status.validation": "Đang kiểm tra", - "mydspace.status.waiting-for-controller": "Đợi nhận nhiệm vụ", - "mydspace.status.workflow": "Đang kiểm duyệt", - "mydspace.status.workspace": "Đang biên mục", + "mydspace.status.mydspaceArchived": "Đã lưu trữ", + "mydspace.status.mydspaceValidation": "Đang kiểm tra", + "mydspace.status.mydspaceWaitingController": "Đợi nhận nhiệm vụ", + "mydspace.status.mydspaceWorkflow": "Đang kiểm duyệt", + "mydspace.status.mydspaceWorkspace": "Đang biên mục", "mydspace.title": "Trang cá nhân", "mydspace.upload.upload-failed": "Có lỗi xảy ra khi tạo tài liệu mới. Vui lòng xác minh nội dung đã tải lên trước khi thử lại.", "mydspace.upload.upload-failed-manyentries": "Không thể xử lý tệp tin. Có quá nhiều mục trong khi hệ thống chỉ cho phép một mục trong tệp tin.", From 2a35180a1b2c81ca84e3fe7d9c4a84567f567a6a Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 21 Jul 2023 15:03:46 +0200 Subject: [PATCH 052/282] 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 @@ <div class="d-flex justify-content-between border-bottom mb-3"> <h2 id="header" class="pb-2">{{labelPrefix + 'head' | translate}}</h2> - <div *ngIf="!isEPersonFormShown"> + <div> <button class="mr-auto btn btn-success addEPerson-button" - (click)="isEPersonFormShown = true"> + [routerLink]="'create'"> <i class="fas fa-plus"></i> <span class="d-none d-sm-inline ml-1">{{labelPrefix + 'button.add' | translate}}</span> </button> </div> </div> - <ds-eperson-form *ngIf="isEPersonFormShown" (submitForm)="reset()" - (cancelForm)="isEPersonFormShown = false"></ds-eperson-form> + <h3 id="search" class="border-bottom pb-2">{{labelPrefix + 'search.head' | translate}} - <div *ngIf="!isEPersonFormShown"> - <h3 id="search" class="border-bottom pb-2">{{labelPrefix + 'search.head' | translate}} - - </h3> - <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> - <div> - <select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope"> - <option value="metadata">{{labelPrefix + 'search.scope.metadata' | translate}}</option> - <option value="email">{{labelPrefix + 'search.scope.email' | translate}}</option> - </select> - </div> - <div class="flex-grow-1 mr-3 ml-3"> - <div class="form-group input-group"> - <input type="text" name="query" id="query" formControlName="query" - class="form-control" [attr.aria-label]="labelPrefix + 'search.placeholder' | translate" - [placeholder]="(labelPrefix + 'search.placeholder' | translate)"> - <span class="input-group-append"> + </h3> + <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> + <div> + <select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope"> + <option value="metadata">{{labelPrefix + 'search.scope.metadata' | translate}}</option> + <option value="email">{{labelPrefix + 'search.scope.email' | translate}}</option> + </select> + </div> + <div class="flex-grow-1 mr-3 ml-3"> + <div class="form-group input-group"> + <input type="text" name="query" id="query" formControlName="query" + class="form-control" [attr.aria-label]="labelPrefix + 'search.placeholder' | translate" + [placeholder]="(labelPrefix + 'search.placeholder' | translate)"> + <span class="input-group-append"> <button type="submit" class="search-button btn btn-primary"> <i class="fas fa-search"></i> {{ labelPrefix + 'search.button' | translate }} </button> </span> - </div> </div> - <div> - <button (click)="clearFormAndResetResult();" - class="search-button btn btn-secondary">{{labelPrefix + 'button.see-all' | translate}}</button> - </div> - </form> + </div> + <div> + <button (click)="clearFormAndResetResult();" + class="search-button btn btn-secondary">{{labelPrefix + 'button.see-all' | translate}}</button> + </div> + </form> - <ds-themed-loading *ngIf="searching$ | async"></ds-themed-loading> - <ds-pagination - *ngIf="(pageInfoState$ | async)?.totalElements > 0 && !(searching$ | async)" - [paginationOptions]="config" - [pageInfoState]="pageInfoState$" - [collectionSize]="(pageInfoState$ | async)?.totalElements" - [hideGear]="true" - [hidePagerWhenSinglePage]="true"> + <ds-themed-loading *ngIf="searching$ | async"></ds-themed-loading> + <ds-pagination + *ngIf="(pageInfoState$ | async)?.totalElements > 0 && !(searching$ | async)" + [paginationOptions]="config" + [pageInfoState]="pageInfoState$" + [collectionSize]="(pageInfoState$ | async)?.totalElements" + [hideGear]="true" + [hidePagerWhenSinglePage]="true"> - <div class="table-responsive"> - <table id="epeople" class="table table-striped table-hover table-bordered"> - <thead> - <tr> - <th scope="col">{{labelPrefix + 'table.id' | translate}}</th> - <th scope="col">{{labelPrefix + 'table.name' | translate}}</th> - <th scope="col">{{labelPrefix + 'table.email' | translate}}</th> - <th>{{labelPrefix + 'table.edit' | translate}}</th> - </tr> - </thead> - <tbody> - <tr *ngFor="let epersonDto of (ePeopleDto$ | async)?.page" - [ngClass]="{'table-primary' : isActive(epersonDto.eperson) | async}"> - <td>{{epersonDto.eperson.id}}</td> - <td>{{ dsoNameService.getName(epersonDto.eperson) }}</td> - <td>{{epersonDto.eperson.email}}</td> - <td> - <div class="btn-group edit-field"> - <button (click)="toggleEditEPerson(epersonDto.eperson)" - class="btn btn-outline-primary btn-sm access-control-editEPersonButton" - title="{{labelPrefix + 'table.edit.buttons.edit' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> - <i class="fas fa-edit fa-fw"></i> - </button> - <button [disabled]="!epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)" - class="delete-button btn btn-outline-danger btn-sm access-control-deleteEPersonButton" - title="{{labelPrefix + 'table.edit.buttons.remove' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> - <i class="fas fa-trash-alt fa-fw"></i> - </button> - </div> - </td> - </tr> - </tbody> - </table> - </div> + <div class="table-responsive"> + <table id="epeople" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col">{{labelPrefix + 'table.id' | translate}}</th> + <th scope="col">{{labelPrefix + 'table.name' | translate}}</th> + <th scope="col">{{labelPrefix + 'table.email' | translate}}</th> + <th>{{labelPrefix + 'table.edit' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let epersonDto of (ePeopleDto$ | async)?.page" + [ngClass]="{'table-primary' : isActive(epersonDto.eperson) | async}"> + <td>{{epersonDto.eperson.id}}</td> + <td>{{ dsoNameService.getName(epersonDto.eperson) }}</td> + <td>{{epersonDto.eperson.email}}</td> + <td> + <div class="btn-group edit-field"> + <button [routerLink]="getEditEPeoplePage(epersonDto.eperson.id)" + class="btn btn-outline-primary btn-sm access-control-editEPersonButton" + title="{{labelPrefix + 'table.edit.buttons.edit' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> + <i class="fas fa-edit fa-fw"></i> + </button> + <button [disabled]="!epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)" + class="delete-button btn btn-outline-danger btn-sm access-control-deleteEPersonButton" + title="{{labelPrefix + 'table.edit.buttons.remove' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> + <i class="fas fa-trash-alt fa-fw"></i> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> - </ds-pagination> + </ds-pagination> - <div *ngIf="(pageInfoState$ | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> - {{labelPrefix + 'no-items' | translate}} - </div> + <div *ngIf="(pageInfoState$ | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> + {{labelPrefix + 'no-items' | translate}} </div> </div> </div> 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<EPerson>) => { 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 @@ -<div *ngIf="epersonService.getActiveEPerson() | async; then editheader; else createHeader"></div> +<div class="container"> + <div class="group-form row"> + <div class="col-12"> -<ng-template #createHeader> - <h4>{{messagePrefix + '.create' | translate}}</h4> -</ng-template> + <div *ngIf="epersonService.getActiveEPerson() | async; then editHeader; else createHeader"></div> -<ng-template #editheader> - <h4>{{messagePrefix + '.edit' | translate}}</h4> -</ng-template> + <ng-template #createHeader> + <h2 class="border-bottom pb-2">{{messagePrefix + '.create' | translate}}</h2> + </ng-template> -<ds-form [formId]="formId" - [formModel]="formModel" - [formGroup]="formGroup" - [formLayout]="formLayout" - [displayCancel]="false" - [submitLabel]="submitLabel" - (submitForm)="onSubmit()"> - <div before class="btn-group"> - <button (click)="onCancel()" - class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> - </div> - <div *ngIf="displayResetPassword" between class="btn-group"> - <button class="btn btn-primary" [disabled]="!(canReset$ | async)" (click)="resetPassword()"> - <i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}} - </button> - </div> - <div between class="btn-group ml-1"> - <button *ngIf="!isImpersonated" class="btn btn-primary" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" (click)="impersonate()"> - <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}} - </button> - <button *ngIf="isImpersonated" class="btn btn-primary" (click)="stopImpersonating()"> - <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}} - </button> - </div> - <button after class="btn btn-danger delete-button" [disabled]="!(canDelete$ | async)" (click)="delete()"> - <i class="fas fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}} - </button> -</ds-form> + <ng-template #editHeader> + <h2 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h2> + </ng-template> -<ds-themed-loading [showMessage]="false" *ngIf="!formGroup"></ds-themed-loading> + <ds-form [formId]="formId" + [formModel]="formModel" + [formGroup]="formGroup" + [formLayout]="formLayout" + [displayCancel]="false" + [submitLabel]="submitLabel" + (submitForm)="onSubmit()"> + <div before class="btn-group"> + <button (click)="onCancel()" class="btn btn-outline-secondary"> + <i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}} + </button> + </div> + <div *ngIf="displayResetPassword" between class="btn-group"> + <button class="btn btn-primary" [disabled]="!(canReset$ | async)" (click)="resetPassword()"> + <i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}} + </button> + </div> + <div between class="btn-group ml-1"> + <button *ngIf="!isImpersonated" class="btn btn-primary" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" + (click)="impersonate()"> + <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}} + </button> + <button *ngIf="isImpersonated" class="btn btn-primary" (click)="stopImpersonating()"> + <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}} + </button> + </div> + <button after class="btn btn-danger delete-button" [disabled]="!(canDelete$ | async)" (click)="delete()"> + <i class="fas fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}} + </button> + </ds-form> -<div *ngIf="epersonService.getActiveEPerson() | async"> - <h5>{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}</h5> + <ds-themed-loading [showMessage]="false" *ngIf="!formGroup"></ds-themed-loading> - <ds-themed-loading [showMessage]="false" *ngIf="!(groups | async)"></ds-themed-loading> + <div *ngIf="epersonService.getActiveEPerson() | async"> + <h5>{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}</h5> - <ds-pagination - *ngIf="(groups | async)?.payload?.totalElements > 0" - [paginationOptions]="config" - [pageInfoState]="(groups | async)?.payload" - [collectionSize]="(groups | async)?.payload?.totalElements" - [hideGear]="true" - [hidePagerWhenSinglePage]="true" - (pageChange)="onPageChange($event)"> + <ds-themed-loading [showMessage]="false" *ngIf="!(groups | async)"></ds-themed-loading> - <div class="table-responsive"> - <table id="groups" class="table table-striped table-hover table-bordered"> - <thead> - <tr> - <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.collectionOrCommunity' | translate}}</th> - </tr> - </thead> - <tbody> - <tr *ngFor="let group of (groups | async)?.payload?.page"> - <td class="align-middle">{{group.id}}</td> - <td class="align-middle"> - <a (click)="groupsDataService.startEditingNewGroup(group)" - [routerLink]="[groupsDataService.getGroupEditPageRouterLink(group)]"> - {{ dsoNameService.getName(group) }} - </a> - </td> - <td class="align-middle">{{ dsoNameService.getName(undefined) }}</td> - </tr> - </tbody> - </table> - </div> + <ds-pagination + *ngIf="(groups | async)?.payload?.totalElements > 0" + [paginationOptions]="config" + [pageInfoState]="(groups | async)?.payload" + [collectionSize]="(groups | async)?.payload?.totalElements" + [hideGear]="true" + [hidePagerWhenSinglePage]="true" + (pageChange)="onPageChange($event)"> + + <div class="table-responsive"> + <table id="groups" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.collectionOrCommunity' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let group of (groups | async)?.payload?.page"> + <td class="align-middle">{{group.id}}</td> + <td class="align-middle"> + <a (click)="groupsDataService.startEditingNewGroup(group)" + [routerLink]="[groupsDataService.getGroupEditPageRouterLink(group)]"> + {{ dsoNameService.getName(group) }} + </a> + </td> + <td class="align-middle">{{ dsoNameService.getName(undefined) }}</td> + </tr> + </tbody> + </table> + </div> - </ds-pagination> + </ds-pagination> - <div *ngIf="(groups | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> - <div>{{messagePrefix + '.memberOfNoGroups' | translate}}</div> - <div> - <button [routerLink]="[groupsDataService.getGroupRegistryRouterLink()]" - class="btn btn-primary">{{messagePrefix + '.goToGroups' | translate}}</button> + <div *ngIf="(groups | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> + <div>{{messagePrefix + '.memberOfNoGroups' | translate}}</div> + <div> + <button [routerLink]="[groupsDataService.getGroupRegistryRouterLink()]" + class="btn btn-primary">{{messagePrefix + '.goToGroups' | translate}}</button> + </div> + </div> + </div> </div> </div> </div> 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<RemoteData<EPerson>> { return createSuccessfulRemoteDataObject$(null); + }, + findById(_id: string, _useCachedVersionIfAvailable = true, _reRequestOnStale = true, ..._linksToFollow: FollowLinkConfig<EPerson>[]): Observable<RemoteData<EPerson>> { + 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<EPerson>) => { + 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<NoContent> | 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<EPerson>[] = [ + 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<RemoteData<EPerson>> { + + constructor( + protected ePersonService: EPersonDataService, + protected store: Store<any>, + ) { + } + + /** + * 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<<RemoteData<EPerson>>` 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<RemoteData<EPerson>> { + const ePersonRD$: Observable<RemoteData<EPerson>> = this.ePersonService.findById(route.params.id, + true, + false, + ...EPERSON_EDIT_FOLLOW_LINKS, + ).pipe( + getFirstCompletedRemoteData(), + ); + + ePersonRD$.subscribe((ePersonRD: RemoteData<EPerson>) => { + 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 <alexandre@atmire.com> Date: Fri, 21 Jul 2023 15:11:01 +0200 Subject: [PATCH 053/282] 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 @@ <div class="group-form row"> <div class="col-12"> - <div *ngIf="groupDataService.getActiveGroup() | async; then editheader; else createHeader"></div> + <div *ngIf="groupDataService.getActiveGroup() | async; then editHeader; else createHeader"></div> <ng-template #createHeader> <h2 class="border-bottom pb-2">{{messagePrefix + '.head.create' | translate}}</h2> </ng-template> - <ng-template #editheader> + <ng-template #editHeader> <h2 class="border-bottom pb-2"> <span *dsContextHelp="{ diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts index 3c0547cca50..528409296a3 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/access-control/group-registry/group-form/group-form.component.ts @@ -10,7 +10,6 @@ import { } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import { - ObservedValueOf, combineLatest as observableCombineLatest, Observable, of as observableOf, @@ -48,6 +47,7 @@ import { Operation } from 'fast-json-patch'; import { ValidateGroupExists } from './validators/group-exists.validator'; import { DSONameService } from '../../../core/breadcrumbs/dso-name.service'; import { environment } from '../../../../environments/environment'; +import { getGroupEditRoute, getGroupsRoute } from '../../access-control-routing-paths'; @Component({ selector: 'ds-group-form', @@ -165,19 +165,19 @@ export class GroupFormComponent implements OnInit, OnDestroy { this.canEdit$ = this.groupDataService.getActiveGroup().pipe( hasValueOperator(), switchMap((group: Group) => { - return observableCombineLatest( + return observableCombineLatest([ this.authorizationService.isAuthorized(FeatureID.CanDelete, isNotEmpty(group) ? group.self : undefined), this.hasLinkedDSO(group), - (isAuthorized: ObservedValueOf<Observable<boolean>>, hasLinkedDSO: ObservedValueOf<Observable<boolean>>) => { - return isAuthorized && !hasLinkedDSO; - }); - }) + ]).pipe( + map(([isAuthorized, hasLinkedDSO]: [boolean, boolean]) => isAuthorized && !hasLinkedDSO), + ); + }), ); - observableCombineLatest( + observableCombineLatest([ this.translateService.get(`${this.messagePrefix}.groupName`), this.translateService.get(`${this.messagePrefix}.groupCommunity`), this.translateService.get(`${this.messagePrefix}.groupDescription`) - ).subscribe(([groupName, groupCommunity, groupDescription]) => { + ]).subscribe(([groupName, groupCommunity, groupDescription]) => { this.groupName = new DynamicInputModel({ id: 'groupName', label: groupName, @@ -215,12 +215,12 @@ export class GroupFormComponent implements OnInit, OnDestroy { } this.subs.push( - observableCombineLatest( + observableCombineLatest([ this.groupDataService.getActiveGroup(), this.canEdit$, this.groupDataService.getActiveGroup() .pipe(filter((activeGroup) => hasValue(activeGroup)),switchMap((activeGroup) => this.getLinkedDSO(activeGroup).pipe(getFirstSucceededRemoteDataPayload()))) - ).subscribe(([activeGroup, canEdit, linkedObject]) => { + ]).subscribe(([activeGroup, canEdit, linkedObject]) => { if (activeGroup != null) { @@ -263,7 +263,7 @@ export class GroupFormComponent implements OnInit, OnDestroy { onCancel() { this.groupDataService.cancelEditGroup(); this.cancelForm.emit(); - this.router.navigate([this.groupDataService.getGroupRegistryRouterLink()]); + void this.router.navigate([getGroupsRoute()]); } /** @@ -310,7 +310,7 @@ export class GroupFormComponent implements OnInit, OnDestroy { const groupSelfLink = rd.payload._links.self.href; this.setActiveGroupWithLink(groupSelfLink); this.groupDataService.clearGroupsRequests(); - this.router.navigateByUrl(this.groupDataService.getGroupEditPageRouterLinkWithID(rd.payload.uuid)); + void this.router.navigateByUrl(getGroupEditRoute(rd.payload.uuid)); } } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.created.failure', { name: groupToCreate.name })); diff --git a/src/app/access-control/group-registry/groups-registry.component.html b/src/app/access-control/group-registry/groups-registry.component.html index 828aadc95a4..27cec262c44 100644 --- a/src/app/access-control/group-registry/groups-registry.component.html +++ b/src/app/access-control/group-registry/groups-registry.component.html @@ -5,7 +5,7 @@ <h2 id="header" class="pb-2">{{messagePrefix + 'head' | translate}}</h2> <div> <button class="mr-auto btn btn-success" - [routerLink]="['newGroup']"> + [routerLink]="'create'"> <i class="fas fa-plus"></i> <span class="d-none d-sm-inline ml-1">{{messagePrefix + 'button.add' | translate}}</span> </button> 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<EPerson> 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<Group> 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 <alexandre@atmire.com> Date: Fri, 21 Jul 2023 17:48:27 +0200 Subject: [PATCH 054/282] 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 @@ <h2 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h2> <i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}} </button> </div> - <div between class="btn-group ml-1"> - <button *ngIf="!isImpersonated" class="btn btn-primary" [ngClass]="{'d-none' : !(canImpersonate$ | async)}" - (click)="impersonate()"> + <div *ngIf="canImpersonate$ | async" between class="btn-group"> + <button *ngIf="!isImpersonated" class="btn btn-primary" (click)="impersonate()"> <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.impersonate' | translate}} </button> <button *ngIf="isImpersonated" class="btn btn-primary" (click)="stopImpersonating()"> From 75ec046bba7f2ce3a76ec32f6bd2172894a78ca4 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 21 Jul 2023 17:49:07 +0200 Subject: [PATCH 055/282] Hide the delete EPerson/Group buttons when the user can't delete the EPerson/Group --- .../epeople-registry/epeople-registry.component.html | 2 +- .../eperson-form/eperson-form.component.html | 2 +- .../eperson-form/eperson-form.component.spec.ts | 8 ++++---- .../group-registry/group-form/group-form.component.html | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) 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 f3ddd63ae80..4979f858193 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -73,7 +73,7 @@ <h3 id="search" class="border-bottom pb-2">{{labelPrefix + 'search.head' | trans title="{{labelPrefix + 'table.edit.buttons.edit' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> <i class="fas fa-edit fa-fw"></i> </button> - <button [disabled]="!epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)" + <button *ngIf="epersonDto.ableToDelete" (click)="deleteEPerson(epersonDto.eperson)" class="delete-button btn btn-outline-danger btn-sm access-control-deleteEPersonButton" title="{{labelPrefix + 'table.edit.buttons.remove' | translate: { name: dsoNameService.getName(epersonDto.eperson) } }}"> <i class="fas fa-trash-alt fa-fw"></i> 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 88c4f99870d..fb65c916495 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 @@ -37,7 +37,7 @@ <h2 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h2> <i class="fa fa-user-secret"></i> {{'admin.access-control.epeople.actions.stop-impersonating' | translate}} </button> </div> - <button after class="btn btn-danger delete-button" [disabled]="!(canDelete$ | async)" (click)="delete()"> + <button *ngIf="canDelete$ | async" after class="btn btn-danger delete-button" (click)="delete()"> <i class="fas fa-trash"></i> {{'admin.access-control.epeople.actions.delete' | translate}} </button> </ds-form> 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 @@ <h2 class="border-bottom pb-2"> <button (click)="onCancel()" class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> </div> - <div after *ngIf="groupBeingEdited != null" class="btn-group"> + <div after *ngIf="(canEdit$ | async) && !groupBeingEdited.permanent" class="btn-group"> <button class="btn btn-danger delete-button" [disabled]="!(canEdit$ | async) || groupBeingEdited.permanent" (click)="delete()"> <i class="fa fa-trash"></i> {{ messagePrefix + '.actions.delete' | translate}} From 15656b03ce743461dadc5d093f5347a57f50fa61 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 21 Jul 2023 23:18:40 +0200 Subject: [PATCH 056/282] Fix mathjax code being displayed twice This was due to sanitizeHtml rendering the mjx-assistive-mml tag as text. This tag is used by screen readers and therefor we should allow it to be rendered --- src/app/shared/utils/markdown.pipe.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/app/shared/utils/markdown.pipe.ts b/src/app/shared/utils/markdown.pipe.ts index e494a826138..90b6d25731a 100644 --- a/src/app/shared/utils/markdown.pipe.ts +++ b/src/app/shared/utils/markdown.pipe.ts @@ -67,7 +67,9 @@ export class MarkdownPipe implements PipeTransform { // sanitize-html doesn't let through SVG by default, so we extend its allowlists to cover MathJax SVG allowedTags: [ ...sanitizeHtml.defaults.allowedTags, - 'mjx-container', 'svg', 'g', 'path', 'rect', 'text' + 'mjx-container', 'svg', 'g', 'path', 'rect', 'text', + // Also let the mjx-assistive-mml tag (and it's children) through (for screen readers) + 'mjx-assistive-mml', 'math', 'mrow', 'mi', ], allowedAttributes: { ...sanitizeHtml.defaults.allowedAttributes, @@ -88,7 +90,16 @@ export class MarkdownPipe implements PipeTransform { ], text: [ 'transform', 'font-size' - ] + ], + 'mjx-assistive-mml': [ + 'unselectable', 'display', 'style', + ], + math: [ + 'xmlns', + ], + mrow: [ + 'data-mjx-texclass', + ], }, parser: { lowerCaseAttributeNames: false, From 08ae7bfdbad027c0888624fdbebb1a90704a8112 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Mon, 24 Jul 2023 16:10:23 -0500 Subject: [PATCH 057/282] Replace all old docker "dspace-7_x" tags with latest --- Dockerfile.dist | 2 +- docker/README.md | 6 +++--- docker/cli.yml | 2 +- docker/docker-compose-ci.yml | 2 +- docker/docker-compose-dist.yml | 2 +- docker/docker-compose-rest.yml | 4 ++-- docker/docker-compose.yml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Dockerfile.dist b/Dockerfile.dist index 2a6a66fc063..e4b467ae26c 100644 --- a/Dockerfile.dist +++ b/Dockerfile.dist @@ -2,7 +2,7 @@ # See https://github.com/DSpace/dspace-angular/tree/main/docker for usage details # Test build: -# docker build -f Dockerfile.dist -t dspace/dspace-angular:dspace-7_x-dist . +# docker build -f Dockerfile.dist -t dspace/dspace-angular:latest-dist . FROM node:18-alpine as build diff --git a/docker/README.md b/docker/README.md index 42deb793f91..08801137b07 100644 --- a/docker/README.md +++ b/docker/README.md @@ -23,14 +23,14 @@ the Docker compose scripts in this 'docker' folder. This Dockerfile is used to build a *development* DSpace 7 Angular UI image, published as 'dspace/dspace-angular' ``` -docker build -t dspace/dspace-angular:dspace-7_x . +docker build -t dspace/dspace-angular:latest . ``` This image is built *automatically* after each commit is made to the `main` branch. Admins to our DockerHub repo can manually publish with the following command. ``` -docker push dspace/dspace-angular:dspace-7_x +docker push dspace/dspace-angular:latest ``` ### Dockerfile.dist @@ -39,7 +39,7 @@ The `Dockerfile.dist` is used to generate a *production* build and runtime envir ```bash # build the latest image -docker build -f Dockerfile.dist -t dspace/dspace-angular:dspace-7_x-dist . +docker build -f Dockerfile.dist -t dspace/dspace-angular:latest-dist . ``` A default/demo version of this image is built *automatically*. diff --git a/docker/cli.yml b/docker/cli.yml index 54b83d45036..223ec356b9c 100644 --- a/docker/cli.yml +++ b/docker/cli.yml @@ -16,7 +16,7 @@ version: "3.7" services: dspace-cli: - image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}" + image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-latest}" container_name: dspace-cli environment: # Below syntax may look odd, but it is how to override dspace.cfg settings via env variables. diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index 9ec8fe664a3..edbb5b07598 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -35,7 +35,7 @@ services: solr__D__statistics__P__autoCommit: 'false' depends_on: - dspacedb - image: dspace/dspace:dspace-7_x-test + image: dspace/dspace:latest-test networks: dspacenet: ports: diff --git a/docker/docker-compose-dist.yml b/docker/docker-compose-dist.yml index 1c75539da97..a9ee4a2656c 100644 --- a/docker/docker-compose-dist.yml +++ b/docker/docker-compose-dist.yml @@ -27,7 +27,7 @@ services: DSPACE_REST_HOST: api7.dspace.org DSPACE_REST_PORT: 443 DSPACE_REST_NAMESPACE: /server - image: dspace/dspace-angular:dspace-7_x-dist + image: dspace/dspace-angular:${DSPACE_VER:-latest}-dist build: context: .. dockerfile: Dockerfile.dist diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml index e5f62600e70..ea766600efa 100644 --- a/docker/docker-compose-rest.yml +++ b/docker/docker-compose-rest.yml @@ -39,7 +39,7 @@ services: # proxies.trusted.ipranges: This setting is required for a REST API running in Docker to trust requests # from the host machine. This IP range MUST correspond to the 'dspacenet' subnet defined above. proxies__P__trusted__P__ipranges: '172.23.0' - image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-7_x-test}" + image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-latest-test}" depends_on: - dspacedb networks: @@ -82,7 +82,7 @@ services: # DSpace Solr container dspacesolr: container_name: dspacesolr - image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-dspace-7_x}" + image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-latest}" # Needs main 'dspace' container to start first to guarantee access to solr_configs depends_on: - dspace diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 1387b1de396..1071b8d6ce2 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -24,7 +24,7 @@ services: DSPACE_REST_HOST: localhost DSPACE_REST_PORT: 8080 DSPACE_REST_NAMESPACE: /server - image: dspace/dspace-angular:dspace-7_x + image: dspace/dspace-angular:${DSPACE_VER:-latest} build: context: .. dockerfile: Dockerfile From 873a8e16a362794eab85d09afa73c9f6c787c169 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 24 Jul 2023 23:42:55 +0200 Subject: [PATCH 058/282] 101577: Ensure the component is always destroyed before rendering the new component --- src/app/shared/theme-support/themed.component.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/shared/theme-support/themed.component.ts b/src/app/shared/theme-support/themed.component.ts index 1df7f77f08a..d67efcb5bdc 100644 --- a/src/app/shared/theme-support/themed.component.ts +++ b/src/app/shared/theme-support/themed.component.ts @@ -60,7 +60,6 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges } ngOnInit(): void { - this.destroyComponentInstance(); this.initComponentInstance(); } @@ -81,8 +80,6 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges } if (hasNoValue(this.lazyLoadObs)) { - this.destroyComponentInstance(); - this.lazyLoadObs = combineLatest([ observableOf(changes), this.resolveThemedComponent(this.themeService.getThemeName()).pipe( @@ -104,6 +101,7 @@ export abstract class ThemedComponent<T> implements OnInit, OnDestroy, OnChanges } this.lazyLoadSub = this.lazyLoadObs.subscribe(([simpleChanges, constructor]: [SimpleChanges, GenericConstructor<T>]) => { + this.destroyComponentInstance(); const factory = this.resolver.resolveComponentFactory(constructor); this.compRef = this.vcr.createComponent(factory); if (hasValue(simpleChanges)) { From 5062e464337f08031b25b132cbf865a7c38dbfe1 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 19 Jul 2023 15:35:38 +0200 Subject: [PATCH 059/282] 104312: Add missing query @Input() to ThemedDynamicLookupRelationExternalSourceTabComponent --- ...d-dynamic-lookup-relation-external-source-tab.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts index 637941ce5bf..113d902c3d8 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts @@ -15,7 +15,7 @@ import { DsDynamicLookupRelationExternalSourceTabComponent } from './dynamic-loo }) export class ThemedDynamicLookupRelationExternalSourceTabComponent extends ThemedComponent<DsDynamicLookupRelationExternalSourceTabComponent> { protected inAndOutputNames: (keyof DsDynamicLookupRelationExternalSourceTabComponent & keyof this)[] = ['label', 'listId', - 'item', 'collection', 'relationship', 'context', 'repeatable', 'importedObject', 'externalSource']; + 'item', 'collection', 'relationship', 'context', 'query', 'repeatable', 'importedObject', 'externalSource']; @Input() label: string; @@ -29,6 +29,8 @@ export class ThemedDynamicLookupRelationExternalSourceTabComponent extends Theme @Input() context: Context; + @Input() query: string; + @Input() repeatable: boolean; @Output() importedObject: EventEmitter<ListableObject> = new EventEmitter(); From 0ec72f679bb8d1bb7611c1de2125f92cb718b1a9 Mon Sep 17 00:00:00 2001 From: Mirko Scherf <mscherf@uni-mainz.de> Date: Wed, 26 Jul 2023 13:04:04 +0200 Subject: [PATCH 060/282] fix(i18m): curation-task.task.registerdoi.label changed curation-task.task.register-doi.label back to curation-task.task.registerdoi.label and added German translation --- src/assets/i18n/de.json5 | 3 ++- src/assets/i18n/en.json5 | 2 +- src/assets/i18n/es.json5 | 4 ++-- src/assets/i18n/hu.json5 | 4 ++-- src/assets/i18n/it.json5 | 4 ++-- src/assets/i18n/pt-PT.json5 | 4 ++-- src/assets/i18n/vi.json5 | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index b03dc21e5a5..7fedf4c85e9 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -1712,7 +1712,8 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Virenscan", - + // "curation-task.task.registerdoi.label": "Register DOI", + "curation-task.task.registerdoi.label": "DOI registrieren", // "curation.form.task-select.label": "Task:", "curation.form.task-select.label": "Aufgabe:", diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..165e56f4947 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1392,7 +1392,7 @@ "curation-task.task.vscan.label": "Virus Scan", - "curation-task.task.register-doi.label": "Register DOI", + "curation-task.task.registerdoi.label": "Register DOI", "curation.form.task-select.label": "Task:", diff --git a/src/assets/i18n/es.json5 b/src/assets/i18n/es.json5 index 7a2f2fa3db9..b03b202beb5 100644 --- a/src/assets/i18n/es.json5 +++ b/src/assets/i18n/es.json5 @@ -2080,8 +2080,8 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Búsqueda de virus", - // "curation-task.task.register-doi.label": "Register DOI", - "curation-task.task.register-doi.label": "Registro DOI", + // "curation-task.task.registerdoi.label": "Register DOI", + "curation-task.task.registerdoi.label": "Registro DOI", diff --git a/src/assets/i18n/hu.json5 b/src/assets/i18n/hu.json5 index 373d73aec53..31bb701ee93 100644 --- a/src/assets/i18n/hu.json5 +++ b/src/assets/i18n/hu.json5 @@ -2228,9 +2228,9 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Virus ellenőrzés", - // "curation-task.task.register-doi.label": "Register DOI", + // "curation-task.task.registerdoi.label": "Register DOI", // TODO New key - Add a translation - "curation-task.task.register-doi.label": "Register DOI", + "curation-task.task.registerdoi.label": "Register DOI", diff --git a/src/assets/i18n/it.json5 b/src/assets/i18n/it.json5 index 4131d0bee66..0e554375a11 100644 --- a/src/assets/i18n/it.json5 +++ b/src/assets/i18n/it.json5 @@ -2160,9 +2160,9 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Scansione antivirus", - // "curation-task.task.register-doi.label": "Register DOI", + // "curation-task.task.registerdoi.label": "Register DOI", // TODO New key - Add a translation - "curation-task.task.register-doi.label": "Register DOI", + "curation-task.task.registerdoi.label": "Register DOI", diff --git a/src/assets/i18n/pt-PT.json5 b/src/assets/i18n/pt-PT.json5 index a187ff927c0..773cb5c3b7c 100644 --- a/src/assets/i18n/pt-PT.json5 +++ b/src/assets/i18n/pt-PT.json5 @@ -2054,8 +2054,8 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Scan de vírus", - // "curation-task.task.register-doi.label": "Register DOI", - "curation-task.task.register-doi.label": "Registo DOI", + // "curation-task.task.registerdoi.label": "Register DOI", + "curation-task.task.registerdoi.label": "Registo DOI", // "curation.form.task-select.label": "Task:", "curation.form.task-select.label": "Tarefa:", diff --git a/src/assets/i18n/vi.json5 b/src/assets/i18n/vi.json5 index 7627818978f..2b90ee7ecf2 100644 --- a/src/assets/i18n/vi.json5 +++ b/src/assets/i18n/vi.json5 @@ -671,7 +671,7 @@ "curation-task.task.citationpage.label": "Tạo trang trích dẫn", "curation-task.task.noop.label": "NOOP", "curation-task.task.profileformats.label": "Định dạng tệp tin", - "curation-task.task.register-doi.label": "Đăng ký DOI", + "curation-task.task.registerdoi.label": "Đăng ký DOI", "curation-task.task.requiredmetadata.label": "Kiểm tra các trường dữ liệu bắt buộc", "curation-task.task.translate.label": "Bộ dịch của Microsoft", "curation-task.task.vscan.label": "Quét Virus", From 338b63ebb8ed847dfd2d2d872b2bc0a4994c7b83 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 28 Jul 2023 14:10:44 -0500 Subject: [PATCH 061/282] Add action to automatically create a port PR when specified --- .../workflows/port_merged_pull_request.yml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/port_merged_pull_request.yml diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml new file mode 100644 index 00000000000..50faf3f8867 --- /dev/null +++ b/.github/workflows/port_merged_pull_request.yml @@ -0,0 +1,44 @@ +# This workflow will attempt to port a merged pull request to +# the branch specified in a "port to" label (if exists) +name: Port merged Pull Request + +# Only run for merged PRs against the "main" or maintenance branches +# We allow this to run for `pull_request_target` so that github secrets are available +# (This is required when the PR comes from a forked repo) +on: + pull_request_target: + types: [ closed ] + branches: + - main + - 'dspace-**' + +permissions: + contents: write # so action can add comments + pull-requests: write # so action can create pull requests + +jobs: + port_pr: + runs-on: ubuntu-latest + # Don't run on closed *unmerged* pull requests + if: github.event.pull_request.merged + steps: + # Checkout code + - uses: actions/checkout@v3 + # Port PR to other branch (ONLY if labeled with "port to") + # See https://github.com/korthout/backport-action + - name: Create backport pull requests + uses: korthout/backport-action@v1 + with: + # Trigger based on a "port to [branch]" label on PR + # (This label must specify the branch name to port to) + label_pattern: '^port to ([^ ]+)$' + # Title to add to the (newly created) port PR + pull_title: '[Port ${target_branch}] ${pull_title}' + # Description to add to the (newly created) port PR + pull_description: 'Port of #${pull_number} by @${pull_author} to `${target_branch}`.' + # Copy all labels from original PR to (newly created) port PR + # NOTE: The labels matching 'label_pattern' are automatically excluded + copy_labels_pattern: '.*' + # Use a personal access token (PAT) to create PR as 'dspace-bot' user. + # A PAT is required in order for the new PR to trigger its own actions (for CI checks) + github_token: ${{ secrets.PR_PORT_TOKEN }} \ No newline at end of file From d75d12b423206e0261372b372c27c04c36336cff Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 28 Jul 2023 14:11:08 -0500 Subject: [PATCH 062/282] Minor update to label_merge_conflicts to ignore any errors (seem random at this time) --- .github/workflows/label_merge_conflicts.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/label_merge_conflicts.yml b/.github/workflows/label_merge_conflicts.yml index 7ea33277411..ccc6c401c0b 100644 --- a/.github/workflows/label_merge_conflicts.yml +++ b/.github/workflows/label_merge_conflicts.yml @@ -25,6 +25,8 @@ jobs: # See: https://github.com/prince-chrismc/label-merge-conflicts-action - name: Auto-label PRs with merge conflicts uses: prince-chrismc/label-merge-conflicts-action@v3 + # Ignore any failures -- may occur (randomly?) for older, outdated PRs. + continue-on-error: true # Add "merge conflict" label if a merge conflict is detected. Remove it when resolved. # Note, the authentication token is created automatically # See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token From ea677bda741bdccee8422945fb9cd7caa4f1e450 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 30 Jul 2023 19:43:20 +0200 Subject: [PATCH 063/282] Reset to base theme when no default theme is set and leaving UUID/handle theme --- src/app/shared/theme-support/theme.service.ts | 9 +++++---- src/config/config.util.ts | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/app/shared/theme-support/theme.service.ts b/src/app/shared/theme-support/theme.service.ts index 6d2939a5f88..762aece7299 100644 --- a/src/app/shared/theme-support/theme.service.ts +++ b/src/app/shared/theme-support/theme.service.ts @@ -29,7 +29,7 @@ export const themeStateSelector = createFeatureSelector<ThemeState>('theme'); export const currentThemeSelector = createSelector( themeStateSelector, - (state: ThemeState): string => hasValue(state) ? state.currentTheme : undefined + (state: ThemeState): string => hasValue(state) ? state.currentTheme : BASE_THEME_NAME, ); @Injectable({ @@ -262,7 +262,7 @@ export class ThemeService { } // inherit the head tags of the default theme - return this.createHeadTags(defaultThemeConfig.name); + return this.createHeadTags(defaultThemeName); } return headTagConfigs.map(this.createHeadTag.bind(this)); @@ -425,9 +425,10 @@ export class ThemeService { * @private */ private getActionForMatch(newTheme: Theme, currentThemeName: string): SetThemeAction | NoOpAction { - if (hasValue(newTheme) && newTheme.config.name !== currentThemeName) { + const newThemeName: string = newTheme?.config.name ?? BASE_THEME_NAME; + if (newThemeName !== currentThemeName) { // If we have a match, and it isn't already the active theme, set it as the new theme - return new SetThemeAction(newTheme.config.name); + return new SetThemeAction(newThemeName); } else { // Otherwise, do nothing return new NoOpAction(); diff --git a/src/config/config.util.ts b/src/config/config.util.ts index c45282269c1..cf744b29203 100644 --- a/src/config/config.util.ts +++ b/src/config/config.util.ts @@ -5,7 +5,8 @@ import { environment } from '../environments/environment'; import { hasNoValue } from '../app/shared/empty.util'; import { AppConfig } from './app-config.interface'; -import { ThemeConfig } from './theme.model'; +import { ThemeConfig, NamedThemeConfig } from './theme.model'; +import { BASE_THEME_NAME } from '../app/shared/theme-support/theme.constants'; /** * Extend Angular environment with app config. @@ -44,7 +45,9 @@ const getDefaultThemeConfig = (): ThemeConfig => { hasNoValue(themeConfig.regex) && hasNoValue(themeConfig.handle) && hasNoValue(themeConfig.uuid) - ); + ) ?? { + name: BASE_THEME_NAME, + } as NamedThemeConfig; }; export { From 18b7a9c7de6e399d5ed27ff22caa082ab7e8ef2a Mon Sep 17 00:00:00 2001 From: Yury Bondarenko <ybnd@tuta.io> Date: Mon, 31 Jul 2023 15:41:25 +0200 Subject: [PATCH 064/282] Update DSO edit menu resolver tests - Abstract away the different "subsections" ~ DSO type (the tests should not care about this) Instead, retrieve sections of interest by ID & assert whether they're there & how they should look - Test separately for Communities, Collections & Items - Test newly added menu section --- .../dso-page/dso-edit-menu.resolver.spec.ts | 254 ++++++++++++++---- 1 file changed, 199 insertions(+), 55 deletions(-) diff --git a/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts b/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts index abfe618174b..e28a416f230 100644 --- a/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts +++ b/src/app/shared/dso-page/dso-edit-menu.resolver.spec.ts @@ -1,6 +1,6 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { MenuServiceStub } from '../testing/menu-service.stub'; -import { of as observableOf } from 'rxjs'; +import { combineLatest, map, of as observableOf } from 'rxjs'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; @@ -16,10 +16,13 @@ import { Item } from '../../core/shared/item.model'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; import { MenuID } from '../menu/menu-id.model'; import { MenuItemType } from '../menu/menu-item-type.model'; -import { TextMenuItemModel } from '../menu/menu-item/models/text.model'; import { LinkMenuItemModel } from '../menu/menu-item/models/link.model'; import { ResearcherProfileDataService } from '../../core/profile/researcher-profile-data.service'; import { NotificationsService } from '../notifications/notifications.service'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { Community } from '../../core/shared/community.model'; +import { Collection } from '../../core/shared/collection.model'; +import flatten from 'lodash/flatten'; describe('DSOEditMenuResolver', () => { @@ -37,25 +40,44 @@ describe('DSOEditMenuResolver', () => { let notificationsService; let translate; - const route = { - data: { - menu: { - 'statistics': [{ - id: 'statistics-dummy-1', - active: false, - visible: true, - model: null - }] - } - }, - params: {id: 'test-uuid'}, + const dsoRoute = (dso: DSpaceObject) => { + return { + data: { + menu: { + 'statistics': [{ + id: 'statistics-dummy-1', + active: false, + visible: true, + model: null + }] + } + }, + params: {id: dso.uuid}, + }; }; const state = { url: 'test-url' }; - const testObject = Object.assign(new Item(), {uuid: 'test-uuid', type: 'item', _links: {self: {href: 'self-link'}}}); + const testCommunity: Community = Object.assign(new Community(), { + uuid: 'test-community-uuid', + type: 'community', + _links: {self: {href: 'self-link'}}, + }); + const testCollection: Collection = Object.assign(new Collection(), { + uuid: 'test-collection-uuid', + type: 'collection', + _links: {self: {href: 'self-link'}}, + }); + const testItem: Item = Object.assign(new Item(), { + uuid: 'test-item-uuid', + type: 'item', + _links: {self: {href: 'self-link'}}, + }); + + let testObject: DSpaceObject; + let route; const dummySections1 = [{ id: 'dummy-1', @@ -90,6 +112,10 @@ describe('DSOEditMenuResolver', () => { }]; beforeEach(waitForAsync(() => { + // test with Items unless specified otherwise + testObject = testItem; + route = dsoRoute(testItem); + menuService = new MenuServiceStub(); spyOn(menuService, 'getMenu').and.returnValue(observableOf(MENU_STATE)); @@ -154,16 +180,17 @@ describe('DSOEditMenuResolver', () => { { ...route.data.menu, [MenuID.DSO_EDIT]: [ - ...dummySections1.map((menu) => Object.assign(menu, {id: menu.id + '-test-uuid'})), - ...dummySections2.map((menu) => Object.assign(menu, {id: menu.id + '-test-uuid'})) + ...dummySections1.map((menu) => Object.assign(menu, {id: menu.id + '-test-item-uuid'})), + ...dummySections2.map((menu) => Object.assign(menu, {id: menu.id + '-test-item-uuid'})) ] } ); - expect(dSpaceObjectDataService.findById).toHaveBeenCalledWith('test-uuid', true, false); + expect(dSpaceObjectDataService.findById).toHaveBeenCalledWith('test-item-uuid', true, false); expect(resolver.getDsoMenus).toHaveBeenCalled(); done(); }); }); + it('should create all menus when a dso is found based on the route scope query param when no id param is present', (done) => { spyOn(resolver, 'getDsoMenus').and.returnValue( [observableOf(dummySections1), observableOf(dummySections2)] @@ -198,6 +225,7 @@ describe('DSOEditMenuResolver', () => { done(); }); }); + it('should return the statistics menu when no dso is found', (done) => { (dSpaceObjectDataService.findById as jasmine.Spy).and.returnValue(createFailedRemoteDataObject$()); @@ -211,49 +239,165 @@ describe('DSOEditMenuResolver', () => { }); }); }); + describe('getDsoMenus', () => { - it('should return as first part the item version, orcid and claim list ', (done) => { - const result = resolver.getDsoMenus(testObject, route, state); - result[0].subscribe((menuList) => { - expect(menuList.length).toEqual(3); - expect(menuList[0].id).toEqual('orcid-dso'); - expect(menuList[0].active).toEqual(false); - // Visible should be false due to the item not being of type person - expect(menuList[0].visible).toEqual(false); - expect(menuList[0].model.type).toEqual(MenuItemType.LINK); - - expect(menuList[1].id).toEqual('version-dso'); - expect(menuList[1].active).toEqual(false); - expect(menuList[1].visible).toEqual(true); - expect(menuList[1].model.type).toEqual(MenuItemType.ONCLICK); - expect((menuList[1].model as TextMenuItemModel).text).toEqual('message'); - expect(menuList[1].model.disabled).toEqual(false); - expect(menuList[1].icon).toEqual('code-branch'); - - expect(menuList[2].id).toEqual('claim-dso'); - expect(menuList[2].active).toEqual(false); - // Visible should be false due to the item not being of type person - expect(menuList[2].visible).toEqual(false); - expect(menuList[2].model.type).toEqual(MenuItemType.ONCLICK); - expect((menuList[2].model as TextMenuItemModel).text).toEqual('item.page.claim.button'); - done(); + describe('for Communities', () => { + beforeEach(() => { + testObject = testCommunity; + dSpaceObjectDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(testCommunity)); + route = dsoRoute(testCommunity); + }); + + it('should not return Item-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const orcidEntry = menu.find(entry => entry.id === 'orcid-dso'); + expect(orcidEntry).toBeFalsy(); + + const versionEntry = menu.find(entry => entry.id === 'version-dso'); + expect(versionEntry).toBeFalsy(); + + const claimEntry = menu.find(entry => entry.id === 'claim-dso'); + expect(claimEntry).toBeFalsy(); + + done(); + }); + }); + + it('should return Community/Collection-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const subscribeEntry = menu.find(entry => entry.id === 'subscribe'); + expect(subscribeEntry).toBeTruthy(); + expect(subscribeEntry.active).toBeFalse(); + expect(subscribeEntry.visible).toBeTrue(); + expect(subscribeEntry.model.type).toEqual(MenuItemType.ONCLICK); + done(); + }); }); + it('should return as third part the common list ', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const editEntry = menu.find(entry => entry.id === 'edit-dso'); + expect(editEntry).toBeTruthy(); + expect(editEntry.active).toBeFalse(); + expect(editEntry.visible).toBeTrue(); + expect(editEntry.model.type).toEqual(MenuItemType.LINK); + expect((editEntry.model as LinkMenuItemModel).link).toEqual( + '/communities/test-community-uuid/edit/metadata' + ); + done(); + }); + }); }); - it('should return as second part the common list ', (done) => { - const result = resolver.getDsoMenus(testObject, route, state); - result[1].subscribe((menuList) => { - expect(menuList.length).toEqual(1); - expect(menuList[0].id).toEqual('edit-dso'); - expect(menuList[0].active).toEqual(false); - expect(menuList[0].visible).toEqual(true); - expect(menuList[0].model.type).toEqual(MenuItemType.LINK); - expect((menuList[0].model as LinkMenuItemModel).text).toEqual('item.page.edit'); - expect((menuList[0].model as LinkMenuItemModel).link).toEqual('/items/test-uuid/edit/metadata'); - expect(menuList[0].icon).toEqual('pencil-alt'); - done(); + + describe('for Collections', () => { + beforeEach(() => { + testObject = testCollection; + dSpaceObjectDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(testCollection)); + route = dsoRoute(testCollection); + }); + + it('should not return Item-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const orcidEntry = menu.find(entry => entry.id === 'orcid-dso'); + expect(orcidEntry).toBeFalsy(); + + const versionEntry = menu.find(entry => entry.id === 'version-dso'); + expect(versionEntry).toBeFalsy(); + + const claimEntry = menu.find(entry => entry.id === 'claim-dso'); + expect(claimEntry).toBeFalsy(); + + done(); + }); + }); + + it('should return Community/Collection-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const subscribeEntry = menu.find(entry => entry.id === 'subscribe'); + expect(subscribeEntry).toBeTruthy(); + expect(subscribeEntry.active).toBeFalse(); + expect(subscribeEntry.visible).toBeTrue(); + expect(subscribeEntry.model.type).toEqual(MenuItemType.ONCLICK); + done(); + }); + }); + + it('should return as third part the common list ', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const editEntry = menu.find(entry => entry.id === 'edit-dso'); + expect(editEntry).toBeTruthy(); + expect(editEntry.active).toBeFalse(); + expect(editEntry.visible).toBeTrue(); + expect(editEntry.model.type).toEqual(MenuItemType.LINK); + expect((editEntry.model as LinkMenuItemModel).link).toEqual( + '/collections/test-collection-uuid/edit/metadata' + ); + done(); + }); }); + }); + + describe('for Items', () => { + beforeEach(() => { + testObject = testItem; + dSpaceObjectDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(testItem)); + route = dsoRoute(testItem); + }); + + it('should return Item-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const orcidEntry = menu.find(entry => entry.id === 'orcid-dso'); + expect(orcidEntry).toBeTruthy(); + expect(orcidEntry.active).toBeFalse(); + expect(orcidEntry.visible).toBeFalse(); + expect(orcidEntry.model.type).toEqual(MenuItemType.LINK); + + const versionEntry = menu.find(entry => entry.id === 'version-dso'); + expect(versionEntry).toBeTruthy(); + expect(versionEntry.active).toBeFalse(); + expect(versionEntry.visible).toBeTrue(); + expect(versionEntry.model.type).toEqual(MenuItemType.ONCLICK); + expect(versionEntry.model.disabled).toBeFalse(); + const claimEntry = menu.find(entry => entry.id === 'claim-dso'); + expect(claimEntry).toBeTruthy(); + expect(claimEntry.active).toBeFalse(); + expect(claimEntry.visible).toBeFalse(); + expect(claimEntry.model.type).toEqual(MenuItemType.ONCLICK); + done(); + }); + }); + + it('should not return Community/Collection-specific entries', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const subscribeEntry = menu.find(entry => entry.id === 'subscribe'); + expect(subscribeEntry).toBeFalsy(); + done(); + }); + }); + + it('should return as third part the common list ', (done) => { + const result = resolver.getDsoMenus(testObject, route, state); + combineLatest(result).pipe(map(flatten)).subscribe((menu) => { + const editEntry = menu.find(entry => entry.id === 'edit-dso'); + expect(editEntry).toBeTruthy(); + expect(editEntry.active).toBeFalse(); + expect(editEntry.visible).toBeTrue(); + expect(editEntry.model.type).toEqual(MenuItemType.LINK); + expect((editEntry.model as LinkMenuItemModel).link).toEqual( + '/items/test-item-uuid/edit/metadata' + ); + done(); + }); + }); }); }); }); From 0b0c60e38c1aecb690f15b1af20df655bd028c5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:23:09 +0000 Subject: [PATCH 065/282] Bump semver from 5.7.1 to 5.7.2 Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 730966fcdb5..21de68a480a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10114,33 +10114,33 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -semver@7.3.8, semver@^7.3.5, semver@^7.3.8: +semver@7.3.8: version "7.3.8" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== dependencies: lru-cache "^6.0.0" semver@^5.3.0, semver@^5.6.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.7: - version "7.4.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz" - integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw== +semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" semver@~7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== send@0.16.2: From 2fec33e70af5de3a2533f4ff33aabaff4aae03fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:28:22 +0000 Subject: [PATCH 066/282] Bump word-wrap from 1.2.3 to 1.2.5 Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.5. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 730966fcdb5..3394bc6456b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11743,9 +11743,9 @@ wildcard@^2.0.0: integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wrap-ansi@^6.2.0: version "6.2.0" From 71cf66ecf491870d8abe578408af3a1f7b5077c9 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 2 Aug 2023 00:00:37 +0200 Subject: [PATCH 067/282] Fix display order of authentication methods --- src/app/core/auth/auth.interceptor.ts | 6 +-- src/app/core/auth/auth.reducer.spec.ts | 8 ++-- src/app/core/auth/auth.reducer.ts | 2 +- src/app/core/auth/models/auth.method.ts | 5 ++- .../log-in-container.component.spec.ts | 12 ++++-- src/app/shared/log-in/log-in.component.html | 14 +++---- .../shared/log-in/log-in.component.spec.ts | 2 +- src/app/shared/log-in/log-in.component.ts | 34 +++++++-------- .../methods/oidc/log-in-oidc.component.html | 4 +- .../oidc/log-in-oidc.component.spec.ts | 42 ++++--------------- .../methods/orcid/log-in-orcid.component.html | 4 +- .../orcid/log-in-orcid.component.spec.ts | 39 +++-------------- .../password/log-in-password.component.html | 9 ++++ .../password/log-in-password.component.scss | 4 ++ .../log-in-password.component.spec.ts | 20 ++++----- .../password/log-in-password.component.ts | 25 +++++++---- .../log-in-shibboleth.component.html | 2 +- .../log-in-shibboleth.component.spec.ts | 39 +++-------------- src/app/shared/testing/auth-service.stub.ts | 7 ++-- src/assets/i18n/en.json5 | 2 - 20 files changed, 107 insertions(+), 173 deletions(-) diff --git a/src/app/core/auth/auth.interceptor.ts b/src/app/core/auth/auth.interceptor.ts index e55d0c0ff96..47ef0b11a5e 100644 --- a/src/app/core/auth/auth.interceptor.ts +++ b/src/app/core/auth/auth.interceptor.ts @@ -152,12 +152,12 @@ export class AuthInterceptor implements HttpInterceptor { let authMethodModel: AuthMethod; if (splittedRealm.length === 1) { - authMethodModel = new AuthMethod(methodName); + authMethodModel = new AuthMethod(methodName, Number(j)); authMethodModels.push(authMethodModel); } else if (splittedRealm.length > 1) { let location = splittedRealm[1]; location = this.parseLocation(location); - authMethodModel = new AuthMethod(methodName, location); + authMethodModel = new AuthMethod(methodName, Number(j), location); authMethodModels.push(authMethodModel); } } @@ -165,7 +165,7 @@ export class AuthInterceptor implements HttpInterceptor { // make sure the email + password login component gets rendered first authMethodModels = this.sortAuthMethods(authMethodModels); } else { - authMethodModels.push(new AuthMethod(AuthMethodType.Password)); + authMethodModels.push(new AuthMethod(AuthMethodType.Password, 0)); } return authMethodModels; diff --git a/src/app/core/auth/auth.reducer.spec.ts b/src/app/core/auth/auth.reducer.spec.ts index 8ebc9f6cb03..770bcc8691f 100644 --- a/src/app/core/auth/auth.reducer.spec.ts +++ b/src/app/core/auth/auth.reducer.spec.ts @@ -575,9 +575,9 @@ describe('authReducer', () => { authMethods: [], idle: false }; - const authMethods = [ - new AuthMethod(AuthMethodType.Password), - new AuthMethod(AuthMethodType.Shibboleth, 'location') + const authMethods: AuthMethod[] = [ + new AuthMethod(AuthMethodType.Password, 0), + new AuthMethod(AuthMethodType.Shibboleth, 1, 'location'), ]; const action = new RetrieveAuthMethodsSuccessAction(authMethods); const newState = authReducer(initialState, action); @@ -609,7 +609,7 @@ describe('authReducer', () => { loaded: false, blocking: false, loading: false, - authMethods: [new AuthMethod(AuthMethodType.Password)], + authMethods: [new AuthMethod(AuthMethodType.Password, 0)], idle: false }; expect(newState).toEqual(state); diff --git a/src/app/core/auth/auth.reducer.ts b/src/app/core/auth/auth.reducer.ts index acdb8ef812f..d09777c60f1 100644 --- a/src/app/core/auth/auth.reducer.ts +++ b/src/app/core/auth/auth.reducer.ts @@ -228,7 +228,7 @@ export function authReducer(state: any = initialState, action: AuthActions): Aut return Object.assign({}, state, { loading: false, blocking: false, - authMethods: [new AuthMethod(AuthMethodType.Password)] + authMethods: [new AuthMethod(AuthMethodType.Password, 0)] }); case AuthActionTypes.SET_REDIRECT_URL: diff --git a/src/app/core/auth/models/auth.method.ts b/src/app/core/auth/models/auth.method.ts index 0579ae0cd1b..b84e7a308af 100644 --- a/src/app/core/auth/models/auth.method.ts +++ b/src/app/core/auth/models/auth.method.ts @@ -2,11 +2,12 @@ import { AuthMethodType } from './auth.method-type'; export class AuthMethod { authMethodType: AuthMethodType; + position: number; location?: string; - // isStandalonePage? = true; + constructor(authMethodName: string, position: number, location?: string) { + this.position = position; - constructor(authMethodName: string, location?: string) { switch (authMethodName) { case 'ip': { this.authMethodType = AuthMethodType.Ip; diff --git a/src/app/shared/log-in/container/log-in-container.component.spec.ts b/src/app/shared/log-in/container/log-in-container.component.spec.ts index 29598e422ec..4700cf93071 100644 --- a/src/app/shared/log-in/container/log-in-container.component.spec.ts +++ b/src/app/shared/log-in/container/log-in-container.component.spec.ts @@ -13,13 +13,17 @@ import { AuthMethod } from '../../../core/auth/models/auth.method'; import { AuthServiceStub } from '../../testing/auth-service.stub'; import { createTestComponent } from '../../testing/utils.test'; import { HardRedirectService } from '../../../core/services/hard-redirect.service'; +import { AuthMethodType } from '../../../core/auth/models/auth.method-type'; +import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; +import { AuthorizationDataServiceStub } from '../../testing/authorization-service.stub'; +import { RouterTestingModule } from '@angular/router/testing'; describe('LogInContainerComponent', () => { let component: LogInContainerComponent; let fixture: ComponentFixture<LogInContainerComponent>; - const authMethod = new AuthMethod('password'); + const authMethod = new AuthMethod(AuthMethodType.Password, 0); let hardRedirectService: HardRedirectService; @@ -35,13 +39,15 @@ describe('LogInContainerComponent', () => { ReactiveFormsModule, StoreModule.forRoot(authReducer), SharedModule, - TranslateModule.forRoot() + TranslateModule.forRoot(), + RouterTestingModule, ], declarations: [ TestComponent ], providers: [ { provide: AuthService, useClass: AuthServiceStub }, + { provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub }, { provide: HardRedirectService, useValue: hardRedirectService }, LogInContainerComponent ], @@ -113,6 +119,6 @@ describe('LogInContainerComponent', () => { class TestComponent { isStandalonePage = true; - authMethod = new AuthMethod('password'); + authMethod = new AuthMethod(AuthMethodType.Password, 0); } diff --git a/src/app/shared/log-in/log-in.component.html b/src/app/shared/log-in/log-in.component.html index 6e4685a07bd..173e0f8e303 100644 --- a/src/app/shared/log-in/log-in.component.html +++ b/src/app/shared/log-in/log-in.component.html @@ -1,13 +1,11 @@ <ds-themed-loading *ngIf="(loading | async) || (isAuthenticated | async)" class="m-5"></ds-themed-loading> <div *ngIf="!(loading | async) && !(isAuthenticated | async)" class="px-4 py-3 login-container"> - <ng-container *ngFor="let authMethod of (authMethods | async); let i = index"> - <div *ngIf="i === 1" class="text-center mt-2"> - <span class="align-middle">{{"login.form.or-divider" | translate}}</span> + <ng-container *ngFor="let authMethod of getOrderedAuthMethods(authMethods | async); let last = last"> + <div [class.d-none]="contentRef.innerText.trim().length === 0"> + <div #contentRef> + <ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container> + </div> + <div *ngIf="!last" class="dropdown-divider my-2"></div> </div> - <ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container> </ng-container> - - <div class="dropdown-divider"></div> - <a class="dropdown-item" *ngIf="canRegister$ | async" [routerLink]="[getRegisterRoute()]" [attr.data-test]="'register' | dsBrowserOnly">{{"login.form.new-user" | translate}}</a> - <a class="dropdown-item" [routerLink]="[getForgotRoute()]" [attr.data-test]="'forgot' | dsBrowserOnly">{{"login.form.forgot-password" | translate}}</a> </div> diff --git a/src/app/shared/log-in/log-in.component.spec.ts b/src/app/shared/log-in/log-in.component.spec.ts index 0a13e8b701e..57ed3e46946 100644 --- a/src/app/shared/log-in/log-in.component.spec.ts +++ b/src/app/shared/log-in/log-in.component.spec.ts @@ -50,7 +50,7 @@ describe('LogInComponent', () => { }); // refine the test module by declaring the test component - TestBed.configureTestingModule({ + void TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, diff --git a/src/app/shared/log-in/log-in.component.ts b/src/app/shared/log-in/log-in.component.ts index 120f3ac4fad..9cc466dcfe2 100644 --- a/src/app/shared/log-in/log-in.component.ts +++ b/src/app/shared/log-in/log-in.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { select, Store } from '@ngrx/store'; import { AuthMethod } from '../../core/auth/models/auth.method'; @@ -8,11 +8,8 @@ import { isAuthenticated, isAuthenticationLoading } from '../../core/auth/selectors'; -import { getForgotPasswordRoute, getRegisterRoute } from '../../app-routing-paths'; import { hasValue } from '../empty.util'; import { AuthService } from '../../core/auth/auth.service'; -import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; -import { FeatureID } from '../../core/data/feature-authorization/feature-id'; import { CoreState } from '../../core/core-state.model'; /** @@ -22,7 +19,8 @@ import { CoreState } from '../../core/core-state.model'; @Component({ selector: 'ds-log-in', templateUrl: './log-in.component.html', - styleUrls: ['./log-in.component.scss'] + styleUrls: ['./log-in.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class LogInComponent implements OnInit { @@ -50,14 +48,9 @@ export class LogInComponent implements OnInit { */ public loading: Observable<boolean>; - /** - * Whether or not the current user (or anonymous) is authorized to register an account - */ - canRegister$: Observable<boolean>; - constructor(private store: Store<CoreState>, private authService: AuthService, - private authorizationService: AuthorizationDataService) { + ) { } ngOnInit(): void { @@ -78,15 +71,18 @@ export class LogInComponent implements OnInit { this.authService.clearRedirectUrl(); } }); - - this.canRegister$ = this.authorizationService.isAuthorized(FeatureID.EPersonRegistration); } - getRegisterRoute() { - return getRegisterRoute(); - } - - getForgotRoute() { - return getForgotPasswordRoute(); + /** + * Returns an ordered list of {@link AuthMethod}s based on their position. + * + * @param authMethods The {@link AuthMethod}s to sort + */ + getOrderedAuthMethods(authMethods: AuthMethod[] | null): AuthMethod[] { + if (hasValue(authMethods)) { + return [...authMethods].sort((method1: AuthMethod, method2: AuthMethod) => method1.position - method2.position); + } else { + return []; + } } } diff --git a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html index 7e78834305b..5719a4838fd 100644 --- a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html +++ b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html @@ -1,3 +1,3 @@ -<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToOidc()"> +<button class="btn btn-lg btn-primary btn-block text-white" (click)="redirectToOidc()"> <i class="fas fa-sign-in-alt"></i> {{"login.form.oidc" | translate}} -</button> \ No newline at end of file +</button> 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<LogInOidcComponent>; - 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<LogInOidcComponent>) { - // 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 @@ -<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToOrcid()"> +<button class="btn btn-lg btn-primary btn-block text-white" (click)="redirectToOrcid()"> <i class="fas fa-sign-in-alt"></i> {{"login.form.orcid" | translate}} -</button> \ No newline at end of file +</button> 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<LogInOrcidComponent>; - 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<LogInOrcidComponent>) { - // 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 @@ <button class="btn btn-lg btn-primary btn-block mt-3" type="submit" [attr.data-test]="'login-button' | dsBrowserOnly" [disabled]="!form.valid"><i class="fas fa-sign-in-alt"></i> {{"login.form.submit" | translate}}</button> </form> + +<div class="mt-2"> + <a class="dropdown-item" *ngIf="canRegister$ | async" [routerLink]="[getRegisterRoute()]" [attr.data-test]="'register' | dsBrowserOnly"> + {{ 'login.form.new-user' | translate }} + </a> + <a class="dropdown-item" [routerLink]="[getForgotRoute()]" [attr.data-test]="'forgot' | dsBrowserOnly"> + {{ 'login.form.forgot-password' | translate }} + </a> +</div> 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<LogInPasswordComponent>; 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<State>} store + * Whether the current user (or anonymous) is authorized to register an account */ + public canRegister$: Observable<boolean>; + constructor( @Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod, @Inject('isStandalonePage') public isStandalonePage: boolean, private authService: AuthService, private hardRedirectService: HardRedirectService, private formBuilder: FormBuilder, - private store: Store<CoreState> + protected store: Store<CoreState>, + 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 @@ -<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToShibboleth()"> +<button class="btn btn-lg btn-primary btn-block text-white" (click)="redirectToShibboleth()"> <i class="fas fa-sign-in-alt"></i> {{"login.form.shibboleth" | translate}} </button> 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<LogInShibbolethComponent>; - 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<LogInShibbolethComponent>) { - // 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 <szott@gmx.de> Date: Wed, 2 Aug 2023 18:00:03 +0200 Subject: [PATCH 068/282] 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 <alexandre@atmire.com> Date: Wed, 2 Aug 2023 21:25:58 +0200 Subject: [PATCH 069/282] 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<AuthMethod[]>; /** * 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 4c93b4728b215474c793b6ee8951b92019c7e2fa Mon Sep 17 00:00:00 2001 From: Alan Orth <alan.orth@gmail.com> Date: Fri, 30 Jun 2023 09:49:01 +0300 Subject: [PATCH 070/282] src/assets/i18n: update Finnish language strings Contributed by Reeta Kuukoski from the National Library of Finland. (cherry picked from commit 1b9656b1351a0de44e15c3d26cab56645b200956) --- src/assets/i18n/fi.json5 | 3382 +++++++++++++++++++++++++++++++++----- 1 file changed, 2975 insertions(+), 407 deletions(-) diff --git a/src/assets/i18n/fi.json5 b/src/assets/i18n/fi.json5 index 62e7e6bffe2..c56fcb6fecc 100644 --- a/src/assets/i18n/fi.json5 +++ b/src/assets/i18n/fi.json5 @@ -9,8 +9,6 @@ // "401.unauthorized": "unauthorized", "401.unauthorized": "valtuuttamaton", - - // "403.help": "You don't have permission to access this page. You can use the button below to get back to the home page.", "403.help": "Sinulla ei ole oikeutta nähdä sivua. Voit palata etusivulle alla olevalla painikkeella.", @@ -20,10 +18,17 @@ // "403.forbidden": "forbidden", "403.forbidden": "kielletty", + // "500.page-internal-server-error": "Service Unavailable", + "500.page-internal-server-error": "Palvelu ei ole saatavilla", + // "500.help": "The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.", + "500.help": "Palvelin ei tilapäisesti pysty käsittelemään pyyntöäsi huoltokatkon tai kapasiteettiongelmien vuoksi. Yritä myöhemmin uudelleen.", + + // "500.link.home-page": "Take me to the home page", + "500.link.home-page": "Palaa etusivulle", // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", - "404.help": "Hakemaasi sivua ei löytynyt. Sivu on voitu siirtää tai poistaa. Painamalla alapuolella olevaa nappia palaat etusivulle. ", + "404.help": "Hakemaasi sivua ei löytynyt. Sivu on voitu siirtää tai poistaa. Painamalla alapuolella olevaa painiketta palaat etusivulle. ", // "404.link.home-page": "Take me to the home page", "404.link.home-page": "Palaa etusivulle", @@ -31,6 +36,36 @@ // "404.page-not-found": "page not found", "404.page-not-found": "sivua ei löytynyt", + // "error-page.description.401": "unauthorized", + "error-page.description.401": "valtuuttamaton", + + // "error-page.description.403": "forbidden", + "error-page.description.403": "kielletty", + + // "error-page.description.500": "Service Unavailable", + "error-page.description.500": "Palvelu ei ole saatavilla", + + // "error-page.description.404": "page not found", + "error-page.description.404": "sivua ei löytynyt", + + // "error-page.orcid.generic-error": "An error occurred during login via ORCID. Make sure you have shared your ORCID account email address with DSpace. If the error persists, contact the administrator", + "error-page.orcid.generic-error": "Virhe ORCID-kirjautumisessa. Varmista, että olet tuonut ORCID-tilisi sähköpostiosoitteen DSpaceen. Jos virhe jatkuu, ota yhteyttä ylläpitäjään.", + + // "access-status.embargo.listelement.badge": "Embargo", + "access-status.embargo.listelement.badge": "Embargo", + + // "access-status.metadata.only.listelement.badge": "Metadata only", + "access-status.metadata.only.listelement.badge": "Vain metadata", + + // "access-status.open.access.listelement.badge": "Open Access", + "access-status.open.access.listelement.badge": "Open Access", + + // "access-status.restricted.listelement.badge": "Restricted", + "access-status.restricted.listelement.badge": "Rajattu", + + // "access-status.unknown.listelement.badge": "Unknown", + "access-status.unknown.listelement.badge": "Tuntematon", + // "admin.curation-tasks.breadcrumbs": "System curation tasks", "admin.curation-tasks.breadcrumbs": "Järjestelmän kuratointitehtävät", @@ -157,11 +192,11 @@ // "admin.registries.bitstream-formats.table.name": "Name", "admin.registries.bitstream-formats.table.name": "Nimi", - // "admin.registries.bitstream-formats.table.id" : "ID", + // "admin.registries.bitstream-formats.table.id": "ID", "admin.registries.bitstream-formats.table.id": "ID", - // "admin.registries.bitstream-formats.table.return": "Return", - "admin.registries.bitstream-formats.table.return": "Palaa", + // "admin.registries.bitstream-formats.table.return": "Back", + "admin.registries.bitstream-formats.table.return": "Paluu", // "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Tunnettu", @@ -175,10 +210,8 @@ // "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", "admin.registries.bitstream-formats.table.supportLevel.head": "Tukitaso", - // "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry", - "admin.registries.bitstream-formats.title": "DSpace Angular :: Tiedostoformaattirekisteri", - - + // "admin.registries.bitstream-formats.title": "Bitstream Format Registry", + "admin.registries.bitstream-formats.title": "Tiedostoformaattirekisteri", // "admin.registries.metadata.breadcrumbs": "Metadata registry", "admin.registries.metadata.breadcrumbs": "Metadatarekisteri", @@ -216,10 +249,8 @@ // "admin.registries.metadata.schemas.table.namespace": "Namespace", "admin.registries.metadata.schemas.table.namespace": "Nimiavaruus", - // "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry", - "admin.registries.metadata.title": "DSpace Angular :: Metadatarekisteri", - - + // "admin.registries.metadata.title": "Metadata Registry", + "admin.registries.metadata.title": "Metadatarekisteri", // "admin.registries.schema.breadcrumbs": "Metadata schema", "admin.registries.schema.breadcrumbs": "Metadataskeema", @@ -293,13 +324,11 @@ // "admin.registries.schema.notification.success": "Success", "admin.registries.schema.notification.success": "Valmis", - // "admin.registries.schema.return": "Return", - "admin.registries.schema.return": "Palaa", - - // "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry", - "admin.registries.schema.title": "DSpace Angular :: Metadataskeemarekisteri", - + // "admin.registries.schema.return": "Back", + "admin.registries.schema.return": "Paluu", + // "admin.registries.schema.title": "Metadata Schema Registry", + "admin.registries.schema.title": "Metadataskeemarekisteri", // "admin.access-control.epeople.actions.delete": "Delete EPerson", "admin.access-control.epeople.actions.delete": "Poista käyttäjä", @@ -313,7 +342,10 @@ // "admin.access-control.epeople.actions.stop-impersonating": "Stop impersonating EPerson", "admin.access-control.epeople.actions.stop-impersonating": "Lopeta käyttäjänä esiintyminen", - // "admin.access-control.epeople.title": "DSpace Angular :: EPeople", + // "admin.access-control.epeople.breadcrumbs": "EPeople", + "admin.access-control.epeople.breadcrumbs": "Käyttäjät", + + // "admin.access-control.epeople.title": "EPeople", "admin.access-control.epeople.title": "DSpace Angular :: Käyttäjät", // "admin.access-control.epeople.head": "EPeople", @@ -334,6 +366,9 @@ // "admin.access-control.epeople.search.button": "Search", "admin.access-control.epeople.search.button": "Hae", + // "admin.access-control.epeople.search.placeholder": "Search people...", + "admin.access-control.epeople.search.placeholder": "Hae käyttäjiä...", + // "admin.access-control.epeople.button.add": "Add EPerson", "admin.access-control.epeople.button.add": "Lisää käyttäjä", @@ -352,6 +387,9 @@ // "admin.access-control.epeople.table.edit.buttons.edit": "Edit \"{{name}}\"", "admin.access-control.epeople.table.edit.buttons.edit": "Muokkaa \"{{name}}\"", + // "admin.access-control.epeople.table.edit.buttons.edit-disabled": "You are not authorized to edit this group", + "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Sinulla ei ole valtuuksia muokata tätä ryhmää", + // "admin.access-control.epeople.table.edit.buttons.remove": "Delete \"{{name}}\"", "admin.access-control.epeople.table.edit.buttons.remove": "Poista \"{{name}}\"", @@ -382,6 +420,9 @@ // "admin.access-control.epeople.form.requireCertificate": "Requires certificate", "admin.access-control.epeople.form.requireCertificate": "Vaatii sertifikaatin", + // "admin.access-control.epeople.form.return": "Back", + "admin.access-control.epeople.form.return": "Paluu", + // "admin.access-control.epeople.form.notification.created.success": "Successfully created EPerson \"{{name}}\"", "admin.access-control.epeople.form.notification.created.success": "Käyttäjä \"{{name}}\" luotu", @@ -415,6 +456,9 @@ // "admin.access-control.epeople.form.table.name": "Name", "admin.access-control.epeople.form.table.name": "Nimi", + // "admin.access-control.epeople.form.table.collectionOrCommunity": "Collection/Community", + "admin.access-control.epeople.form.table.collectionOrCommunity": "Kokoelma/Yhteisö", + // "admin.access-control.epeople.form.memberOfNoGroups": "This EPerson is not a member of any groups", "admin.access-control.epeople.form.memberOfNoGroups": "Tämä käyttäjä ei kuulu mihinkään ryhmään", @@ -427,16 +471,23 @@ // "admin.access-control.epeople.notification.deleted.success": "Successfully deleted EPerson: \"{{name}}\"", "admin.access-control.epeople.notification.deleted.success": "Käyttäjä poistettu: \"{{name}}\"", + // "admin.access-control.groups.title": "Groups", + "admin.access-control.groups.title": "Ryhmät", + // "admin.access-control.groups.breadcrumbs": "Groups", + "admin.access-control.groups.breadcrumbs": "Ryhmät", - // "admin.access-control.groups.title": "DSpace Angular :: Groups", - "admin.access-control.groups.title": "DSpace Angular :: Ryhmät", + // "admin.access-control.groups.singleGroup.breadcrumbs": "Edit Group", + // "admin.access-control.groups.singleGroup.breadcrumbs": "Ryhmän muokkaus", - // "admin.access-control.groups.title.singleGroup": "DSpace Angular :: Edit Group", - "admin.access-control.groups.title.singleGroup": "DSpace Angular :: Ryhmän muokkaus", + // "admin.access-control.groups.title.singleGroup": "Edit Group", + "admin.access-control.groups.title.singleGroup": "Ryhmän muokkaus", - // "admin.access-control.groups.title.addGroup": "DSpace Angular :: New Group", - "admin.access-control.groups.title.addGroup": "DSpace Angular :: Uusi ryhmä", + // "admin.access-control.groups.title.addGroup": "New Group", + "admin.access-control.groups.title.addGroup": "Uusi ryhmä", + + // "admin.access-control.groups.addGroup.breadcrumbs": "New Group", + "admin.access-control.groups.addGroup.breadcrumbs": "uusi ryhmä", // "admin.access-control.groups.head": "Groups", "admin.access-control.groups.head": "Ryhmät", @@ -453,12 +504,18 @@ // "admin.access-control.groups.search.button": "Search", "admin.access-control.groups.search.button": "Hae", + // "admin.access-control.groups.search.placeholder": "Search groups...", + "admin.access-control.groups.search.placeholder": "Hae ryhmiä...", + // "admin.access-control.groups.table.id": "ID", "admin.access-control.groups.table.id": "ID", // "admin.access-control.groups.table.name": "Name", "admin.access-control.groups.table.name": "Nimi", + // "admin.access-control.groups.table.collectionOrCommunity": "Collection/Community", + "admin.access-control.groups.table.collectionOrCommunity": "Kokoelma/Yhteisö", + // "admin.access-control.groups.table.members": "Members", "admin.access-control.groups.table.members": "Jäsenet", @@ -483,8 +540,6 @@ // "admin.access-control.groups.notification.deleted.failure.content": "Cause: \"{{cause}}\"", "admin.access-control.groups.notification.deleted.failure.content": "Syy: \"{{cause}}\"", - - // "admin.access-control.groups.form.alert.permanent": "This group is permanent, so it can't be edited or deleted. You can still add and remove group members using this page.", "admin.access-control.groups.form.alert.permanent": "Tämä ryhmä on pysyvä, eikä sitä voi muokata tai poistaa. Ryhmään voi kuitenkin lisätä ja poistaa jäseniä tällä sivulla.", @@ -500,6 +555,9 @@ // "admin.access-control.groups.form.groupName": "Group name", "admin.access-control.groups.form.groupName": "Ryhmän nimi", + // "admin.access-control.groups.form.groupCommunity": "Community or Collection", + "admin.access-control.groups.form.groupCommunity": "Yhteisö tai kokoelma", + // "admin.access-control.groups.form.groupDescription": "Description", "admin.access-control.groups.form.groupDescription": "Kuvaus", @@ -572,6 +630,15 @@ // "admin.access-control.groups.form.members-list.table.name": "Name", "admin.access-control.groups.form.members-list.table.name": "Nimi", + // "admin.access-control.groups.form.members-list.table.identity": "Identity", + "admin.access-control.groups.form.members-list.table.identity": "Identiteetti", + + // "admin.access-control.groups.form.members-list.table.email": "Email", + "admin.access-control.groups.form.members-list.table.email": "Sähköpostiosoite", + + // "admin.access-control.groups.form.members-list.table.netid": "NetID", + "admin.access-control.groups.form.members-list.table.netid": "Käyttäjätunnus", + // "admin.access-control.groups.form.members-list.table.edit": "Remove / Add", "admin.access-control.groups.form.members-list.table.edit": "Poista / Lisää", @@ -626,6 +693,9 @@ // "admin.access-control.groups.form.subgroups-list.table.name": "Name", "admin.access-control.groups.form.subgroups-list.table.name": "Nimi", + // "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Collection/Community", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Kokoelma/Yhteisö", + // "admin.access-control.groups.form.subgroups-list.table.edit": "Remove / Add", "admin.access-control.groups.form.subgroups-list.table.edit": "Poista / Lisää", @@ -662,10 +732,18 @@ // "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "No subgroups in group yet.", "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Ryhmällä ei ole alaryhmiä.", - // "admin.access-control.groups.form.return": "Return to groups", - "admin.access-control.groups.form.return": "Palaa ryhmiin", + // "admin.access-control.groups.form.return": "Back", + "admin.access-control.groups.form.return": "Paluu", + // "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": "Tällä sivulla voit muokata ryhmän ominaisuuksia ja jäseniä. Yläosassa voit muokata ryhmän nimeä ja kuvausta, paitsi jos kyseessä on kokoelman tai yhteisön ylläpitäjäryhmä, jolloin ryhmän nimi ja kuvaus luodaan automaattisesti, eikä niitä voi muokata. Muissa osioissa voit muokata ryhmän jäsenyyttä. Katso lisätietoja wiki-sivulta (https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", + // "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": "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.search.breadcrumbs": "Administrative Search", "admin.search.breadcrumbs": "Ylläpitäjän haku", @@ -682,17 +760,17 @@ // "admin.search.item.edit": "Edit", "admin.search.item.edit": "Muokkaa", - // "admin.search.item.make-private": "Make Private", + // "admin.search.item.make-private": "Make non-discoverable", "admin.search.item.make-private": "Tee yksityiseksi", - // "admin.search.item.make-public": "Make Public", + // "admin.search.item.make-public": "Make discoverable", "admin.search.item.make-public": "Tee julkiseksi", // "admin.search.item.move": "Move", "admin.search.item.move": "Siirrä", // "admin.search.item.reinstate": "Reinstate", - "admin.search.item.reinstate": "Palauta käyttöön", + "admin.search.item.reinstate": "Palauta", // "admin.search.item.withdraw": "Withdraw", "admin.search.item.withdraw": "Poista käytöstä", @@ -703,9 +781,6 @@ // "administrativeView.search.results.head": "Administrative Search", "administrativeView.search.results.head": "Ylläpitäjän haku", - - - // "admin.workflow.breadcrumbs": "Administer Workflow", "admin.workflow.breadcrumbs": "Hallinnoi työnkulkua", @@ -715,43 +790,191 @@ // "admin.workflow.item.workflow": "Workflow", "admin.workflow.item.workflow": "Työnkulku", + // "admin.workflow.item.workspace": "Workspace", + "admin.workflow.item.workspace": "Työtila", + // "admin.workflow.item.delete": "Delete", "admin.workflow.item.delete": "Poista", // "admin.workflow.item.send-back": "Send back", "admin.workflow.item.send-back": "Lähetä takaisin", + // "admin.workflow.item.policies": "Policies", + "admin.workflow.item.policies": "Käytännöt", + // "admin.workflow.item.supervision": "Supervision", + "admin.workflow.item.supervision": "Valvonta", // "admin.metadata-import.breadcrumbs": "Import Metadata", "admin.metadata-import.breadcrumbs": "Importoi metadata", + // "admin.batch-import.breadcrumbs": "Import Batch", + "admin.batch-import.breadcrumbs": "Importoi erä", + // "admin.metadata-import.title": "Import Metadata", "admin.metadata-import.title": "Importoi metadata", + // "admin.batch-import.title": "Import Batch", + "admin.batch-import.title": "Importoi erä", + // "admin.metadata-import.page.header": "Import Metadata", "admin.metadata-import.page.header": "Importoi metadata", + // "admin.batch-import.page.header": "Import Batch", + "admin.batch-import.page.header": "Importoi erä", + // "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": "Voit pudottaa tähän tai selata CSV-tiedostoja, joilla voit tehdä metadatatoimintoja usealle tietueelle", + // "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": "Valitse kokoelma, johon tietueet importoidaan. Sen jälkeen pudota tai selaa esiin importoitavat tietueet sisältävä Simple Archive Format (SAF) -ZIP-tiedosto.", + + // "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", + "admin.batch-import.page.toggle.help": "Importoinnin voi tehdä joko lataamalla tiedoston tai URL-osoitteen kautta. Käytä yllä olevaa kytkintä valitaksesi syöttötavan.", + // "admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import", "admin.metadata-import.page.dropMsg": "Pudota CSV-metadata importoimista varten", + // "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", + "admin.batch-import.page.dropMsg": "Pudota erän ZIP-tiedosto importoimista varten", + // "admin.metadata-import.page.dropMsgReplace": "Drop to replace the metadata CSV to import", "admin.metadata-import.page.dropMsgReplace": "Pudota korvataksesi importoitava CSV-metadata", - // "admin.metadata-import.page.button.return": "Return", + // "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", + "admin.batch-import.page.dropMsgReplace": "Pudota korvataksesi importoitava erän ZIP-tiedosto", + + // "admin.metadata-import.page.button.return": "Back", "admin.metadata-import.page.button.return": "Paluu", // "admin.metadata-import.page.button.proceed": "Proceed", "admin.metadata-import.page.button.proceed": "Jatka", + // "admin.metadata-import.page.button.select-collection": "Select Collection", + "admin.metadata-import.page.button.select-collection": "Valitse kokoelma", + // "admin.metadata-import.page.error.addFile": "Select file first!", "admin.metadata-import.page.error.addFile": "Valitse ensin tiedosto!", + // "admin.metadata-import.page.error.addFileUrl": "Insert file url first!", + "admin.metadata-import.page.error.addFileUrl": "Syötä tiedoston URL ensin!", + + // "admin.batch-import.page.error.addFile": "Select Zip file first!", + "admin.batch-import.page.error.addFile": "Valitse ZIP-tiedosto ensin!", + + // "admin.metadata-import.page.toggle.upload": "Upload", + "admin.metadata-import.page.toggle.upload": "Lataa", + + // "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.toggle.url": "URL", + + // "admin.metadata-import.page.urlMsg": "Insert the batch ZIP url to import", + "admin.metadata-import.page.urlMsg": "Syötä erän ZIP-URL importoitavaksi", + + // "admin.metadata-import.page.validateOnly": "Validate Only", + "admin.metadata-import.page.validateOnly": "Pelkkä validointi", + + // "admin.metadata-import.page.validateOnly.hint": "When selected, the uploaded CSV will be validated. You will receive a report of detected changes, but no changes will be saved.", + "admin.metadata-import.page.validateOnly.hint": "Kun tämä valitaan, ladattu CSV-tiedosto validoidaan. Saat raportin havaituista muutoksista, mutta muutoksia ei tallenneta.", + + // "advanced-workflow-action.rating.form.rating.label": "Rating", + "advanced-workflow-action.rating.form.rating.label": "Arviointi", + + // "advanced-workflow-action.rating.form.rating.error": "You must rate the item", + "advanced-workflow-action.rating.form.rating.error": "Sinun on arvioitava tietua", + + // "advanced-workflow-action.rating.form.review.label": "Review", + "advanced-workflow-action.rating.form.review.label": "Tarkasta", + + // "advanced-workflow-action.rating.form.review.error": "You must enter a review to submit this rating", + "advanced-workflow-action.rating.form.review.error": "Sinun on annettava arvostelu lähettääksesi tämän arvioinnin", + + // "advanced-workflow-action.rating.description": "Please select a rating below", + "advanced-workflow-action.rating.description": "Valitse arviointi alapuolelta", + + // "advanced-workflow-action.rating.description-requiredDescription": "Please select a rating below and also add a review", + "advanced-workflow-action.rating.description-requiredDescription": "Valitse arviointi alapuolelta. Lisää myös arvostelu", + + // "advanced-workflow-action.select-reviewer.description-single": "Please select a single reviewer below before submitting", + "advanced-workflow-action.select-reviewer.description-single": "Valitse yksi tarkastaja alapuolelta ennen lähettämistä", + + // "advanced-workflow-action.select-reviewer.description-multiple": "Please select one or more reviewers below before submitting", + "advanced-workflow-action.select-reviewer.description-multiple": "Valitse yksi tai useampi tarkastaja alapuolelta ennen lähettämistä", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "Käyttäjät", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Add EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Lisää käyttäjiä", + + // "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": "Selaa kaikkia", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Current Members", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Nykyiset jäsenet", + // "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": "Metadata", + + // "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": "Sähköpostiosoite (oikea)", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Search", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Hae", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Name", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nimi", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identity", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identiteetti", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Email", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Sähköpostiosoite", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "Käyttäjätunnus", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remove / Add", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Poista / Lisää", + + // "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": "Poista jäsen nimellä \"{{name}}\"", + + // "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": "Jäsen lisätty: \"{{name}}\"", + + // "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": "Jäsenen lisäys epäonnistui: \"{{name}}\"", + + // "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": "Jäsen poistettu: \"{{name}}\"", + + // "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": "Jäsenen poisto epäonnistui: \"{{name}}\"", + + // "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": "Lisää jäsen nimellä \"{{name}}\"", + + // "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": "Ei aktiivista ryhmää, syötä ensin nimi", + + // "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": "Ryhmässä ei ole vielä jäseniä, hae ja lisää.", + + // "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": "Haku ei palauttanut käyttäjiä", + + // "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "No reviewer selected.", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Ei valittua tarkastajaa.", + + // "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": "Kun tämä valitaan, ladattu ZIP-tiedosto validoidaan. the uploaded ZIP will be validated. Saat raportin havaituista muutoksista, mutta muutoksia ei tallenneta.", + + // "admin.batch-import.page.remove": "remove", + "admin.batch-import.page.remove": "poista", // "auth.errors.invalid-user": "Invalid email address or password.", "auth.errors.invalid-user": "Virheellinen sähköpostiosoite tai salasana.", @@ -759,7 +982,23 @@ // "auth.messages.expired": "Your session has expired. Please log in again.", "auth.messages.expired": "Istuntosi on vanhentunut. Kirjaudu uudelleen.", + // "auth.messages.token-refresh-failed": "Refreshing your session token failed. Please log in again.", + "auth.messages.token-refresh-failed": "Istuntotunnisteen päivittäminen epäonnistui. Kirjaudu uudelleen.", + + // "bitstream.download.page": "Now downloading {{bitstream}}...", + "bitstream.download.page": "Nyt ladataan {{bitstream}}...", + + // "bitstream.download.page.back": "Back", + "bitstream.download.page.back": "Paluu", + + // "bitstream.edit.authorizations.link": "Edit bitstream's Policies", + "bitstream.edit.authorizations.link": "Muokkaa tiedostokäytäntöjä", + + // "bitstream.edit.authorizations.title": "Edit bitstream's Policies", + "bitstream.edit.authorizations.title": "Muokkaa tiedostokäytäntöjä", + // "bitstream.edit.return": "Back", + "bitstream.edit.return": "Paluu", // "bitstream.edit.bitstream": "Bitstream: ", "bitstream.edit.bitstream": "Tiedosto: ", @@ -803,6 +1042,33 @@ // "bitstream.edit.notifications.error.format.title": "An error occurred saving the bitstream's format", "bitstream.edit.notifications.error.format.title": "Virhe tallennettaessa tiedoston formaattia", + // "bitstream.edit.notifications.error.primaryBitstream.title": "An error occurred saving the primary bitstream", + "bitstream.edit.notifications.error.primaryBitstream.title": "Virhe tallennettaessa päätiedostoa", + + // "bitstream.edit.form.iiifLabel.label": "IIIF Label", + "bitstream.edit.form.iiifLabel.label": "IIIF-nimike", + + // "bitstream.edit.form.iiifLabel.hint": "Canvas label for this image. If not provided default label will be used.", + "bitstream.edit.form.iiifLabel.hint": "Kuvan canvasin nimike. Ellei nimikettä anneta, käytetään oletusnimikettä.", + + // "bitstream.edit.form.iiifToc.label": "IIIF Table of Contents", + "bitstream.edit.form.iiifToc.label": "IIIF-sisällysluettelo", + + // "bitstream.edit.form.iiifToc.hint": "Adding text here makes this the start of a new table of contents range.", + "bitstream.edit.form.iiifToc.hint": "Jos tekstiä lisätään tähän, tästä alkaa uusi sisällysluetteloaihe.", + + // "bitstream.edit.form.iiifWidth.label": "IIIF Canvas Width", + "bitstream.edit.form.iiifWidth.label": "IIIF-canvasin leveys", + + // "bitstream.edit.form.iiifWidth.hint": "The canvas width should usually match the image width.", + "bitstream.edit.form.iiifWidth.hint": "Canvasin leveyden tulee vastata kuvan leveyttä.", + + // "bitstream.edit.form.iiifHeight.label": "IIIF Canvas Height", + "bitstream.edit.form.iiifHeight.label": "IIIF-canvasin korkeus", + + // "bitstream.edit.form.iiifHeight.hint": "The canvas height should usually match the image height.", + "bitstream.edit.form.iiifHeight.hint": "Canvasin korkeuden tulee vastata kuvan korkeutta.", + // "bitstream.edit.notifications.saved.content": "Your changes to this bitstream were saved.", "bitstream.edit.notifications.saved.content": "Muutokset tiedostoon on tallennettu.", @@ -812,7 +1078,65 @@ // "bitstream.edit.title": "Edit bitstream", "bitstream.edit.title": "Muokkaa tiedostoa", + // "bitstream-request-a-copy.alert.canDownload1": "You already have access to this file. If you want to download the file, click ", + "bitstream-request-a-copy.alert.canDownload1": "Sinulla on jo pääsy tähän tiedostoon. Jos haluat ladata tiedoston, napsauta ", + + // "bitstream-request-a-copy.alert.canDownload2": "here", + "bitstream-request-a-copy.alert.canDownload2": "tässä", + + // "bitstream-request-a-copy.header": "Request a copy of the file", + "bitstream-request-a-copy.header": "Pyydä tiedostokopiota", + + // "bitstream-request-a-copy.intro": "Enter the following information to request a copy for the following item: ", + "bitstream-request-a-copy.intro": "Syötä seuraavat tiedot pyytääksesi kopiota tietueesta: ", + + // "bitstream-request-a-copy.intro.bitstream.one": "Requesting the following file: ", + "bitstream-request-a-copy.intro.bitstream.one": "Pyydetään seuraavaa tiedostoa: ", + + // "bitstream-request-a-copy.intro.bitstream.all": "Requesting all files. ", + "bitstream-request-a-copy.intro.bitstream.all": "Pyydetään kaikkia tiedostoja. ", + + // "bitstream-request-a-copy.name.label": "Name *", + "bitstream-request-a-copy.name.label": "Nimi *", + + // "bitstream-request-a-copy.name.error": "The name is required", + "bitstream-request-a-copy.name.error": "Nimi on pakollinen tieto", + + // "bitstream-request-a-copy.email.label": "Your e-mail address *", + "bitstream-request-a-copy.email.label": "Sähköpostiosoite *", + + // "bitstream-request-a-copy.email.hint": "This email address is used for sending the file.", + "bitstream-request-a-copy.email.hint": "Tätä sähköpostiosoitetta käytetään tiedostoa lähetettäessä.", + + // "bitstream-request-a-copy.email.error": "Please enter a valid email address.", + "bitstream-request-a-copy.email.error": "Syötä toimiva sähköpostiosoite.", + + // "bitstream-request-a-copy.allfiles.label": "Files", + "bitstream-request-a-copy.allfiles.label": "Tiedostot", + + // "bitstream-request-a-copy.files-all-false.label": "Only the requested file", + "bitstream-request-a-copy.files-all-false.label": "Vain pyydetty tiedosto", + + // "bitstream-request-a-copy.files-all-true.label": "All files (of this item) in restricted access", + "bitstream-request-a-copy.files-all-true.label": "Kaikilla (tämän tietueen) tiedostoilla on rajattu käyttöoikeus", + + // "bitstream-request-a-copy.message.label": "Message", + "bitstream-request-a-copy.message.label": "Viesti", + + // "bitstream-request-a-copy.return": "Back", + "bitstream-request-a-copy.return": "Paluu", + // "bitstream-request-a-copy.submit": "Request copy", + "bitstream-request-a-copy.submit": "Pyydä kopio", + + // "bitstream-request-a-copy.submit.success": "The item request was submitted successfully.", + "bitstream-request-a-copy.submit.success": "Tietuepyyntö on lähetetty.", + + // "bitstream-request-a-copy.submit.error": "Something went wrong with submitting the item request.", + "bitstream-request-a-copy.submit.error": "Tapahtui virhe lähetettäessä tietuepyyntöä", + + // "browse.back.all-results": "All browse results", + "browse.back.all-results": "Kaikki selaustulokset", // "browse.comcol.by.author": "By Author", "browse.comcol.by.author": "Tekijän mukaan", @@ -823,6 +1147,9 @@ // "browse.comcol.by.subject": "By Subject", "browse.comcol.by.subject": "Asiasanan mukaan", + // "browse.comcol.by.srsc": "By Subject Category", + "browse.comcol.by.srsc": "Aihekategorian mukaan", + // "browse.comcol.by.title": "By Title", "browse.comcol.by.title": "Nimekkeen mukaan", @@ -853,17 +1180,35 @@ // "browse.metadata.subject.breadcrumbs": "Browse by Subject", "browse.metadata.subject.breadcrumbs": "Selaa asiasanan mukaan", + // "browse.metadata.srsc.breadcrumbs": "Browse by Subject Category", + "browse.metadata.srsc.breadcrumbs": "Selaa aihekategorian luokan mukaan", + // "browse.metadata.title.breadcrumbs": "Browse by Title", "browse.metadata.title.breadcrumbs": "Selaa nimekkeen mukaan", + // "pagination.next.button": "Next", + "pagination.next.button": "Seuraava", + + // "pagination.previous.button": "Previous", + "pagination.previous.button": "Edellinen", + + // "pagination.next.button.disabled.tooltip": "No more pages of results", + "pagination.next.button.disabled.tooltip": "Ei enempää tulossivuja", + + // "browse.startsWith": ", starting with {{ startsWith }}", + "browse.startsWith": ", alkaa kirjaimella {{ startsWith }}", + // "browse.startsWith.choose_start": "(Choose start)", "browse.startsWith.choose_start": "(Valitse alku)", // "browse.startsWith.choose_year": "(Choose year)", "browse.startsWith.choose_year": "(Valitse vuosi)", - // "browse.startsWith.jump": "Jump to a point in the index:", - "browse.startsWith.jump": "Hyppää indeksin kohtaan:", + // "browse.startsWith.choose_year.label": "Choose the issue year", + "browse.startsWith.choose_year.label": "Valitse julkaisuvuosi", + + // "browse.startsWith.jump": "Filter results by year or month", + "browse.startsWith.jump": "Suodata tulokset vuoden tai kuukauden mukaan", // "browse.startsWith.months.april": "April", "browse.startsWith.months.april": "Huhtikuu", @@ -895,6 +1240,9 @@ // "browse.startsWith.months.none": "(Choose month)", "browse.startsWith.months.none": "(Valitse kuukausi)", + // "browse.startsWith.months.none.label": "Choose the issue month", + "browse.startsWith.months.none.label": "Valitse julkaisukuukausi", + // "browse.startsWith.months.november": "November", "browse.startsWith.months.november": "Marraskuu", @@ -904,23 +1252,44 @@ // "browse.startsWith.months.september": "September", "browse.startsWith.months.september": "Syyskuu", - // "browse.startsWith.submit": "Go", - "browse.startsWith.submit": "Ok", + // "browse.startsWith.submit": "Browse", + "browse.startsWith.submit": "Selaa", + + // "browse.startsWith.type_date": "Filter results by date", + "browse.startsWith.type_date": "Suodata tulokset päivämäärän mukaan", - // "browse.startsWith.type_date": "Or type in a date (year-month):", - "browse.startsWith.type_date": "Tai anna päiväys (vuosi-kuukausi):", + // "browse.startsWith.type_date.label": "Or type in a date (year-month) and click on the Browse button", + "browse.startsWith.type_date.label": "Tai syötä päiväys (vuosi-kuukausi) ja napsauta Selaa-painiketta", - // "browse.startsWith.type_text": "Or enter first few letters:", - "browse.startsWith.type_text": "Tai anna muutama alkukirjain:", + // "browse.startsWith.type_text": "Filter results by typing the first few letters", + "browse.startsWith.type_text": "Suodata tuloksia antamalla muutama alkukirjain", - // "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}", - "browse.title": "Selataan {{ collection }}-kokoelmaa {{ field }}-kentän arvolla {{ value }}", + // "browse.startsWith.input": "Filter", + "browse.startsWith.input": "Suodata", + // "browse.taxonomy.button": "Browse", + "browse.taxonomy.button": "Selaa", + + // "browse.title": "Browsing {{ collection }} by {{ field }}{{ startsWith }} {{ value }}", + "browse.title": "Selataan {{ collection }}-kokoelmaa {{ field }}{{ startsWith }}-kentän arvolla {{ value }}", + + // "browse.title.page": "Browsing {{ collection }} by {{ field }} {{ value }}", + "browse.title.page": "Selataan {{ collection }}-kokoelmaa {{ field }}-kentän arvolla {{ value }}", + + // "search.browse.item-back": "Back to Results", + "search.browse.item-back": "Paluu tuloksiin", // "chips.remove": "Remove chip", "chips.remove": "Poista chip", + // "claimed-approved-search-result-list-element.title": "Approved", + "claimed-approved-search-result-list-element.title": "Hyväksytty", + + // "claimed-declined-search-result-list-element.title": "Rejected, sent back to submitter", + "claimed-declined-search-result-list-element.title": "Hylätty, lähetetty takaisin tallentajalle", + // "claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow", + "claimed-declined-task-search-result-list-element.title": "Kieltäydytty, lähetetty takaisin päätarkastajan työnkulkuun", // "collection.create.head": "Create a Collection", "collection.create.head": "Luo kokoelma", @@ -940,6 +1309,9 @@ // "collection.delete.confirm": "Confirm", "collection.delete.confirm": "Vahvista", + // "collection.delete.processing": "Deleting", + "collection.delete.processing": "Poistetaan", + // "collection.delete.head": "Delete Collection", "collection.delete.head": "Poista kokoelma", @@ -952,8 +1324,6 @@ // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", "collection.delete.text": "Haluatko varmasti poistaa kokoelman \"{{ dso }}\"", - - // "collection.edit.delete": "Delete this collection", "collection.edit.delete": "Poista kokoelma", @@ -963,8 +1333,6 @@ // "collection.edit.breadcrumbs": "Edit Collection", "collection.edit.breadcrumbs": "Muokkaa kokoelmaa", - - // "collection.edit.tabs.mapper.head": "Item Mapper", "collection.edit.tabs.mapper.head": "Tietueliitosväline", @@ -1016,13 +1384,20 @@ // "collection.edit.item-mapper.remove": "Remove selected item mappings", "collection.edit.item-mapper.remove": "Poista valitut tietueliitokset", + // "collection.edit.item-mapper.search-form.placeholder": "Search items...", + "collection.edit.item-mapper.search-form.placeholder": "Hae tietueita...", + // "collection.edit.item-mapper.tabs.browse": "Browse mapped items", "collection.edit.item-mapper.tabs.browse": "Selaa liitettyjä tietueita", // "collection.edit.item-mapper.tabs.map": "Map new items", "collection.edit.item-mapper.tabs.map": "Liitä uusia tietueita", + // "collection.edit.logo.delete.title": "Delete logo", + "collection.edit.logo.delete.title": "Poista logo", + // "collection.edit.logo.delete-undo.title": "Undo delete", + "collection.edit.logo.delete-undo.title": "Kumoa poisto", // "collection.edit.logo.label": "Collection logo", "collection.edit.logo.label": "Kokoelman logo", @@ -1045,15 +1420,11 @@ // "collection.edit.logo.upload": "Drop a Collection Logo to upload", "collection.edit.logo.upload": "Pudota kokoelman logo ladattavaksi", - - // "collection.edit.notifications.success": "Successfully edited the Collection", "collection.edit.notifications.success": "Kokoelman muokkaus onnistui", - // "collection.edit.return": "Return", - "collection.edit.return": "Palaa", - - + // "collection.edit.return": "Back", + "collection.edit.return": "Paluu", // "collection.edit.tabs.curate.head": "Curate", "collection.edit.tabs.curate.head": "Kuratoi", @@ -1067,6 +1438,15 @@ // "collection.edit.tabs.authorizations.title": "Collection Edit - Authorizations", "collection.edit.tabs.authorizations.title": "Kokoelman muokkaus - Käyttöoikeudet", + // "collection.edit.item.authorizations.load-bundle-button": "Load more bundles", + "collection.edit.item.authorizations.load-bundle-button": "Lataa lisää nippuja", + + // "collection.edit.item.authorizations.load-more-button": "Load more", + "collection.edit.item.authorizations.load-more-button": "Lataa lisää", + + // "collection.edit.item.authorizations.show-bitstreams-button": "Show bitstream policies for bundle", + "collection.edit.item.authorizations.show-bitstreams-button": "Näytä nipun tiedostokäytännöt", + // "collection.edit.tabs.metadata.head": "Edit Metadata", "collection.edit.tabs.metadata.head": "Muokkaa metadataa", @@ -1115,7 +1495,7 @@ // "collection.edit.tabs.source.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", "collection.edit.tabs.source.notifications.discarded.content": "Muutokset hylätty. Valitse 'Kumoa' palauttaaksesi muutokset", - // "collection.edit.tabs.source.notifications.discarded.title": "Changed discarded", + // "collection.edit.tabs.source.notifications.discarded.title": "Changes discarded", "collection.edit.tabs.source.notifications.discarded.title": "Muutokset hylätty", // "collection.edit.tabs.source.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", @@ -1133,8 +1513,6 @@ // "collection.edit.tabs.source.title": "Collection Edit - Content Source", "collection.edit.tabs.source.title": "Kokoelman muokkaus - Sisältölähde", - - // "collection.edit.template.add-button": "Add", "collection.edit.template.add-button": "Lisää", @@ -1150,12 +1528,18 @@ // "collection.edit.template.edit-button": "Edit", "collection.edit.template.edit-button": "Muokkaa", + // "collection.edit.template.error": "An error occurred retrieving the template item", + "collection.edit.template.error": "Virhe noudettaessa mallitietuetta", + // "collection.edit.template.head": "Edit Template Item for Collection \"{{ collection }}\"", "collection.edit.template.head": "Muokkaa kokoelman \"{{ collection }}\" mallitietuetta", // "collection.edit.template.label": "Template item", "collection.edit.template.label": "Mallitietue", + // "collection.edit.template.loading": "Loading template item...", + "collection.edit.template.loading": "Ladataan mallitietuetta...", + // "collection.edit.template.notifications.delete.error": "Failed to delete the item template", "collection.edit.template.notifications.delete.error": "Tietueen mallipohjan poisto epäonnistui", @@ -1165,8 +1549,6 @@ // "collection.edit.template.title": "Edit Template Item", "collection.edit.template.title": "Muokkaa mallitietuetta", - - // "collection.form.abstract": "Short Description", "collection.form.abstract": "Lyhyt kuvaus", @@ -1191,13 +1573,12 @@ // "collection.form.title": "Name", "collection.form.title": "Nimi", - + // "collection.form.entityType": "Entity Type", + "collection.form.entityType": "Entiteettityyppi", // "collection.listelement.badge": "Collection", "collection.listelement.badge": "Kokoelma", - - // "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.head": "Viimeksi lisätyt", @@ -1216,8 +1597,6 @@ // "collection.page.news": "News", "collection.page.news": "Uutiset", - - // "collection.select.confirm": "Confirm selected", "collection.select.confirm": "Vahvista valinta", @@ -1227,7 +1606,74 @@ // "collection.select.table.title": "Title", "collection.select.table.title": "Nimeke", + // "collection.source.controls.head": "Harvest Controls", + "collection.source.controls.head": "Harvointikontrollit", + + // "collection.source.controls.test.submit.error": "Something went wrong with initiating the testing of the settings", + "collection.source.controls.test.submit.error": "Virhe asetusten testaamisen valmistelussa", + + // "collection.source.controls.test.failed": "The script to test the settings has failed", + "collection.source.controls.test.failed": "Asetusten testausskripti epäonnistui", + + // "collection.source.controls.test.completed": "The script to test the settings has successfully finished", + "collection.source.controls.test.completed": "Asetusten testausskripti suoritettu", + + // "collection.source.controls.test.submit": "Test configuration", + "collection.source.controls.test.submit": "Testikonfiguraatio", + + // "collection.source.controls.test.running": "Testing configuration...", + "collection.source.controls.test.running": "Testataan konfiguraatiota...", + + // "collection.source.controls.import.submit.success": "The import has been successfully initiated", + "collection.source.controls.import.submit.success": "Importointi valmisteltu", + + // "collection.source.controls.import.submit.error": "Something went wrong with initiating the import", + "collection.source.controls.import.submit.error": "Virhe importoinnin valmistelussa", + + // "collection.source.controls.import.submit": "Import now", + "collection.source.controls.import.submit": "Importoi nyt", + // "collection.source.controls.import.running": "Importing...", + "collection.source.controls.import.running": "Importoidaan...", + + // "collection.source.controls.import.failed": "An error occurred during the import", + "collection.source.controls.import.failed": "Virhe importoinnissa", + + // "collection.source.controls.import.completed": "The import completed", + "collection.source.controls.import.completed": "Importointi valmis", + + // "collection.source.controls.reset.submit.success": "The reset and reimport has been successfully initiated", + "collection.source.controls.reset.submit.success": "Nollaus ja uudelleenimportointi valmisteltu", + + // "collection.source.controls.reset.submit.error": "Something went wrong with initiating the reset and reimport", + "collection.source.controls.reset.submit.error": "Virhe nollauksen ja uudelleenimportoinnin valmistelussa", + + // "collection.source.controls.reset.failed": "An error occurred during the reset and reimport", + "collection.source.controls.reset.failed": "Virhe nollauksessa ja uudelleenimportoinnissa", + + // "collection.source.controls.reset.completed": "The reset and reimport completed", + "collection.source.controls.reset.completed": "Nollaus ja uudelleenimportointi valmis", + + // "collection.source.controls.reset.submit": "Reset and reimport", + "collection.source.controls.reset.submit": "Nollaus ja uudelleenimportointi", + + // "collection.source.controls.reset.running": "Resetting and reimporting...", + "collection.source.controls.reset.running": "Nollataan ja uudelleenimportoidaan...", + + // "collection.source.controls.harvest.status": "Harvest status:", + "collection.source.controls.harvest.status": "Harvestoinnin tila:", + + // "collection.source.controls.harvest.start": "Harvest start time:", + "collection.source.controls.harvest.start": "Harvestoinnin aloitusaika:", + + // "collection.source.controls.harvest.last": "Last time harvested:", + "collection.source.controls.harvest.last": "Harvestoitu viimeksi::", + + // "collection.source.controls.harvest.message": "Harvest info:", + "collection.source.controls.harvest.message": "Harvestointitiedot:", + + // "collection.source.controls.harvest.no-information": "N/A", + "collection.source.controls.harvest.no-information": "Ei saatavilla", // "collection.source.update.notifications.error.content": "The provided settings have been tested and didn't work.", "collection.source.update.notifications.error.content": "Annetut asetukset on testattu. Ne eivät toimi.", @@ -1235,10 +1681,11 @@ // "collection.source.update.notifications.error.title": "Server Error", "collection.source.update.notifications.error.title": "Palvelinvirhe", + // "communityList.breadcrumbs": "Community List", + "communityList.breadcrumbs": "Yhteisöluettelo", - - // "communityList.tabTitle": "DSpace - Community List", - "communityList.tabTitle": "DSpace - Yhteisöluettelo", + // "communityList.tabTitle": "Community List", + "communityList.tabTitle": "Yhteisöluettelo", // "communityList.title": "List of Communities", "communityList.title": "Luettelo yhteisöistä", @@ -1246,8 +1693,6 @@ // "communityList.showMore": "Show More", "communityList.showMore": "Näytä lisää", - - // "community.create.head": "Create a Community", "community.create.head": "Luo yhteisö", @@ -1266,6 +1711,9 @@ // "community.delete.confirm": "Confirm", "community.delete.confirm": "Vahvista", + // "community.delete.processing": "Deleting...", + "community.delete.processing": "Poistetaan...", + // "community.delete.head": "Delete Community", "community.delete.head": "Poista yhteisö", @@ -1287,6 +1735,11 @@ // "community.edit.breadcrumbs": "Edit Community", "community.edit.breadcrumbs": "Muokkaa yhteisöä", + // "community.edit.logo.delete.title": "Delete logo", + "community.edit.logo.delete.title": "Poista logo", + + // "community.edit.logo.delete-undo.title": "Undo delete", + "community.edit.logo.delete-undo.title": "Kumoa poisto", // "community.edit.logo.label": "Community logo", "community.edit.logo.label": "Yhteisön logo", @@ -1309,8 +1762,6 @@ // "community.edit.logo.upload": "Drop a Community Logo to upload", "community.edit.logo.upload": "Pudota yhteisön logo ladattavaksi", - - // "community.edit.notifications.success": "Successfully edited the Community", "community.edit.notifications.success": "Yhteisön muokkaus onnistui", @@ -1320,10 +1771,8 @@ // "community.edit.notifications.error": "An error occured while editing the Community", "community.edit.notifications.error": "Virhe muokattaessa yhteisöä", - // "community.edit.return": "Return", - "community.edit.return": "Palaa", - - + // "community.edit.return": "Back", + "community.edit.return": "Paluu", // "community.edit.tabs.curate.head": "Curate", "community.edit.tabs.curate.head": "Kuratoi", @@ -1349,25 +1798,26 @@ // "community.edit.tabs.authorizations.title": "Community Edit - Authorizations", "community.edit.tabs.authorizations.title": "Yhteisön muokkaus - Käyttöoikeudet", - - // "community.listelement.badge": "Community", "community.listelement.badge": "Yhteisö", - - // "comcol-role.edit.no-group": "None", "comcol-role.edit.no-group": "Ei mitään", // "comcol-role.edit.create": "Create", "comcol-role.edit.create": "Luo", + // "comcol-role.edit.create.error.title": "Failed to create a group for the '{{ role }}' role", + "comcol-role.edit.create.error.title": "Ryhmän luonti '{{ role }}'-roolille epäonnistui", + // "comcol-role.edit.restrict": "Restrict", "comcol-role.edit.restrict": "Rajoita", // "comcol-role.edit.delete": "Delete", "comcol-role.edit.delete": "Poista", + // "comcol-role.edit.delete.error.title": "Failed to delete the '{{ role }}' role's group", + "comcol-role.edit.delete.error.title": "'{{ role }}'-roolin ryhmän poisto epäonnistui", // "comcol-role.edit.community-admin.name": "Administrators", "comcol-role.edit.community-admin.name": "Ylläpitäjät", @@ -1375,21 +1825,18 @@ // "comcol-role.edit.collection-admin.name": "Administrators", "comcol-role.edit.collection-admin.name": "Ylläpitäjät", - // "comcol-role.edit.community-admin.description": "Community administrators can create sub-communities or collections, and manage or assign management for those sub-communities or collections. In addition, they decide who can submit items to any sub-collections, edit item metadata (after submission), and add (map) existing items from other collections (subject to authorization).", "comcol-role.edit.community-admin.description": "Yhteisön ylläpitäjät voivat luoda alayhteisöjä tai kokoelmia ja hallita niitä sekä myöntää niihin hallintaoikeuksia. He päättävät, kuka saa tallentaa tietueita alakokoelmiin, muokata metadataa (tallennuksen jälkeen) ja lisätä (liittää) olemassa olevia tietueita muista kokoelmista (käyttöoikeuksien puitteissa).", // "comcol-role.edit.collection-admin.description": "Collection administrators decide who can submit items to the collection, edit item metadata (after submission), and add (map) existing items from other collections to this collection (subject to authorization for that collection).", "comcol-role.edit.collection-admin.description": "Kokoelman ylläpitäjät päättävät, kuka saa tallentaa tietueita alakokoelmiin, muokata metadataa (tallennuksen jälkeen) ja lisätä (liittää) olemassa olevia tietueita muista kokoelmista (k.o. kokoelman käyttöoikeuksien puitteissa).", - // "comcol-role.edit.submitters.name": "Submitters", "comcol-role.edit.submitters.name": "Tallentajat", // "comcol-role.edit.submitters.description": "The E-People and Groups that have permission to submit new items to this collection.", "comcol-role.edit.submitters.description": "Käyttäjät ja ryhmät, joilla on oikeus tallentaa uusia tietueita tähän kokoelmaan", - // "comcol-role.edit.item_read.name": "Default item read access", "comcol-role.edit.item_read.name": "Tietueen oletuslukuoikeus", @@ -1399,7 +1846,6 @@ // "comcol-role.edit.item_read.anonymous-group": "Default read for incoming items is currently set to Anonymous.", "comcol-role.edit.item_read.anonymous-group": "Uusien tietuiden oletuslukuoikeus on tällä hetkellä Anonymous.", - // "comcol-role.edit.bitstream_read.name": "Default bitstream read access", "comcol-role.edit.bitstream_read.name": "Tiedostojen oletuslukuoikeus", @@ -1409,28 +1855,29 @@ // "comcol-role.edit.bitstream_read.anonymous-group": "Default read for incoming bitstreams is currently set to Anonymous.", "comcol-role.edit.bitstream_read.anonymous-group": "Uusien tiedostojen oletuslukuoikeus on tällä hetkellä Anonymous.", - // "comcol-role.edit.editor.name": "Editors", "comcol-role.edit.editor.name": "Muokkaajat", // "comcol-role.edit.editor.description": "Editors are able to edit the metadata of incoming submissions, and then accept or reject them.", "comcol-role.edit.editor.description": "Muokkaajat voivat muokata uusien tallennusten metadataa sekä hyväksyä tai hylätä tallennukset.", - // "comcol-role.edit.finaleditor.name": "Final editors", "comcol-role.edit.finaleditor.name": "Loppumuokkaajat", // "comcol-role.edit.finaleditor.description": "Final editors are able to edit the metadata of incoming submissions, but will not be able to reject them.", "comcol-role.edit.finaleditor.description": "Loppumuokkaajat voivat muokata uusien tallennusten metadataa. He eivät voi hylätä tallennuksia.", - // "comcol-role.edit.reviewer.name": "Reviewers", "comcol-role.edit.reviewer.name": "Tarkastajat", // "comcol-role.edit.reviewer.description": "Reviewers are able to accept or reject incoming submissions. However, they are not able to edit the submission's metadata.", "comcol-role.edit.reviewer.description": "Tarkastajat voivat hyväksyä tai hylätä uudet tallennukset. He eivät voi muokata tallennusten metadataa.", + // "comcol-role.edit.scorereviewers.name": "Score Reviewers", + "comcol-role.edit.scorereviewers.name": "Arvosanatarkastajat", + // "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": "Tarkastajat voivat antaa tallennettaville julkaisuille arvosanan, joka määrittää, hylätäänkö vai hyväksytäänkö tallennus.", // "community.form.abstract": "Short Description", "community.form.abstract": "Lyhyt kuvaus", @@ -1471,8 +1918,6 @@ // "community.sub-community-list.head": "Communities of this Community", "community.sub-community-list.head": "Yhteisön alayhteisöt", - - // "cookies.consent.accept-all": "Accept all", "cookies.consent.accept-all": "Hyväksy kaikki", @@ -1494,6 +1939,12 @@ // "cookies.consent.app.required.title": "(always required)", "cookies.consent.app.required.title": "(aina pakollinen)", + // "cookies.consent.app.disable-all.description": "Use this switch to enable or disable all services.", + "cookies.consent.app.disable-all.description": "Tästä kytkimestä voit ottaa kaikki palvelut käyttöön tai poistaa ne käytöstä", + + // "cookies.consent.app.disable-all.title": "Enable or disable all services", + "cookies.consent.app.disable-all.title": "Ota käyttöön tai poista käytöstä kaikki palvelut", + // "cookies.consent.update": "There were changes since your last visit, please update your consent.", "cookies.consent.update": "Viime käyntisi jälkeen on tehty muutoksia. Ole hyvä ja päivitä suostumuksesi.", @@ -1503,9 +1954,21 @@ // "cookies.consent.decline": "Decline", "cookies.consent.decline": "Kieltäydy", + // "cookies.consent.ok": "That's ok", + "cookies.consent.ok": "OK", + + // "cookies.consent.save": "Save", + "cookies.consent.save": "Tallenna", + + // "cookies.consent.content-notice.title": "Cookie Consent", + "cookies.consent.content-notice.title": "Evästeiden hyväksyntä", + // "cookies.consent.content-notice.description": "We collect and process your personal information for the following purposes: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>. <br/> To learn more, please read our {privacyPolicy}.", "cookies.consent.content-notice.description": "Keräämme ja käsittelemme tietojasi seuraaviin tarkoituksiin: <strong>todentaminen, asetukset, kuittaus ja tilastot</strong>. <br/> Lisätietoa saat lukemalla tämän: {privacyPolicy}.", + // "cookies.consent.content-notice.description.no-privacy": "We collect and process your personal information for the following purposes: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>.", + "cookies.consent.content-notice.description.no-privacy": "Keräämme ja käsittelemme tietojasi seuraaviin tarkoituksiin: <strong>todentaminen, asetukset, kuittaus ja tilastot</strong>.", + // "cookies.consent.content-notice.learnMore": "Customize", "cookies.consent.content-notice.learnMore": "Räätälöi", @@ -1521,7 +1984,11 @@ // "cookies.consent.content-modal.title": "Information that we collect", "cookies.consent.content-modal.title": "Keräämämme tieto", + // "cookies.consent.content-modal.services": "services", + "cookies.consent.content-modal.services": "palvelut", + // "cookies.consent.content-modal.service": "service", + "cookies.consent.content-modal.service": "palvelu", // "cookies.consent.app.title.authentication": "Authentication", "cookies.consent.app.title.authentication": "Todentaminen", @@ -1529,30 +1996,29 @@ // "cookies.consent.app.description.authentication": "Required for signing you in", "cookies.consent.app.description.authentication": "Vaadittu kirjautumista varten", - // "cookies.consent.app.title.preferences": "Preferences", "cookies.consent.app.title.preferences": "Asetukset", // "cookies.consent.app.description.preferences": "Required for saving your preferences", "cookies.consent.app.description.preferences": "Vaadittu asetustesi tallentamista varten", - - // "cookies.consent.app.title.acknowledgement": "Acknowledgement", "cookies.consent.app.title.acknowledgement": "Kuittaus", // "cookies.consent.app.description.acknowledgement": "Required for saving your acknowledgements and consents", "cookies.consent.app.description.acknowledgement": "Vaadittu kuittaustesi ja hyväksyntäsi tallentamista varten", - - // "cookies.consent.app.title.google-analytics": "Google Analytics", "cookies.consent.app.title.google-analytics": "Google Analytics", // "cookies.consent.app.description.google-analytics": "Allows us to track statistical data", "cookies.consent.app.description.google-analytics": "Sallii tilastollisen datan seurannan", + // "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + // "cookies.consent.app.description.google-recaptcha": "We use google reCAPTCHA service during registration and password recovery", + "cookies.consent.app.description.google-recaptcha": "Käytämme Googlen reCAPTCHA-palvelua rekisteröinnin ja salasanan palauttamisen yhteydessä.", // "cookies.consent.purpose.functional": "Functional", "cookies.consent.purpose.functional": "Toiminnallinen", @@ -1560,8 +2026,16 @@ // "cookies.consent.purpose.statistical": "Statistical", "cookies.consent.purpose.statistical": "Tilastollinen", + // "cookies.consent.purpose.registration-password-recovery": "Registration and Password recovery", + "cookies.consent.purpose.registration-password-recovery": "Rekisteröinti ja salasanan palauttaminen", + + // "cookies.consent.purpose.sharing": "Sharing", + "cookies.consent.purpose.sharing": "Jakaminen", - // "curation-task.task.checklinks.label": "Check Links in Metadata", + // "curation-task.task.citationpage.label": "Generate Citation Page", + "curation-task.task.citationpage.label": "Luo viittaussivu", + + // "curation-task.task.checklinks.label": "Check Links in Metadata", "curation-task.task.checklinks.label": "Tarkista metadatan linkit", // "curation-task.task.noop.label": "NOOP", @@ -1579,7 +2053,8 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Virusskannaus", - + // "curation-task.task.register-doi.label": "Register DOI", + "curation-task.task.register-doi.label": "Rekisteröi DOI", // "curation.form.task-select.label": "Task:", "curation.form.task-select.label": "Tehtävä:", @@ -1599,13 +2074,38 @@ // "curation.form.submit.error.content": "An error occured when trying to start the curation task.", "curation.form.submit.error.content": "Virhe kuratointitehtävää aloitettaessa.", + // "curation.form.submit.error.invalid-handle": "Couldn't determine the handle for this object", + "curation.form.submit.error.invalid-handle": "Kohteen handlea ei voitu määrittää", + // "curation.form.handle.label": "Handle:", "curation.form.handle.label": "Handle:", // "curation.form.handle.hint": "Hint: Enter [your-handle-prefix]/0 to run a task across entire site (not all tasks may support this capability)", "curation.form.handle.hint": "Vinkki: Syötä [oma-handle-prefix]/0 suorittaaksesi tehtävän koko sivustolla (kaikki tehtävät eivät tue tätä toimintoa)", + // "deny-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I regret to inform you that it's not possible to send you a copy of the file(s) you have requested, concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am an author.\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.message": "Hyvä {{ recipientName }},\nValitettavasti emme voi lähettää kopiota pyytämistänne tiedostoista (dokumentti \"{{ itemUrl }}\" ({{ itemName }})), joiden tekijä olen. Ystävällisin terveisin \n{{ authorName }} <{{ authorEmail }}>", + + // "deny-request-copy.email.subject": "Request copy of document", + "deny-request-copy.email.subject": "Dokumenttikopion pyyntö", + + // "deny-request-copy.error": "An error occurred", + "deny-request-copy.error": "Tapahtui virhe", + + // "deny-request-copy.header": "Deny document copy request", + "deny-request-copy.header": "Epää dokumenttikopion pyyntö", + + // "deny-request-copy.intro": "This message will be sent to the applicant of the request", + "deny-request-copy.intro": "Tämä viesti lähetetään pyynnön esittäjälle", + + // "deny-request-copy.success": "Successfully denied item request", + "deny-request-copy.success": "Tietuepyyntö evätty", + // "dso.name.untitled": "Untitled", + "dso.name.untitled": "Nimetön", + + // "dso.name.unnamed": "Unnamed", + "dso.name.unnamed": "Nimeämätön", // "dso-selector.create.collection.head": "New collection", "dso-selector.create.collection.head": "Uusi kokoelma", @@ -1616,6 +2116,9 @@ // "dso-selector.create.community.head": "New community", "zxzcommunity.head": "Uusi yhteisö", + // "dso-selector.create.community.or-divider": "or", + "dso-selector.create.community.or-divider": "tai", + // "dso-selector.create.community.sub-level": "Create a new community in", "dso-selector.create.community.sub-level": "Luo uusi yhteisö tänne: ", @@ -1640,16 +2143,92 @@ // "dso-selector.edit.item.head": "Edit item", "dso-selector.edit.item.head": "Muokkaa tietuetta", + // "dso-selector.error.title": "An error occurred searching for a {{ type }}", + "dso-selector.error.title": "Virhe etsittäessä tyyppiä {{ type }}", + // "dso-selector.export-metadata.dspaceobject.head": "Export metadata from", "dso-selector.export-metadata.dspaceobject.head": "Eksportoi metadata täältä: ", + // "dso-selector.export-batch.dspaceobject.head": "Export Batch (ZIP) from", + "dso-selector.export-batch.dspaceobject.head": "Eksportoi erä (ZIP): ", + + // "dso-selector.import-batch.dspaceobject.head": "Import batch from", + "dso-selector.import-batch.dspaceobject.head": "Importoi erä: ", + // "dso-selector.no-results": "No {{ type }} found", "dso-selector.no-results": "Ei {{ type }}-tyyppiä.", // "dso-selector.placeholder": "Search for a {{ type }}", "dso-selector.placeholder": "Hae {{ type }}-tyyppiä", + // "dso-selector.select.collection.head": "Select a collection", + "dso-selector.select.collection.head": "Valitse kokoelma", + + // "dso-selector.set-scope.community.head": "Select a search scope", + "dso-selector.set-scope.community.head": "Valitse hakualue", + + // "dso-selector.set-scope.community.button": "Search all of DSpace", + "dso-selector.set-scope.community.button": "Hae koko julkaisuarkistosta", + + // "dso-selector.set-scope.community.or-divider": "or", + "dso-selector.set-scope.community.or-divider": "tai", + // "dso-selector.set-scope.community.input-header": "Search for a community or collection", + "dso-selector.set-scope.community.input-header": "Hae yhteisöä tai kokoelmaa", + + // "dso-selector.claim.item.head": "Profile tips", + "dso-selector.claim.item.head": "Profiilivinkkejä", + + // "dso-selector.claim.item.body": "These are existing profiles that may be related to you. If you recognize yourself in one of these profiles, select it and on the detail page, among the options, choose to claim it. Otherwise you can create a new profile from scratch using the button below.", + "dso-selector.claim.item.body": "Nämä ovat olemassa olevia profiileja, jotka saattavat liittyä sinuun. Jos tunnistat jonkin näistä profiileista omaksesi, valitse se ja valitse tarkentavan sivun vaihtoehdoista, että otat sen itsellesi. Muussa tapauksessa voit luoda uuden profiilin käyttämällä alla olevaa painiketta.", + + // "dso-selector.claim.item.not-mine-label": "None of these are mine", + "dso-selector.claim.item.not-mine-label": "Mikään näistä ei ole minun", + + // "dso-selector.claim.item.create-from-scratch": "Create a new one", + "dso-selector.claim.item.create-from-scratch": "Luo uusi", + + // "dso-selector.results-could-not-be-retrieved": "Something went wrong, please refresh again ↻", + "dso-selector.results-could-not-be-retrieved": "Tapahtui virhe, päivitä uudelleen ↻", + + // "supervision-group-selector.header": "Supervision Group Selector", + "supervision-group-selector.header": "Ohjausryhmän valitsin", + + // "supervision-group-selector.select.type-of-order.label": "Select a type of Order", + "supervision-group-selector.select.type-of-order.label": "Valitse tilauksen tyyppi", + + // "supervision-group-selector.select.type-of-order.option.none": "NONE", + "supervision-group-selector.select.type-of-order.option.none": "EI MITÄÄN", + + // "supervision-group-selector.select.type-of-order.option.editor": "EDITOR", + "supervision-group-selector.select.type-of-order.option.editor": "MUOKKAAJA", + + // "supervision-group-selector.select.type-of-order.option.observer": "OBSERVER", + "supervision-group-selector.select.type-of-order.option.observer": "KATSELIJA", + + // "supervision-group-selector.select.group.label": "Select a Group", + "supervision-group-selector.select.group.label": "Valitse ryhmä", + + // "supervision-group-selector.button.cancel": "Cancel", + "supervision-group-selector.button.cancel": "Peruuta", + + // "supervision-group-selector.button.save": "Save", + "supervision-group-selector.button.save": "Tallenna", + + // "supervision-group-selector.select.type-of-order.error": "Please select a type of order", + "supervision-group-selector.select.type-of-order.error": "Valitse tilauksen tyyppi", + + // "supervision-group-selector.select.group.error": "Please select a group", + "supervision-group-selector.select.group.error": "Valitse ryhmä", + + // "supervision-group-selector.notification.create.success.title": "Successfully created supervision order for group {{ name }}", + "supervision-group-selector.notification.create.success.title": "Ohjausmääräys luotu {{ name }}-ryhmälle", + + // "supervision-group-selector.notification.create.failure.title": "Error", + "supervision-group-selector.notification.create.failure.title": "Virhe", + + // "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": "Tietueelle on jo ohjausmääräys valitulle ryhmälle", // "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", "confirmation-modal.export-metadata.header": "Eksportoi {{ dsoName }}:n metadata", @@ -1663,11 +2242,23 @@ // "confirmation-modal.export-metadata.confirm": "Export", "confirmation-modal.export-metadata.confirm": "Eksportoi", + // "confirmation-modal.export-batch.header": "Export batch (ZIP) for {{ dsoName }}", + "confirmation-modal.export-batch.header": "Exportoi erä (ZIP) {{ dsoName }}", + + // "confirmation-modal.export-batch.info": "Are you sure you want to export batch (ZIP) for {{ dsoName }}", + "confirmation-modal.export-batch.info": "Haluatko varmasti eksportoida erän (ZIP) {{ dsoName }}?", + + // "confirmation-modal.export-batch.cancel": "Cancel", + "confirmation-modal.export-batch.cancel": "Peruuta", + + // "confirmation-modal.export-batch.confirm": "Export", + "confirmation-modal.export-batch.confirm": "Eksportoi", + // "confirmation-modal.delete-eperson.header": "Delete EPerson \"{{ dsoName }}\"", "confirmation-modal.delete-eperson.header": "Poista käyttäjä \"{{ dsoName }}\"", // "confirmation-modal.delete-eperson.info": "Are you sure you want to delete EPerson \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.info": "Haluatko varmasti poistaa käyttäjän \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Haluatko varmasti poistaa käyttäjän \"{{ dsoName }}\"?", // "confirmation-modal.delete-eperson.cancel": "Cancel", "confirmation-modal.delete-eperson.cancel": "Peruuta", @@ -1675,6 +2266,29 @@ // "confirmation-modal.delete-eperson.confirm": "Delete", "confirmation-modal.delete-eperson.confirm": "Poista", + // "confirmation-modal.delete-profile.header": "Delete Profile", + "confirmation-modal.delete-profile.header": "Poista profiili", + + // "confirmation-modal.delete-profile.info": "Are you sure you want to delete your profile", + "confirmation-modal.delete-profile.info": "Haluatko varmasti poistaa profiilisi?", + + // "confirmation-modal.delete-profile.cancel": "Cancel", + "confirmation-modal.delete-profile.cancel": "Peruuta", + + // "confirmation-modal.delete-profile.confirm": "Delete", + "confirmation-modal.delete-profile.confirm": "Poista", + + // "confirmation-modal.delete-subscription.header": "Delete Subscription", + "confirmation-modal.delete-subscription.header": "Poista tilaus", + + // "confirmation-modal.delete-subscription.info": "Are you sure you want to delete subscription for \"{{ dsoName }}\"", + "confirmation-modal.delete-subscription.info": "Haluatko varmasti poistaa tilauksen: \"{{ dsoName }}\"", + + // "confirmation-modal.delete-subscription.cancel": "Cancel", + "confirmation-modal.delete-subscription.cancel": "Peruuta", + + // "confirmation-modal.delete-subscription.confirm": "Delete", + "confirmation-modal.delete-subscription.confirm": "Poista", // "error.bitstream": "Error fetching bitstream", "error.bitstream": "Virhe tiedostoa noudettaessa", @@ -1712,6 +2326,9 @@ // "error.search-results": "Error fetching search results", "error.search-results": "Virhe hakutuloksia noudettaessa", + // "error.invalid-search-query": "Search query is not valid. Please check <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a> best practices for further information about this error.", + "error.invalid-search-query": "Hakulauseke on virheellinen. Tarkista <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr-kyselysyntaksi</a> ja sieltä parhaat käytännöt saadaksesi lisätietoja.", + // "error.sub-collections": "Error fetching sub-collections", "error.sub-collections": "Virhe alakokoelmia noudettaessa", @@ -1733,12 +2350,44 @@ // "error.validation.filerequired": "The file upload is mandatory", "error.validation.filerequired": "Tiedoston lataus on pakollinen", + // "error.validation.required": "This field is required", + "error.validation.required": "Kenttä on pakollinen", + // "error.validation.NotValidEmail": "This E-mail is not a valid email", + "error.validation.NotValidEmail": "Sähköpostiosoite ei ole toimiva sähköpostiosoite.", - // "file-section.error.header": "Error obtaining files for this item", - "file-section.error.header": "Virhe tietueen tiedostoja noudettaessa", + // "error.validation.emailTaken": "This E-mail is already taken", + "error.validation.emailTaken": "Sähköpostiosoite on jo käytössä", + // "error.validation.groupExists": "This group already exists", + "error.validation.groupExists": "Ryhmä on jo olemassa", + // "error.validation.metadata.name.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Element & Qualifier fields instead", + "error.validation.metadata.name.invalid-pattern": "Kenttään ei voi syöttää pisteitä, pilkkuja tai välilyöntejä. Käytä tämän kentän sijasta Elementti- ja Tarkenne-kenttiä.", + + // "error.validation.metadata.name.max-length": "This field may not contain more than 32 characters", + "error.validation.metadata.name.max-length": "Kenttään voi laittaa vain 32 merkkiä", + + // "error.validation.metadata.namespace.max-length": "This field may not contain more than 256 characters", + "error.validation.metadata.namespace.max-length": "Kenttään voi laittaa vain 256 merkkiä", + + // "error.validation.metadata.element.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Qualifier field instead", + "error.validation.metadata.element.invalid-pattern": "Kenttään ei voi syöttää pisteitä, pilkkuja tai välilyöntejä. Käytä tämän kentän sijasta Elementti- ja Tarkenne-kenttiä.", + + // "error.validation.metadata.element.max-length": "This field may not contain more than 64 characters", + "error.validation.metadata.element.max-length": "Kenttään voi laittaa vain 64 merkkiä", + + // "error.validation.metadata.qualifier.invalid-pattern": "This field cannot contain dots, commas or spaces", + "error.validation.metadata.qualifier.invalid-pattern": "Kenttään ei voi syöttää pisteitä, pilkkuja tai välilyöntejä", + + // "error.validation.metadata.qualifier.max-length": "This field may not contain more than 64 characters", + "error.validation.metadata.qualifier.max-length": "Kenttään voi laittaa vain 64 merkkiä", + + // "feed.description": "Syndication feed", + "feed.description": "Jakelusyöte", + + // "file-section.error.header": "Error obtaining files for this item", + "file-section.error.header": "Virhe tietueen tiedostoja noudettaessa", // "footer.copyright": "copyright © 2002-{{ year }}", "footer.copyright": "tekijänoikeus © 2002-{{ year }}", @@ -1755,16 +2404,17 @@ // "footer.link.privacy-policy": "Privacy policy", "footer.link.privacy-policy": "Yksilönsuoja", - // "footer.link.end-user-agreement":"End User Agreement", - "footer.link.end-user-agreement": "Käyttöehdot", - + // "footer.link.end-user-agreement": "End User Agreement", + "footer.link.end-user-agreement": "Käyttöoikeussopimus", + // "footer.link.feedback": "Send Feedback", + "footer.link.feedback": "Lähetä palautetta", // "forgot-email.form.header": "Forgot Password", "forgot-email.form.header": "Unohtunut salasana", - // "forgot-email.form.info": "Enter Register an account to subscribe to collections for email updates, and submit new items to DSpace.", - "forgot-email.form.info": "Rekisteröi käyttäjätili voidaksesi tilata sähköposti-ilmoituksia kokoelmien päivityksistä ja lisätä uusia tietueita julkaisuarkistoon.", + // "forgot-email.form.info": "Enter the email address associated with the account.", + "forgot-email.form.info": "Syötä tiliin liittyvä sähköpostiosoite.", // "forgot-email.form.email": "Email Address *", "forgot-email.form.email": "Sähköpostiosoite *", @@ -1772,28 +2422,26 @@ // "forgot-email.form.email.error.required": "Please fill in an email address", "forgot-email.form.email.error.required": "Anna sähköpostiosoite", - // "forgot-email.form.email.error.pattern": "Please fill in a valid email address", - "forgot-email.form.email.error.pattern": "Anna oikea sähköpostiosoite", + // "forgot-email.form.email.error.not-email-form": "Please fill in a valid email address", + "forgot-email.form.email.error.not-email-form": "Anna toimiva sähköpostiosoite", - // "forgot-email.form.email.hint": "This address will be verified and used as your login name.", - "forgot-email.form.email.hint": "Osoite varmistetaan, ja se toimii käyttäjätunnuksenasi kirjautumisessa.", + // "forgot-email.form.email.hint": "An email will be sent to this address with a further instructions.", + "forgot-email.form.email.hint": "Sähköpostiosoitteeseen lähetetään viesti, jossa on lisäohjeita.", - // "forgot-email.form.submit": "Submit", - "forgot-email.form.submit": "Lähetä", + // "forgot-email.form.submit": "Reset password", + "forgot-email.form.submit": "Nollaa salasana", - // "forgot-email.form.success.head": "Verification email sent", - "forgot-email.form.success.head": "Varmistusviesti lähetetty", + // "forgot-email.form.success.head": "Password reset email sent", + "forgot-email.form.success.head": "Salasanan nollausviesti lähetetty", // "forgot-email.form.success.content": "An email has been sent to {{ email }} containing a special URL and further instructions.", "forgot-email.form.success.content": "Viesti on lähetetty osoitteeseen {{ email }}. Viestissä on URL-osoite ja lisäohjeita.", - // "forgot-email.form.error.head": "Error when trying to register email", - "forgot-email.form.error.head": "Virhe sähköpostiosoitetta rekisteröitäessä", - - // "forgot-email.form.error.content": "An error occured when registering the following email address: {{ email }}", - "forgot-email.form.error.content": "Virhe rekisteröitäessä tätä sähköpostiosoitetta: {{ email }}", - + // "forgot-email.form.error.head": "Error when trying to reset password", + "forgot-email.form.error.head": "Virhe salasanaa nollattaessa", + // "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": "Virhe nollattaessa tähän sähköpostiosoitteeseen liittyvän tilin salasanaa {{ email }}", // "forgot-password.title": "Forgot Password", "forgot-password.title": "Unohtunut salasana", @@ -1801,8 +2449,8 @@ // "forgot-password.form.head": "Forgot Password", "forgot-password.form.head": "Unohtunut salasana", - // "forgot-password.form.info": "Enter a new password in the box below, and confirm it by typing it again into the second box. It should be at least six characters long.", - "forgot-password.form.info": "Syötä uusi salasana alla olevaan kenttään ja vahvista se kirjoittamalla salasana uudelleen seuraavaan kenttään. Salasanan on oltava vähintään kuusi merkkiä pitkä.", + // "forgot-password.form.info": "Enter a new password in the box below, and confirm it by typing it again into the second box.", + "forgot-password.form.info": "Syötä uusi salasana alla olevaan kenttään ja vahvista se kirjoittamalla salasana uudelleen seuraavaan kenttään.", // "forgot-password.form.card.security": "Security", "forgot-password.form.card.security": "Turvallisuus", @@ -1825,9 +2473,6 @@ // "forgot-password.form.error.matching-passwords": "The passwords do not match.", "forgot-password.form.error.matching-passwords": "Salasanat eivät täsmää.", - // "forgot-password.form.error.password-length": "The password should be at least 6 characters long.", - "forgot-password.form.error.password-length": "Salasanan on oltava vähintään 6 merkkiä pitkä.", - // "forgot-password.form.notification.error.title": "Error when trying to submit new password", "forgot-password.form.notification.error.title": "Virhe uutta salasanaa lähetettäessä", @@ -1840,10 +2485,8 @@ // "forgot-password.form.submit": "Submit password", "forgot-password.form.submit": "Lähetä salasana", - - - // "form.add": "Add", - "form.add": "Lisää", + // "form.add": "Add more", + "form.add": "Lisää vielä", // "form.add-help": "Click here to add the current entry and to add another one", "form.add-help": "Valitse lisätäksesi nykyisen kohteen ja toisen kohteen", @@ -1855,13 +2498,19 @@ "form.clear": "Tyhjennä", // "form.clear-help": "Click here to remove the selected value", - "form.clear-help": "Napauta tästä poistaaksesi valitun arvon", + "form.clear-help": "Napsauta tästä poistaaksesi valitun arvon", + + // "form.discard": "Discard", + "form.discard": "Hylkää", + + // "form.drag": "Drag", + "form.drag": "Raahaa", // "form.edit": "Edit", "form.edit": "Muokkaa", // "form.edit-help": "Click here to edit the selected value", - "form.edit-help": "Napauta tästä muokataksesi valittua arvoa", + "form.edit-help": "Napsauta tästä muokataksesi valittua arvoa", // "form.first-name": "First name", "form.first-name": "Etunimi", @@ -1896,6 +2545,24 @@ // "form.no-value": "No value entered", "form.no-value": "Ei syötettyä arvoa", + // "form.other-information.email": "Email", + "form.other-information.email": "Sähköpostiosoite", + + // "form.other-information.first-name": "First Name", + "form.other-information.first-name": "Etunimi", + + // "form.other-information.insolr": "In Solr Index", + "form.other-information.insolr": "Solr-indeksissä", + + // "form.other-information.institution": "Institution", + "form.other-information.institution": "Instituutio", + + // "form.other-information.last-name": "Last Name", + "form.other-information.last-name": "Sukunimi", + + // "form.other-information.orcid": "ORCID", + "form.other-information.orcid": "ORCID-tunniste", + // "form.remove": "Remove", "form.remove": "Poista", @@ -1911,10 +2578,134 @@ // "form.search-help": "Click here to look for an existing correspondence", "form.search-help": "Valitse etsiäksesi olemassa olevaa vastaavuutta", - // "form.submit": "Submit", - "form.submit": "Lähetä", + // "form.submit": "Save", + "form.submit": "Tallenna", + + // "form.create": "Create", + "form.create": "Luo", + + // "form.repeatable.sort.tip": "Drop the item in the new position", + "form.repeatable.sort.tip": "Pudota tietue uuteen paikkaan", + + // "grant-deny-request-copy.deny": "Don't send copy", + "grant-deny-request-copy.deny": "Älä lähetä kopiota", + + // "grant-deny-request-copy.email.back": "Back", + "grant-deny-request-copy.email.back": "Paluu", + + // "grant-deny-request-copy.email.message": "Optional additional message", + "grant-deny-request-copy.email.message": "Valinnainen lisäviesti", + + // "grant-deny-request-copy.email.message.empty": "Please enter a message", + "grant-deny-request-copy.email.message.empty": "Kirjoita viesti", + + // "grant-deny-request-copy.email.permissions.info": "You may use this occasion to reconsider the access restrictions on the document, to avoid having to respond to these requests. If you’d like to ask the repository administrators to remove these restrictions, please check the box below.", + "grant-deny-request-copy.email.permissions.info": "Voit harkita uudelleen dokumentin pääsyrajoituksia, jotta sinun ei tarvitse vastata näihin pyyntöihin. Rastita alla oleva ruutu pyytääksesi julkaisuarkiston ylläpitäjää poistamaan rajoitukset.", + + // "grant-deny-request-copy.email.permissions.label": "Change to open access", + "grant-deny-request-copy.email.permissions.label": "Valitse Open Access", + + // "grant-deny-request-copy.email.send": "Send", + "grant-deny-request-copy.email.send": "Lähetä", + + // "grant-deny-request-copy.email.subject": "Subject", + "grant-deny-request-copy.email.subject": "Asiasana", + + // "grant-deny-request-copy.email.subject.empty": "Please enter a subject", + "grant-deny-request-copy.email.subject.empty": "Syötä asiasana", + + // "grant-deny-request-copy.grant": "Send copy", + "grant-deny-request-copy.grant": "Lähetä kopio", + + // "grant-deny-request-copy.header": "Document copy request", + "grant-deny-request-copy.header": "Dokumenttikopion pyyntö", + + // "grant-deny-request-copy.home-page": "Take me to the home page", + "grant-deny-request-copy.home-page": "Palaa etusivulle", + + // "grant-deny-request-copy.intro1": "If you are one of the authors of the document <a href='{{ url }}'>{{ name }}</a>, then please use one of the options below to respond to the user's request.", + "grant-deny-request-copy.intro1": "Jos olet dokumentin <a href='{{ url }}'>{{ name }}</a> tekijä, vastaa käyttäjän pyyntöön jollakin alla olevista vaihtoehdoista.", + + // "grant-deny-request-copy.intro2": "After choosing an option, you will be presented with a suggested email reply which you may edit.", + "grant-deny-request-copy.intro2": "Valittuasi vaihtoehdon näet sähköpostiviestiehdotuksen. Voit muokata ehdotusta halutessasi.", + + // "grant-deny-request-copy.processed": "This request has already been processed. You can use the button below to get back to the home page.", + "grant-deny-request-copy.processed": "Pyyntö on käsitelty. Voit käyttää alla olevaa painiketta palataksesi etusivulle.", + + // "grant-request-copy.email.subject": "Request copy of document", + "grant-request-copy.email.subject": "Pyydä kopiota dokumentista", + + // "grant-request-copy.error": "An error occurred", + "grant-request-copy.error": "Tapahtui virhe", + + // "grant-request-copy.header": "Grant document copy request", + "grant-request-copy.header": "Hyväksy dokumenttikopion pyyntö", + + // "grant-request-copy.intro": "A message will be sent to the applicant of the request. The requested document(s) will be attached.", + "grant-request-copy.intro": "Viesti lähetetään pyynnön esittäjälle. Pyydetyt dokumentit liitetään viestiin.", + + // "grant-request-copy.success": "Successfully granted item request", + "grant-request-copy.success": "Tietuepyyntö hyväksytty", + + // "health.breadcrumbs": "Health", + "health.breadcrumbs": "Järjestelmän kunto", + + // "health-page.heading": "Health", + "health-page.heading": "Järjestelmän kunto", + + // "health-page.info-tab": "Info", + "health-page.info-tab": "Tiedot", + + // "health-page.status-tab": "Status", + "health-page.status-tab": "Tila", + + // "health-page.error.msg": "The health check service is temporarily unavailable", + "health-page.error.msg": "Järjestelmän kunnon tarkistus on väliaikaisesti poissa käytöstä", + + // "health-page.property.status": "Status code", + "health-page.property.status": "Tilakoodi", + + // "health-page.section.db.title": "Database", + "health-page.section.db.title": "Tietokanta", + + // "health-page.section.geoIp.title": "GeoIp", + "health-page.section.geoIp.title": "GeoIp", + + // "health-page.section.solrAuthorityCore.title": "Solr: authority core", + "health-page.section.solrAuthorityCore.title": "Solr: auktoriteettiydin", + + // "health-page.section.solrOaiCore.title": "Solr: oai core", + "health-page.section.solrOaiCore.title": "Solr: OAI-ydin", + + // "health-page.section.solrSearchCore.title": "Solr: search core", + "health-page.section.solrSearchCore.title": "Solr: hakuydin", + + // "health-page.section.solrStatisticsCore.title": "Solr: statistics core", + "health-page.section.solrStatisticsCore.title": "Solr: tilastoydin", + + // "health-page.section-info.app.title": "Application Backend", + "health-page.section-info.app.title": "Taustasovellus", + + // "health-page.section-info.java.title": "Java", + "health-page.section-info.java.title": "Java", + + // "health-page.status": "Status", + "health-page.status": "Tila", + + // "health-page.status.ok.info": "Operational", + "health-page.status.ok.info": "Toiminnassa", + + // "health-page.status.error.info": "Problems detected", + "health-page.status.error.info": "Ongelmia havaittu", + + // "health-page.status.warning.info": "Possible issues detected", + "health-page.status.warning.info": "Mahdollisia ongelmia havaittu", + // "health-page.title": "Health", + "health-page.title": "Järjestelmän kunto", + // "health-page.section.no-issues": "No issues detected", + "health-page.section.no-issues": "Ei havaittuja ongelmia", // "home.description": "", "home.description": "", @@ -1922,11 +2713,11 @@ // "home.breadcrumbs": "Home", "home.breadcrumbs": "Etusivu", - // "home.search-form.placeholder": "Search the repository ...", + // "home.search-form.placeholder": "Search the repository ...", "home.search-form.placeholder": "Hae julkaisuarkistosta ...", - // "home.title": "DSpace Angular :: Home", - "home.title": "DSpace Angular :: Etusivu", + // "home.title": "Home", + "home.title": "Etusivu", // "home.top-level-communities.head": "Communities in DSpace", "home.top-level-communities.head": "Julkaisuarkiston yhteisöt", @@ -1934,19 +2725,17 @@ // "home.top-level-communities.help": "Select a community to browse its collections.", "home.top-level-communities.help": "Valitse yhteisö, jonka kokoelmia haluat selata.", - - // "info.end-user-agreement.accept": "I have read and I agree to the End User Agreement", - "info.end-user-agreement.accept": "Olen lukenut ja hyväksyn käyttöehdot", + "info.end-user-agreement.accept": "Olen lukenut ja hyväksyn käyttöoikeussopimuksen", // "info.end-user-agreement.accept.error": "An error occurred accepting the End User Agreement", - "info.end-user-agreement.accept.error": "Virhe hyväksyttäessä käyttöehtoja", + "info.end-user-agreement.accept.error": "Virhe hyväksyttäessä käyttöoikeussopimusta", // "info.end-user-agreement.accept.success": "Successfully updated the End User Agreement", - "info.end-user-agreement.accept.success": "Käyttöehdot päivitetty", + "info.end-user-agreement.accept.success": "Käyttöoikeussopimus päivitetty", // "info.end-user-agreement.breadcrumbs": "End User Agreement", - "info.end-user-agreement.breadcrumbs": "Käyttöehdot", + "info.end-user-agreement.breadcrumbs": "Käyttöoikeussopimus", // "info.end-user-agreement.buttons.cancel": "Cancel", "info.end-user-agreement.buttons.cancel": "Peruuta", @@ -1955,10 +2744,13 @@ "info.end-user-agreement.buttons.save": "Tallenna", // "info.end-user-agreement.head": "End User Agreement", - "info.end-user-agreement.head": "Käyttöehdot", + "info.end-user-agreement.head": "Käyttöoikeussopimus", // "info.end-user-agreement.title": "End User Agreement", - "info.end-user-agreement.title": "Käyttöehdot", + "info.end-user-agreement.title": "Käyttöoikeussopimus", + + // "info.end-user-agreement.hosting-country": "the United States", + "info.end-user-agreement.hosting-country": "Suomi", // "info.privacy.breadcrumbs": "Privacy Statement", "info.privacy.breadcrumbs": "Tietosuojalauseke", @@ -1969,39 +2761,68 @@ // "info.privacy.title": "Privacy Statement", "info.privacy.title": "Tietosuojalauseke", + // "info.feedback.breadcrumbs": "Feedback", + "info.feedback.breadcrumbs": "Palaute", + + // "info.feedback.head": "Feedback", + "info.feedback.head": "Palaute", + + // "info.feedback.title": "Feedback", + "info.feedback.title": "Palaute", + + // "info.feedback.info": "Thanks for sharing your feedback about the DSpace system. Your comments are appreciated!", + "info.feedback.info": "Kiitos antamastasi palautteesta. Havaintosi ovat arvokkaita!", + + // "info.feedback.email_help": "This address will be used to follow up on your feedback.", + "info.feedback.email_help": "Tätä osoitetta käytetään palautteesi käsittelyssä.", + + // "info.feedback.send": "Send Feedback", + "info.feedback.send": "Lähetä palautetta", + // "info.feedback.comments": "Comments", + "info.feedback.comments": "Kommentit", - // "item.alerts.private": "This item is private", + // "info.feedback.email-label": "Your Email", + "info.feedback.email-label": "Sähköpostiosoitteesi", + + // "info.feedback.create.success": "Feedback Sent Successfully!", + "info.feedback.create.success": "Palaute lähetetty!", + + // "info.feedback.error.email.required": "A valid email address is required", + "info.feedback.error.email.required": "Toimiva sähköpostiosoite on pakollinen", + + // "info.feedback.error.message.required": "A comment is required", + "info.feedback.error.message.required": "Kommentti on pakollinen", + + // "info.feedback.page-label": "Page", + "info.feedback.page-label": "Sivu", + + // "info.feedback.page_help": "Tha page related to your feedback", + "info.feedback.page_help": "Sivu, johon palautteesi kohdistuu", + + // "item.alerts.private": "This item is non-discoverable", "item.alerts.private": "Tietue on yksityinen", // "item.alerts.withdrawn": "This item has been withdrawn", "item.alerts.withdrawn": "Tietue on poistettu käytöstä", - - // "item.edit.authorizations.heading": "With this editor you can view and alter the policies of an item, plus alter policies of individual item components: bundles and bitstreams. Briefly, an item is a container of bundles, and bundles are containers of bitstreams. Containers usually have ADD/REMOVE/READ/WRITE policies, while bitstreams only have READ/WRITE policies.", "item.edit.authorizations.heading": "Tässä voit tarkastella ja muokata tietuekäytäntöjä sekä tietueen yksittäisten komponenttien eli nippujen ja tiedostojen käytäntöjä. Tietue on nippujen säiliö ja niput ovat tiedostojen säiliöitä. Säiliöillä on yleensä LISÄYS/POISTO/LUKU/KIRJOITUS-käytännöt, mutta tiedostoihin sovelletaan vain LUKU/KIRJOITUS-käytäntöjä.", - - // "item.edit.authorizations.title": "Edit item's Policies", "item.edit.authorizations.title": "Muokkaa tietuekäytäntöjä", - - - // "item.badge.private": "Private", + // "item.badge.private": "Non-discoverable", "item.badge.private": "Yksityinen", // "item.badge.withdrawn": "Withdrawn", "item.badge.withdrawn": "Poistettu käytöstä", - - // "item.bitstreams.upload.bundle": "Bundle", "item.bitstreams.upload.bundle": "Nippu", - // "item.bitstreams.upload.bundle.placeholder": "Select a bundle", - "item.bitstreams.upload.bundle.placeholder": "Valitse nippu", + // "item.bitstreams.upload.bundle.placeholder": "Select a bundle or input new bundle name", + "item.bitstreams.upload.bundle.placeholder": "Valitse nippu tai syötä uuden nipun nimi", // "item.bitstreams.upload.bundle.new": "Create bundle", "item.bitstreams.upload.bundle.new": "Luo nippu", @@ -2030,8 +2851,6 @@ // "item.bitstreams.upload.title": "Upload bitstream", "item.bitstreams.upload.title": "Lataa tiedosto", - - // "item.edit.bitstreams.bundle.edit.buttons.upload": "Upload", "item.edit.bitstreams.bundle.edit.buttons.upload": "Lataus", @@ -2063,7 +2882,7 @@ "item.edit.bitstreams.edit.buttons.remove": "Poista", // "item.edit.bitstreams.edit.buttons.undo": "Undo changes", - "item.edit.bitstreams.edit.buttons.undo": "Peruuta muutokset", + "item.edit.bitstreams.edit.buttons.undo": "Kumoa muutokset", // "item.edit.bitstreams.empty": "This item doesn't contain any bitstreams. Click the upload button to create one.", "item.edit.bitstreams.empty": "Tietueeseen ei liity tiedostoja. Valitse latauspainike luodaksesi tiedoston.", @@ -2122,8 +2941,6 @@ // "item.edit.bitstreams.upload-button": "Upload", "item.edit.bitstreams.upload-button": "Lataa", - - // "item.edit.delete.cancel": "Cancel", "item.edit.delete.cancel": "Peruuta", @@ -2148,6 +2965,8 @@ // "item.edit.breadcrumbs": "Edit Item", "item.edit.breadcrumbs": "Muokkaa tietuetta", + // "item.edit.tabs.disabled.tooltip": "You're not authorized to access this tab", + "item.edit.tabs.disabled.tooltip": "Sinulla ei ole valtuuksia tähän välilehteen", // "item.edit.tabs.mapper.head": "Collection Mapper", "item.edit.tabs.mapper.head": "Kokoelmaliitosväline", @@ -2155,6 +2974,69 @@ // "item.edit.tabs.item-mapper.title": "Item Edit - Collection Mapper", "item.edit.tabs.item-mapper.title": "Tietueen muokkaus - Kokoelmaliitosväline", + // "item.edit.identifiers.doi.status.UNKNOWN": "Unknown", + "item.edit.identifiers.doi.status.UNKNOWN": "Tuntematon", + + // "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Queued for registration", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Rekisteröintijonossa", + + // "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Queued for reservation", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Varausjonossa", + + // "item.edit.identifiers.doi.status.IS_REGISTERED": "Registered", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Rekisteröity", + + // "item.edit.identifiers.doi.status.IS_RESERVED": "Reserved", + "item.edit.identifiers.doi.status.IS_RESERVED": "Varattu", + + // "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Reserved (update queued)", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Varattu (päivitysjonossa)", + + // "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registered (update queued)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Rekisteröity (päivitysjonossa)", + + // "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Queued for update and registration", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Päivitys- ja rekisteröintijonossa", + + // "item.edit.identifiers.doi.status.TO_BE_DELETED": "Queued for deletion", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "Poistojonossa", + + // "item.edit.identifiers.doi.status.DELETED": "Deleted", + "item.edit.identifiers.doi.status.DELETED": "Poistettu", + + // "item.edit.identifiers.doi.status.PENDING": "Pending (not registered)", + "item.edit.identifiers.doi.status.PENDING": "Vireillä (ei rekisteröity)", + + // "item.edit.identifiers.doi.status.MINTED": "Minted (not registered)", + "item.edit.identifiers.doi.status.MINTED": "Luotu (ei rekisteröity)", + + // "item.edit.tabs.status.buttons.register-doi.label": "Register a new or pending DOI", + "item.edit.tabs.status.buttons.register-doi.label": "Rekisteröi uusi tai vireillä oleva DOI", + + // "item.edit.tabs.status.buttons.register-doi.button": "Register DOI...", + "item.edit.tabs.status.buttons.register-doi.button": "Rekisteröi DOI...", + + // "item.edit.register-doi.header": "Register a new or pending DOI", + "item.edit.register-doi.header": "Rekisteröi uusi tai vireillä oleva DOI", + + // "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": "Tarkasta vireillä olevat tunnisteet ja tietueitten metadata alapuolella. Napsauta Vahvista jatkaaksesi DOI-tunnuksen rekisteröintiä tai Peruuta peruuttaaksesi.", + + // "item.edit.register-doi.confirm": "Confirm", + "item.edit.register-doi.confirm": "Vahvista", + + // "item.edit.register-doi.cancel": "Cancel", + "item.edit.register-doi.cancel": "Peruuta", + + // "item.edit.register-doi.success": "DOI queued for registration successfully.", + "item.edit.register-doi.success": "DOI lisätty rekisteröintijonoon.", + + // "item.edit.register-doi.error": "Error registering DOI", + "item.edit.register-doi.error": "Virhe rekisteröitäessä DOI-tunnusta", + + // "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": "DOI on jo luotu ja lisätään rekisteröintijonoon verkossa", + // "item.edit.item-mapper.buttons.add": "Map item to selected collections", "item.edit.item-mapper.buttons.add": "Liitä tietue valittuihin kokoelmiin", @@ -2200,20 +3082,27 @@ // "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", "item.edit.item-mapper.notifications.remove.success.head": "Liitos poistettu", + // "item.edit.item-mapper.search-form.placeholder": "Search collections...", + "item.edit.item-mapper.search-form.placeholder": "Hae kokoelmia...", + // "item.edit.item-mapper.tabs.browse": "Browse mapped collections", "item.edit.item-mapper.tabs.browse": "Selaa liitettyjä kokoelmia", // "item.edit.item-mapper.tabs.map": "Map new collections", "item.edit.item-mapper.tabs.map": "Liitä uusia kokoelmia", - - // "item.edit.metadata.add-button": "Add", "item.edit.metadata.add-button": "Lisää", // "item.edit.metadata.discard-button": "Discard", "item.edit.metadata.discard-button": "Hylkää", + // "item.edit.metadata.edit.buttons.confirm": "Confirm", + "item.edit.metadata.edit.buttons.confirm": "Vahvista", + + // "item.edit.metadata.edit.buttons.drag": "Drag to reorder", + "item.edit.metadata.edit.buttons.drag": "Raahaa uudelleenjärjestääksesi", + // "item.edit.metadata.edit.buttons.edit": "Edit", "item.edit.metadata.edit.buttons.edit": "Muokkaa", @@ -2226,6 +3115,9 @@ // "item.edit.metadata.edit.buttons.unedit": "Stop editing", "item.edit.metadata.edit.buttons.unedit": "Lopeta muokkaus", + // "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": "Tämä on virtuaalinen metadata-arvo eli arvo, joka on peritty liittyvältä entiteetiltä. Sitä ei voi muokata suoraan. Lisää tai poista yhteys \"Suhteet\"-välilehdellä,", + // "item.edit.metadata.empty": "The item currently doesn't contain any metadata. Click Add to start adding a metadata value.", "item.edit.metadata.empty": "Tietueessa ei ole metadataa. Valitse Lisää lisätäksesi metadataa.", @@ -2241,13 +3133,16 @@ // "item.edit.metadata.headers.value": "Value", "item.edit.metadata.headers.value": "Arvo", + // "item.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", + "item.edit.metadata.metadatafield.error": "Virhe validoitaessa metadatakenttää", + // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", "item.edit.metadata.metadatafield.invalid": "Valitse oikea metadatakenttä", // "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", "item.edit.metadata.notifications.discarded.content": "Muutokset hylätty. Valitse 'Kumoa' palauttaaksesi muutokset", - // "item.edit.metadata.notifications.discarded.title": "Changed discarded", + // "item.edit.metadata.notifications.discarded.title": "Changes discarded", "item.edit.metadata.notifications.discarded.title": "Muutokset hylätty", // "item.edit.metadata.notifications.error.title": "An error occurred", @@ -2262,7 +3157,7 @@ // "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", "item.edit.metadata.notifications.outdated.content": "Toinen käyttäjä on muuttanut parhaillaan muokkaamaasi tietuetta. Tekemäsi muutokset on hylätty ristiriitojen estämiseksi", - // "item.edit.metadata.notifications.outdated.title": "Changed outdated", + // "item.edit.metadata.notifications.outdated.title": "Changes outdated", "item.edit.metadata.notifications.outdated.title": "Muutokset vanhentuneet", // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", @@ -2272,13 +3167,14 @@ "item.edit.metadata.notifications.saved.title": "Metadata tallennettu", // "item.edit.metadata.reinstate-button": "Undo", - "item.edit.metadata.reinstate-button": "Peruuta", + "item.edit.metadata.reinstate-button": "Kumoa", + + // "item.edit.metadata.reset-order-button": "Undo reorder", + "item.edit.metadata.reset-order-button": "Kumoa uudelleenjärjestäminen", // "item.edit.metadata.save-button": "Save", "item.edit.metadata.save-button": "Tallenna", - - // "item.edit.modify.overview.field": "Field", "item.edit.modify.overview.field": "Kenttä", @@ -2288,10 +3184,14 @@ // "item.edit.modify.overview.value": "Value", "item.edit.modify.overview.value": "Arvo", + // "item.edit.move.cancel": "Back", + "item.edit.move.cancel": "Paluu", + // "item.edit.move.save-button": "Save", + "item.edit.move.save-button": "Tallenna", - // "item.edit.move.cancel": "Cancel", - "item.edit.move.cancel": "Peruuta", + // "item.edit.move.discard-button": "Discard", + "item.edit.move.discard-button": "Hylkää", // "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", "item.edit.move.description": "Valitse kokoelma, johon haluat siirtää tietueen. Voit antaa hakulausekkeen kokoelmien määrän pienentämiseksi.", @@ -2323,48 +3223,42 @@ // "item.edit.move.title": "Move item", "item.edit.move.title": "Siirrä tietue", - - // "item.edit.private.cancel": "Cancel", "item.edit.private.cancel": "Peruuta", - // "item.edit.private.confirm": "Make it Private", + // "item.edit.private.confirm": "Make it non-discoverable", "item.edit.private.confirm": "Muuta yksityiseksi", - // "item.edit.private.description": "Are you sure this item should be made private in the archive?", - "item.edit.private.description": "Haluatko varmasti muuttaa tietueen yksityiseksi?", + // "item.edit.private.description": "Are you sure this item should be made non-discoverable in the archive?", + "item.edit.private.description": "Haluatko varmasti muuttaa tietueen yksityiseksi? Yksityinen tietue ei löydy haettaessa.", - // "item.edit.private.error": "An error occurred while making the item private", + // "item.edit.private.error": "An error occurred while making the item non-discoverable", "item.edit.private.error": "Virhe muutettaessa tietuetta yksityiseksi", - // "item.edit.private.header": "Make item private: {{ id }}", - "item.edit.private.header": "Muuta yksityiseksi tietue: {{ id }}", + // "item.edit.private.header": "Make item non-discoverable: {{ id }}", + "item.edit.private.header": "Muuta tietue yksityiseksi: {{ id }}", - // "item.edit.private.success": "The item is now private", + // "item.edit.private.success": "The item is now non-discoverable", "item.edit.private.success": "Tietue on yksityinen", - - // "item.edit.public.cancel": "Cancel", "item.edit.public.cancel": "Peruuta", - // "item.edit.public.confirm": "Make it Public", + // "item.edit.public.confirm": "Make it discoverable", "item.edit.public.confirm": "Muuta julkiseksi", - // "item.edit.public.description": "Are you sure this item should be made public in the archive?", - "item.edit.public.description": "Haluatko varmasti muuttaa tietueen julkiseksi?", + // "item.edit.public.description": "Are you sure this item should be made discoverable in the archive?", + "item.edit.public.description": "Haluatko varmasti muuttaa tietueen julkiseksi? Julkinen tietue löytyy haettaessa.", - // "item.edit.public.error": "An error occurred while making the item public", + // "item.edit.public.error": "An error occurred while making the item discoverable", "item.edit.public.error": "Virhe muutettaessa tietuetta julkiseksi", - // "item.edit.public.header": "Make item public: {{ id }}", - "item.edit.public.header": "Muuta julkiseksi tietue: {{ id }}", + // "item.edit.public.header": "Make item discoverable: {{ id }}", + "item.edit.public.header": "Muuta tietue julkiseksi: {{ id }}", - // "item.edit.public.success": "The item is now public", + // "item.edit.public.success": "The item is now discoverable", "item.edit.public.success": "Tietue on julkinen", - - // "item.edit.reinstate.cancel": "Cancel", "item.edit.reinstate.cancel": "Peruuta", @@ -2383,8 +3277,6 @@ // "item.edit.reinstate.success": "The item was reinstated successfully", "item.edit.reinstate.success": "Tietue palautettu käyttöön", - - // "item.edit.relationships.discard-button": "Discard", "item.edit.relationships.discard-button": "Hylkää", @@ -2395,13 +3287,13 @@ "item.edit.relationships.edit.buttons.remove": "Poista", // "item.edit.relationships.edit.buttons.undo": "Undo changes", - "item.edit.relationships.edit.buttons.undo": "Peruuta muutokset", + "item.edit.relationships.edit.buttons.undo": "Kumoa muutokset", // "item.edit.relationships.no-relationships": "No relationships", "item.edit.relationships.no-relationships": "Ei yhteyksiä", // "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", - "item.edit.relationships.notifications.discarded.content": "Muutoksesi hylättiin. Valitse 'Peruuta' palauttaaksesi ne.", + "item.edit.relationships.notifications.discarded.content": "Muutoksesi hylättiin. Valitse 'Kumoa' palauttaaksesi ne.", // "item.edit.relationships.notifications.discarded.title": "Changes discarded", "item.edit.relationships.notifications.discarded.title": "Muutokset hylätty", @@ -2422,7 +3314,7 @@ "item.edit.relationships.notifications.saved.title": "Yhteydet tallennettu", // "item.edit.relationships.reinstate-button": "Undo", - "item.edit.relationships.reinstate-button": "Peruuta", + "item.edit.relationships.reinstate-button": "Kumoa", // "item.edit.relationships.save-button": "Save", "item.edit.relationships.save-button": "Tallenna", @@ -2430,6 +3322,9 @@ // "item.edit.relationships.no-entity-type": "Add 'dspace.entity.type' metadata to enable relationships for this item", "item.edit.relationships.no-entity-type": "Lisää 'dspace.entity.type' -metadataa aktivoidaksesi yhteydet tietueessa", + // "item.edit.return": "Back", + "item.edit.return": "Paluu", + // "item.edit.tabs.bitstreams.head": "Bitstreams", "item.edit.tabs.bitstreams.head": "Tietueen tiedostot", @@ -2442,6 +3337,9 @@ // "item.edit.tabs.curate.title": "Item Edit - Curate", "item.edit.tabs.curate.title": "Tietueen muokkaus - Kuratointi", + // "item.edit.curate.title": "Curate Item: {{item}}", + "item.edit.curate.title": "Kuratoi tietuetta: {{item}}", + // "item.edit.tabs.metadata.head": "Metadata", "item.edit.tabs.metadata.head": "Tietueen metadata", @@ -2478,23 +3376,26 @@ // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", "item.edit.tabs.status.buttons.move.label": "Siirrä tietue toiseen kokoelmaan", - // "item.edit.tabs.status.buttons.private.button": "Make it private...", + // "item.edit.tabs.status.buttons.private.button": "Make it non-discoverable...", "item.edit.tabs.status.buttons.private.button": "Muuta yksityiseksi...", - // "item.edit.tabs.status.buttons.private.label": "Make item private", + // "item.edit.tabs.status.buttons.private.label": "Make item non-discoverable", "item.edit.tabs.status.buttons.private.label": "Muuta tietue yksityiseksi", - // "item.edit.tabs.status.buttons.public.button": "Make it public...", + // "item.edit.tabs.status.buttons.public.button": "Make it discoverable...", "item.edit.tabs.status.buttons.public.button": "Muuta julkiseksi...", - // "item.edit.tabs.status.buttons.public.label": "Make item public", + // "item.edit.tabs.status.buttons.public.label": "Make item discoverable", "item.edit.tabs.status.buttons.public.label": "Muuta tietue julkiseksi", // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", "item.edit.tabs.status.buttons.reinstate.button": "Palauta käyttöön...", // "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", - "item.edit.tabs.status.buttons.reinstate.label": "Palauta tietue arkistoon", + "item.edit.tabs.status.buttons.reinstate.label": "Palauta tietue julkaisuarkistoon", + + // "item.edit.tabs.status.buttons.unauthorized": "You're not authorized to perform this action", + "item.edit.tabs.status.buttons.unauthorized": "Sinulla ei ole valtuuksia suorittaa tätä toimintoa", // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw this item", "item.edit.tabs.status.buttons.withdraw.button": "Poista tämä kohde", @@ -2509,7 +3410,7 @@ "item.edit.tabs.status.head": "Tietueen tila", // "item.edit.tabs.status.labels.handle": "Handle", - "item.edit.tabs.status.labels.handle": "Handle-tunnus", + "item.edit.tabs.status.labels.handle": "Handle", // "item.edit.tabs.status.labels.id": "Item Internal ID", "item.edit.tabs.status.labels.id": "Tietueen sisäinen ID", @@ -2538,8 +3439,6 @@ // "item.edit.tabs.view.title": "Item Edit - View", "item.edit.tabs.view.title": "Tietueen muokkaus - Näytä", - - // "item.edit.withdraw.cancel": "Cancel", "item.edit.withdraw.cancel": "Peruuta", @@ -2558,7 +3457,8 @@ // "item.edit.withdraw.success": "The item was withdrawn successfully", "item.edit.withdraw.success": "Tietue poistettu käytöstä", - + // "item.orcid.return": "Back", + "item.orcid.return": "Paluu", // "item.listelement.badge": "Item", "item.listelement.badge": "Tietue", @@ -2584,10 +3484,38 @@ // "item.search.results.head": "Item Search Results", "item.search.results.head": "Tietuehaun tulokset", - // "item.search.title": "DSpace Angular :: Item Search", - "item.search.title": "DSpace Angular :: Tietuehaku", + // "item.search.title": "Item Search", + "item.search.title": "Tietuehaku", + + // "item.truncatable-part.show-more": "Show more", + "item.truncatable-part.show-more": "Näytä lisää", + // "item.truncatable-part.show-less": "Collapse", + "item.truncatable-part.show-less": "Sulje", + // "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", + "workflow-item.search.result.delete-supervision.modal.header": "Poista ohjausmääräys", + + // "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": "Haluatko varmasti poistaa ohjausmääräyksen?", + + // "workflow-item.search.result.delete-supervision.modal.cancel": "Cancel", + "workflow-item.search.result.delete-supervision.modal.cancel": "Peruuta", + + // "workflow-item.search.result.delete-supervision.modal.confirm": "Delete", + "workflow-item.search.result.delete-supervision.modal.confirm": "Poista", + + // "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"", + "workflow-item.search.result.notification.deleted.success": "Ohjausmääräys poistettu \"{{name}}\"", + + // "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Ohjausmääräyksen poisto epäonnistui \"{{name}}\"", + + // "workflow-item.search.result.list.element.supervised-by": "Supervised by:", + "workflow-item.search.result.list.element.supervised-by": "Ohjaajana:", + + // "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Poista ohjausryhmä", // "item.page.abstract": "Abstract", "item.page.abstract": "Tiivistelmä", @@ -2601,6 +3529,12 @@ // "item.page.collections": "Collections", "item.page.collections": "Kokoelmat", + // "item.page.collections.loading": "Loading...", + "item.page.collections.loading": "Ladataan...", + + // "item.page.collections.load-more": "Load more", + "item.page.collections.load-more": "Lataa lisää", + // "item.page.date": "Date", "item.page.date": "Päivämäärä", @@ -2634,6 +3568,12 @@ // "item.page.link.simple": "Simple item page", "item.page.link.simple": "Tietueen suppeat tiedot", + // "item.page.orcid.title": "ORCID", + "item.page.orcid.title": "ORCID-tunniste", + + // "item.page.orcid.tooltip": "Open ORCID setting page", + "item.page.orcid.tooltip": "Avaa ORCID-asetusten sivu", + // "item.page.person.search.title": "Articles by this author", "item.page.person.search.title": "Tekijän artikkelit", @@ -2667,12 +3607,27 @@ // "item.page.bitstreams.collapse": "Collapse", "item.page.bitstreams.collapse": "Sulje", - // "item.page.filesection.original.bundle" : "Original bundle", + // "item.page.filesection.original.bundle": "Original bundle", "item.page.filesection.original.bundle": "Alkuperäinen nippu", - // "item.page.filesection.license.bundle" : "License bundle", + // "item.page.filesection.license.bundle": "License bundle", "item.page.filesection.license.bundle": "Lisenssinippu", + // "item.page.return": "Back", + "item.page.return": "Paluu", + + // "item.page.version.create": "Create new version", + "item.page.version.create": "Luo uusi versio", + + // "item.page.version.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history", + "item.page.version.hasDraft": "Uutta versiota ei voida luoda, koska versiohistoriassa on kesken oleva tallennus.", + + // "item.page.claim.button": "Claim", + "item.page.claim.button": "Ota itsellesi", + + // "item.page.claim.tooltip": "Claim this item as profile", + "item.page.claim.tooltip": "Ota tämä kohde profiiliksi", + // "item.preview.dc.identifier.uri": "Identifier:", "item.preview.dc.identifier.uri": "Tunnus:", @@ -2680,7 +3635,7 @@ "item.preview.dc.contributor.author": "Tekijät:", // "item.preview.dc.date.issued": "Published date:", - "item.preview.dc.date.issued": "Julkaisuajankohta:", + "item.preview.dc.date.issued": "Julkaisuaika:", // "item.preview.dc.description.abstract": "Abstract:", "item.preview.dc.description.abstract": "Tiivistelmä:", @@ -2697,6 +3652,33 @@ // "item.preview.dc.title": "Title:", "item.preview.dc.title": "Nimeke:", + // "item.preview.dc.type": "Type:", + "item.preview.dc.type": "Tyyppi:", + + // "item.preview.oaire.citation.issue": "Issue", + "item.preview.oaire.citation.issue": "Numero", + + // "item.preview.oaire.citation.volume": "Volume", + "item.preview.oaire.citation.volume": "Vuosikerta", + + // "item.preview.dc.relation.issn": "ISSN", + "item.preview.dc.relation.issn": "ISSN-tunnus", + + // "item.preview.dc.identifier.isbn": "ISBN", + "item.preview.dc.identifier.isbn": "ISBN", + + // "item.preview.dc.identifier": "Identifier:", + "item.preview.dc.identifier": "Tunnisteet:", + + // "item.preview.dc.relation.ispartof": "Journal or Serie", + "item.preview.dc.relation.ispartof": "Kausijulkaisu tai sarja", + + // "item.preview.dc.identifier.doi": "DOI", + "item.preview.dc.identifier.doi": "DOI", + + // "item.preview.dc.publisher": "Publisher:", + "item.preview.dc.publisher": "Julkaisija:", + // "item.preview.person.familyName": "Surname:", "item.preview.person.familyName": "Sukunimi:", @@ -2706,6 +3688,23 @@ // "item.preview.person.identifier.orcid": "ORCID:", "item.preview.person.identifier.orcid": "ORCID-tunniste:", + // "item.preview.project.funder.name": "Funder:", + "item.preview.project.funder.name": "Rahoittaja:", + + // "item.preview.project.funder.identifier": "Funder Identifier:", + "item.preview.project.funder.identifier": "Rahoittajan tunniste:", + + // "item.preview.oaire.awardNumber": "Funding ID:", + "item.preview.oaire.awardNumber": "Rahoitustunnus:", + + // "item.preview.dc.title.alternative": "Acronym:", + "item.preview.dc.title.alternative": "Kirjainlyhemme:", + + // "item.preview.dc.coverage.spatial": "Jurisdiction:", + "item.preview.dc.coverage.spatial": "Toimivalta:", + + // "item.preview.oaire.fundingStream": "Funding Stream:", + "item.preview.oaire.fundingStream": "Rahoituslähde:", // "item.select.confirm": "Confirm selected", "item.select.confirm": "Vahvista valinta", @@ -2722,19 +3721,21 @@ // "item.select.table.title": "Title", "item.select.table.title": "Nimeke", - // "item.version.history.empty": "There are no other versions for this item yet.", "item.version.history.empty": "Tietueesta ei ole muita versioita.", // "item.version.history.head": "Version History", "item.version.history.head": "Versiohistoria", - // "item.version.history.return": "Return", - "item.version.history.return": "Palaa", + // "item.version.history.return": "Back", + "item.version.history.return": "Paluu", // "item.version.history.selected": "Selected version", "item.version.history.selected": "Valittu versio", + // "item.version.history.selected.alert": "You are currently viewing version {{version}} of the item.", + "item.version.history.selected.alert": "Tarkastelet tietueen versiota {{version}}.", + // "item.version.history.table.version": "Version", "item.version.history.table.version": "Versio", @@ -2750,12 +3751,191 @@ // "item.version.history.table.summary": "Summary", "item.version.history.table.summary": "Yhteenveto", + // "item.version.history.table.workspaceItem": "Workspace item", + "item.version.history.table.workspaceItem": "Työtilan tietue", + + // "item.version.history.table.workflowItem": "Workflow item", + "item.version.history.table.workflowItem": "Työtilan tietue", + + // "item.version.history.table.actions": "Action", + "item.version.history.table.actions": "Toiminto", + + // "item.version.history.table.action.editWorkspaceItem": "Edit workspace item", + "item.version.history.table.action.editWorkspaceItem": "Muokkaa työtilan tietuetta", + + // "item.version.history.table.action.editSummary": "Edit summary", + "item.version.history.table.action.editSummary": "Muokkaa yhteenvetoa", + + // "item.version.history.table.action.saveSummary": "Save summary edits", + "item.version.history.table.action.saveSummary": "Tallenna yhteenvedon muokkaukset", + + // "item.version.history.table.action.discardSummary": "Discard summary edits", + "item.version.history.table.action.discardSummary": "Hylkää yhteenvedon muokkaukset", + + // "item.version.history.table.action.newVersion": "Create new version from this one", + "item.version.history.table.action.newVersion": "Luo tästä uusi versio", + + // "item.version.history.table.action.deleteVersion": "Delete version", + "item.version.history.table.action.deleteVersion": "Poista versio", + // "item.version.history.table.action.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history", + "item.version.history.table.action.hasDraft": "Uutta versiota ei voida luoda, koska versiohistoriassa on kesken oleva tallennus.", // "item.version.notice": "This is not the latest version of this item. The latest version can be found <a href='{{destination}}'>here</a>.", "item.version.notice": "Tämä ei ole tietueen uusin versio. Uusin versio löytyy <a href='{{destination}}'>täältä</a>.", + // "item.version.create.modal.header": "New version", + "item.version.create.modal.header": "uusi versio", + + // "item.version.create.modal.text": "Create a new version for this item", + "item.version.create.modal.text": "Luodaan tietueesta uusi versio", + + // "item.version.create.modal.text.startingFrom": "starting from version {{version}}", + "item.version.create.modal.text.startingFrom": "alkaen versiosta {{version}}", + + // "item.version.create.modal.button.confirm": "Create", + "item.version.create.modal.button.confirm": "Luo", + + // "item.version.create.modal.button.confirm.tooltip": "Create new version", + "item.version.create.modal.button.confirm.tooltip": "Luo uusi versio", + + // "item.version.create.modal.button.cancel": "Cancel", + "item.version.create.modal.button.cancel": "Peruuta", + + // "item.version.create.modal.button.cancel.tooltip": "Do not create new version", + "item.version.create.modal.button.cancel.tooltip": "Älä luo uutta versiota", + + // "item.version.create.modal.form.summary.label": "Summary", + "item.version.create.modal.form.summary.label": "Yhteenveto", + + // "item.version.create.modal.form.summary.placeholder": "Insert the summary for the new version", + "item.version.create.modal.form.summary.placeholder": "Syötä uuden version yhteenveto", + + // "item.version.create.modal.submitted.header": "Creating new version...", + "item.version.create.modal.submitted.header": "Luodaan uutta versiota...", + + // "item.version.create.modal.submitted.text": "The new version is being created. This may take some time if the item has a lot of relationships.", + "item.version.create.modal.submitted.text": "Uutta versiota luodaan. Luonti voi kestää, jos tietueella on paljon yhteyksiä.", + + // "item.version.create.notification.success": "New version has been created with version number {{version}}", + "item.version.create.notification.success": "Uusi versio on luotu, sen versionumero on {{version}}", + + // "item.version.create.notification.failure": "New version has not been created", + "item.version.create.notification.failure": "Uutta versiota ei luotu", + + // "item.version.create.notification.inProgress": "A new version cannot be created because there is an inprogress submission in the version history", + "item.version.create.notification.inProgress": "Uutta versiota ei voida luoda, koska versiohistoriassa on kesken oleva tallennus.", + + // "item.version.delete.modal.header": "Delete version", + "item.version.delete.modal.header": "Poista versio", + + // "item.version.delete.modal.text": "Do you want to delete version {{version}}?", + "item.version.delete.modal.text": "Haluatko poistaa version {{version}}?", + + // "item.version.delete.modal.button.confirm": "Delete", + "item.version.delete.modal.button.confirm": "Poista", + // "item.version.delete.modal.button.confirm.tooltip": "Delete this version", + "item.version.delete.modal.button.confirm.tooltip": "Poista tämä versio", + + // "item.version.delete.modal.button.cancel": "Cancel", + "item.version.delete.modal.button.cancel": "Peruuta", + + // "item.version.delete.modal.button.cancel.tooltip": "Do not delete this version", + "item.version.delete.modal.button.cancel.tooltip": "Älä poista tätä versiota", + + // "item.version.delete.notification.success": "Version number {{version}} has been deleted", + "item.version.delete.notification.success": "Versio versionumerolla {{version}} poistettu", + + // "item.version.delete.notification.failure": "Version number {{version}} has not been deleted", + "item.version.delete.notification.failure": "Versiota versionumerolla {{version}} ei poistettu", + + // "item.version.edit.notification.success": "The summary of version number {{version}} has been changed", + "item.version.edit.notification.success": "Version versionumerolla {{version}} yhteenveto on muuttunut", + + // "item.version.edit.notification.failure": "The summary of version number {{version}} has not been changed", + "item.version.edit.notification.failure": "Version versionumerolla {{version}} yhteenvetoa ei ole muutettu", + + // "itemtemplate.edit.metadata.add-button": "Add", + "itemtemplate.edit.metadata.add-button": "Lisää", + + // "itemtemplate.edit.metadata.discard-button": "Discard", + "itemtemplate.edit.metadata.discard-button": "Hylkää", + + // "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirm", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Vahvista", + + // "itemtemplate.edit.metadata.edit.buttons.drag": "Drag to reorder", + "itemtemplate.edit.metadata.edit.buttons.drag": "Raahaa uudelleenjärjestääksesi", + + // "itemtemplate.edit.metadata.edit.buttons.edit": "Edit", + "itemtemplate.edit.metadata.edit.buttons.edit": "Muokkaa", + + // "itemtemplate.edit.metadata.edit.buttons.remove": "Remove", + "itemtemplate.edit.metadata.edit.buttons.remove": "Poista", + + // "itemtemplate.edit.metadata.edit.buttons.undo": "Undo changes", + "itemtemplate.edit.metadata.edit.buttons.undo": "Kumoa muutokset", + + // "itemtemplate.edit.metadata.edit.buttons.unedit": "Stop editing", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Lopeta muokkaus", + + // "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": "Mallipohjassa ei ole metadataa. Napsauta Lisää lisätäksesi metadata-arvoja.", + + // "itemtemplate.edit.metadata.headers.edit": "Edit", + "itemtemplate.edit.metadata.headers.edit": "Muokkaa", + + // "itemtemplate.edit.metadata.headers.field": "Field", + "itemtemplate.edit.metadata.headers.field": "Kenttä", + + // "itemtemplate.edit.metadata.headers.language": "Lang", + "itemtemplate.edit.metadata.headers.language": "Kieli", + + // "itemtemplate.edit.metadata.headers.value": "Value", + "itemtemplate.edit.metadata.headers.value": "Arvo", + + // "itemtemplate.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", + "itemtemplate.edit.metadata.metadatafield.error": "Virhe metadatakenttää validoitaessa", + + // "itemtemplate.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + "itemtemplate.edit.metadata.metadatafield.invalid": "Valitse kelvollinen metadatakenttä ", + + // "itemtemplate.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "itemtemplate.edit.metadata.notifications.discarded.content": "Muutoksesi hylättiin. Palauta muutokset napsauttamalla Kumoa-painiketta", + + // "itemtemplate.edit.metadata.notifications.discarded.title": "Changes discarded", + "itemtemplate.edit.metadata.notifications.discarded.title": "Muutokset peruttu", + + // "itemtemplate.edit.metadata.notifications.error.title": "An error occurred", + "itemtemplate.edit.metadata.notifications.error.title": "Tapahtui virhe", + + // "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": "Muutoksia ei tallennettu. Tarkista kaikkien kenttien oikeellisuus ennen tallennusta.", + + // "itemtemplate.edit.metadata.notifications.invalid.title": "Metadata invalid", + "itemtemplate.edit.metadata.notifications.invalid.title": "Virheellinen metadata", + + // "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": "Toinen käyttäjä on muokannut käsittelemääsi mallipohjaa. Muutoksesi on hylätty konfliktien välttämiseksi.", + + // "itemtemplate.edit.metadata.notifications.outdated.title": "Changes outdated", + "itemtemplate.edit.metadata.notifications.outdated.title": "Muutokset vanhentuneet", + + // "itemtemplate.edit.metadata.notifications.saved.content": "Your changes to this item template's metadata were saved.", + "itemtemplate.edit.metadata.notifications.saved.content": "Muutokset mallipohjan metadataan on tallennettu.", + + // "itemtemplate.edit.metadata.notifications.saved.title": "Metadata saved", + "itemtemplate.edit.metadata.notifications.saved.title": "Metadata tallennettu", + + // "itemtemplate.edit.metadata.reinstate-button": "Undo", + "itemtemplate.edit.metadata.reinstate-button": "Kumoa", + + // "itemtemplate.edit.metadata.reset-order-button": "Undo reorder", + "itemtemplate.edit.metadata.reset-order-button": "Kumoa uudelleenjärjestäminen", + + // "itemtemplate.edit.metadata.save-button": "Save", + "itemtemplate.edit.metadata.save-button": "Tallenna", // "journal.listelement.badge": "Journal", "journal.listelement.badge": "Kausijulkaisu", @@ -2781,10 +3961,11 @@ // "journal.search.results.head": "Journal Search Results", "journal.search.results.head": "Kausijulkaisuhaun tulokset", - // "journal.search.title": "DSpace Angular :: Journal Search", - "journal.search.title": "DSpace Angular :: Kausijulkaisuhaku", - + // "journal-relationships.search.results.head": "Journal Search Results", + "journal-relationships.search.results.head": "Kausijulkaisuhaun tulokset", + // "journal.search.title": "Journal Search", + "journal.search.title": "Kausijulkaisuhaku", // "journalissue.listelement.badge": "Journal Issue", "journalissue.listelement.badge": "Kausijulkaisun numero", @@ -2813,8 +3994,6 @@ // "journalissue.page.titleprefix": "Journal Issue: ", "journalissue.page.titleprefix": "Kausijulkaisun numero: ", - - // "journalvolume.listelement.badge": "Journal Volume", "journalvolume.listelement.badge": "Kausijulkaisun vuosikerta", @@ -2833,7 +4012,38 @@ // "journalvolume.page.volume": "Volume", "journalvolume.page.volume": "Vuosikerta", + // "iiifsearchable.listelement.badge": "Document Media", + "iiifsearchable.listelement.badge": "Dokumenttimedia", + + // "iiifsearchable.page.titleprefix": "Document: ", + "iiifsearchable.page.titleprefix": "Dokumentti: ", + + // "iiifsearchable.page.doi": "Permanent Link: ", + "iiifsearchable.page.doi": "Pysyvä linkki: ", + + // "iiifsearchable.page.issue": "Issue: ", + "iiifsearchable.page.issue": "Numero: ", + + // "iiifsearchable.page.description": "Description: ", + "iiifsearchable.page.description": "Kuvaus: ", + // "iiifviewer.fullscreen.notice": "Use full screen for better viewing.", + "iiifviewer.fullscreen.notice": "Käytä koko näytön tilaa nähdäksesi paremmin", + + // "iiif.listelement.badge": "Image Media", + "iiif.listelement.badge": "Kuvamedia", + + // "iiif.page.titleprefix": "Image: ", + "iiif.page.titleprefix": "Kuva: ", + + // "iiif.page.doi": "Permanent Link: ", + "iiif.page.doi": "Pysyvä linkki: ", + + // "iiif.page.issue": "Issue: ", + "iiif.page.issue": "Numero: ", + + // "iiif.page.description": "Description: ", + "iiif.page.description": "Kuvaus: ", // "loading.bitstream": "Loading bitstream...", "loading.bitstream": "Ladataan tiedostoa...", @@ -2889,8 +4099,6 @@ // "loading.top-level-communities": "Loading top-level communities...", "loading.top-level-communities": "Ladataan ylätason yhteisöjä...", - - // "login.form.email": "Email address", "login.form.email": "Sähköpostiosoite", @@ -2906,6 +4114,12 @@ // "login.form.or-divider": "or", "login.form.or-divider": "tai", + // "login.form.oidc": "Log in with OIDC", + "login.form.oidc": "Kirjaudu OIDC-tunnuksella", + + // "login.form.orcid": "Log in with ORCID", + "login.form.orcid": "Kirjaudu ORCID-tunnuksella", + // "login.form.password": "Password", "login.form.password": "Salasana", @@ -2921,8 +4135,6 @@ // "login.breadcrumbs": "Login", "login.breadcrumbs": "Sisäänkirjautuminen", - - // "logout.form.header": "Log out from DSpace", "logout.form.header": "Kirjaudu ulos", @@ -2932,15 +4144,14 @@ // "logout.title": "Logout", "logout.title": "Uloskirjautuminen", - - - // "menu.header.admin": "Admin", - "menu.header.admin": "Ylläpitäjä", + // "menu.header.admin": "Management", + "menu.header.admin": "Hallinto", // "menu.header.image.logo": "Repository logo", "menu.header.image.logo": "Arkiston logo", - + // "menu.header.admin.description": "Management menu", + "menu.header.admin.description": "Hallintovalikko", // "menu.section.access_control": "Access Control", "menu.section.access_control": "Pääsyoikeudet", @@ -2954,13 +4165,9 @@ // "menu.section.access_control_people": "People", "menu.section.access_control_people": "Käyttäjät", - - // "menu.section.admin_search": "Admin Search", "menu.section.admin_search": "Ylläpitäjän haku", - - // "menu.section.browse_community": "This Community", "menu.section.browse_community": "Tämä yhteisö", @@ -2968,7 +4175,7 @@ "menu.section.browse_community_by_author": "Tekijän mukaan", // "menu.section.browse_community_by_issue_date": "By Issue Date", - "menu.section.browse_community_by_issue_date": "Julkaisuajankohdan mukaan", + "menu.section.browse_community_by_issue_date": "Julkaisuajan mukaan", // "menu.section.browse_community_by_title": "By Title", "menu.section.browse_community_by_title": "Nimekkeen mukaan", @@ -2980,27 +4187,26 @@ "menu.section.browse_global_by_author": "Tekijän mukaan", // "menu.section.browse_global_by_dateissued": "By Issue Date", - "menu.section.browse_global_by_dateissued": "Julkaisuajankohdan mukaan", + "menu.section.browse_global_by_dateissued": "Julkaisuajan mukaan", // "menu.section.browse_global_by_subject": "By Subject", "menu.section.browse_global_by_subject": "Asiasanan mukaan", + // "menu.section.browse_global_by_srsc": "By Subject Category", + "menu.section.browse_global_by_srsc": "Aihekategorian mukaan", + // "menu.section.browse_global_by_title": "By Title", "menu.section.browse_global_by_title": "Nimekkeen mukaan", // "menu.section.browse_global_communities_and_collections": "Communities & Collections", "menu.section.browse_global_communities_and_collections": "Yhteisöt & kokoelmat", - - // "menu.section.control_panel": "Control Panel", "menu.section.control_panel": "Hallintapaneeli", // "menu.section.curation_task": "Curation Task", "menu.section.curation_task": "Kuratointitehtävä", - - // "menu.section.edit": "Edit", "menu.section.edit": "Muokkaa", @@ -3013,8 +4219,6 @@ // "menu.section.edit_item": "Item", "menu.section.edit_item": "Tietue", - - // "menu.section.export": "Export", "menu.section.export": "Eksportoi", @@ -3030,7 +4234,8 @@ // "menu.section.export_metadata": "Metadata", "menu.section.export_metadata": "Metadata", - + // "menu.section.export_batch": "Batch Export (ZIP)", + "menu.section.export_batch": "Erän eksportointi(ZIP)", // "menu.section.icon.access_control": "Access Control menu section", "menu.section.icon.access_control": "Pääsyoikeudet", @@ -3041,8 +4246,8 @@ // "menu.section.icon.control_panel": "Control Panel menu section", "menu.section.icon.control_panel": "Hallintapaneeli", - // "menu.section.icon.curation_task": "Curation Task menu section", - "menu.section.icon.curation_task": "Kuratointi", + // "menu.section.icon.curation_tasks": "Curation Task menu section", + "menu.section.icon.curation_tasks": "Kuratointitehtävä", // "menu.section.icon.edit": "Edit menu section", "menu.section.icon.edit": "Muokkaus", @@ -3053,6 +4258,9 @@ // "menu.section.icon.find": "Find menu section", "menu.section.icon.find": "Haku", + // "menu.section.icon.health": "Health check menu section", + "menu.section.icon.health": "Järjestelmän kunnon tarkistus", + // "menu.section.icon.import": "Import menu section", "menu.section.icon.import": "Importointi", @@ -3062,8 +4270,8 @@ // "menu.section.icon.pin": "Pin sidebar", "menu.section.icon.pin": "Kiinnitä sivupalkki", - // "menu.section.icon.processes": "Processes menu section", - "menu.section.icon.processes": "Prosessit", + // "menu.section.icon.processes": "Processes Health", + "menu.section.icon.processes": "Prosessien kunto", // "menu.section.icon.registries": "Registries menu section", "menu.section.icon.registries": "Rekisterit", @@ -3071,11 +4279,12 @@ // "menu.section.icon.statistics_task": "Statistics Task menu section", "menu.section.icon.statistics_task": "Tilastot", + // "menu.section.icon.workflow": "Administer workflow menu section", + "menu.section.icon.workflow": "Työnkulku hallinta", + // "menu.section.icon.unpin": "Unpin sidebar", "menu.section.icon.unpin": "Vapauta sivupalkki", - - // "menu.section.import": "Import", "menu.section.import": "Importoi", @@ -3085,8 +4294,6 @@ // "menu.section.import_metadata": "Metadata", "menu.section.import_metadata": "Metadata", - - // "menu.section.new": "New", "menu.section.new": "Uusi", @@ -3105,20 +4312,17 @@ // "menu.section.new_process": "Process", "menu.section.new_process": "Prosessi", - - // "menu.section.pin": "Pin sidebar", "menu.section.pin": "Kiinnitä sivupalkki", // "menu.section.unpin": "Unpin sidebar", "menu.section.unpin": "Vapauta sivupalkki", - - // "menu.section.processes": "Processes", "menu.section.processes": "Prosessit", - + // "menu.section.health": "Health", + "menu.section.health": "Järjestelmän kunto", // "menu.section.registries": "Registries", "menu.section.registries": "Rekisterit", @@ -3129,57 +4333,60 @@ // "menu.section.registries_metadata": "Metadata", "menu.section.registries_metadata": "Metadata", - - // "menu.section.statistics": "Statistics", "menu.section.statistics": "Tilastot", // "menu.section.statistics_task": "Statistics Task", "menu.section.statistics_task": "Tilastointitehtävä", - - // "menu.section.toggle.access_control": "Toggle Access Control section", - "menu.section.toggle.access_control": "Vaihda Pääsyoikeudet-osion tilaa", + "menu.section.toggle.access_control": "Näytä/piilota Pääsyoikeudet-osio", // "menu.section.toggle.control_panel": "Toggle Control Panel section", - "menu.section.toggle.control_panel": "Vaihda Hallintapaneeli-osion tilaa", + "menu.section.toggle.control_panel": "Näytä/piilota Hallintapaneeli-osio", // "menu.section.toggle.curation_task": "Toggle Curation Task section", - "menu.section.toggle.curation_task": "Vaihda Kuratointitehtävä-osion tilaa", + "menu.section.toggle.curation_task": "Näytä/piilota Kuratointitehtävä-osio", // "menu.section.toggle.edit": "Toggle Edit section", - "menu.section.toggle.edit": "Vaihda Muokkaus-osion tilaa", + "menu.section.toggle.edit": "Näytä/piilota Muokkaus-osio", // "menu.section.toggle.export": "Toggle Export section", - "menu.section.toggle.export": "Vaihda Eksportointi-osion tilaa", + "menu.section.toggle.export": "Näytä/piilota Eksportointi-osio", // "menu.section.toggle.find": "Toggle Find section", - "menu.section.toggle.find": "Vaihda Haku-osion tilaa", + "menu.section.toggle.find": "Näytä/piilota Haku-osio", // "menu.section.toggle.import": "Toggle Import section", - "menu.section.toggle.import": "Vaihda Importointi-osion tilaa", + "menu.section.toggle.import": "Näytä/piilota Importointi-osio", // "menu.section.toggle.new": "Toggle New section", - "menu.section.toggle.new": "Vaihda Uusi-osion tilaa", + "menu.section.toggle.new": "Näytä/piilota Uusi-osio", // "menu.section.toggle.registries": "Toggle Registries section", - "menu.section.toggle.registries": "Vaihda Rekisterit-osion tilaa", + "menu.section.toggle.registries": "Näytä/piilota Rekisterit-osio", // "menu.section.toggle.statistics_task": "Toggle Statistics Task section", - "menu.section.toggle.statistics_task": "Vaihda Tilastointitehtävä-osion tilaa", - + "menu.section.toggle.statistics_task": "Näytä/piilota Tilastointitehtävä-osio", // "menu.section.workflow": "Administer Workflow", "menu.section.workflow": "Hallinnoi työnkulkua", + // "metadata-export-search.tooltip": "Export search results as CSV", + "metadata-export-search.tooltip": "Eksportoi Hakutulokset CSV-tiedostona", + + // "metadata-export-search.submit.success": "The export was started successfully", + "metadata-export-search.submit.success": "Eksportointi aloitettu", + + // "metadata-export-search.submit.error": "Starting the export has failed", + "metadata-export-search.submit.error": "Eksportoinnin aloittaminen epäonnistui", + + // "mydspace.breadcrumbs": "MyDSpace", + "mydspace.breadcrumbs": "Oma DSpace", // "mydspace.description": "", "mydspace.description": "", - // "mydspace.general.text-here": "here", - "mydspace.general.text-here": "tässä", - // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", "mydspace.messages.controller-help": "Valitse tämä, jos haluat lähettää viestin tietueen tallentajalle.", @@ -3255,26 +4462,32 @@ // "mydspace.results.no-uri": "No Uri", "mydspace.results.no-uri": "Ei URL-osoitetta", - // "mydspace.show.workflow": "All tasks", - "mydspace.show.workflow": "Kaikki tehtävät", + // "mydspace.search-form.placeholder": "Search in mydspace...", + "mydspace.search-form.placeholder": "Hae omasta DSpacesta...", + + // "mydspace.show.workflow": "Workflow tasks", + "mydspace.show.workflow": "Työnkulun tehtävät", // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Tallennuksesi", - // "mydspace.status.archived": "Archived", - "mydspace.status.archived": "Arkistoitu", + // "mydspace.show.supervisedWorkspace": "Supervised items", + "mydspace.show.supervisedWorkspace": "Valvotut tietueet", + + // "mydspace.status.mydspaceArchived": "Archived", + "mydspace.status.mydspaceArchived": "Arkistoitu", - // "mydspace.status.validation": "Validation", - "mydspace.status.validation": "Tarkastaminen", + // "mydspace.status.mydspaceValidation": "Validation", + "mydspace.status.mydspaceValidation": "Validointi", - // "mydspace.status.waiting-for-controller": "Waiting for controller", - "mydspace.status.waiting-for-controller": "Odotetaan tarkastajaa", + // "mydspace.status.mydspaceWaitingController": "Waiting for controller", + "mydspace.status.mydspaceWaitingController": "Odottaa tarkastajaa", - // "mydspace.status.workflow": "Workflow", - "mydspace.status.workflow": "Työnkulku", + // "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkflow": "Työnkulku", - // "mydspace.status.workspace": "Workspace", - "mydspace.status.workspace": "Työtila", + // "mydspace.status.mydspaceWorkspace": "Workspace", + "mydspace.status.mydspaceWorkspace": "Työtila", // "mydspace.title": "MyDSpace", "mydspace.title": "Oma DSpace", @@ -3291,31 +4504,35 @@ // "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", "mydspace.upload.upload-multiple-successful": "{{qty}} uutta työtilaa luotu.", - // "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", - "mydspace.upload.upload-successful": "Uusi työtila luotu. Napauta tästä muokataksesi sitä.", - // "mydspace.view-btn": "View", "mydspace.view-btn": "Näytä", - - // "nav.browse.header": "All of DSpace", "nav.browse.header": "Koko julkaisuarkisto", // "nav.community-browse.header": "By Community", "nav.community-browse.header": "Yhteisön mukaan", + // "nav.context-help-toggle": "Toggle context help", + "nav.context-help-toggle": "Näytä/piilota tilannekohtainen ohje", + // "nav.language": "Language switch", "nav.language": "Kielivalinta", // "nav.login": "Log In", "nav.login": "Kirjaudu sisään", + // "nav.user-profile-menu-and-logout": "User profile menu and Log Out", + "nav.user-profile-menu-and-logout": "Käyttäjäprofiilivalikko ja uloskirjautuminen", + // "nav.logout": "Log Out", "nav.logout": "Kirjaudu ulos", + // "nav.main.description": "Main navigation bar", + "nav.main.description": "Päänavigointipalkki", + // "nav.mydspace": "MyDSpace", - "nav.mydspace": "Omat tiedot", + "nav.mydspace": "Oma DSpace", // "nav.profile": "Profile", "nav.profile": "Profiili", @@ -3323,17 +4540,33 @@ // "nav.search": "Search", "nav.search": "Hae", + // "nav.search.button": "Submit search", + "nav.search.button": "Lähetä haku", + // "nav.statistics.header": "Statistics", "nav.statistics.header": "Tilastot", // "nav.stop-impersonating": "Stop impersonating EPerson", "nav.stop-impersonating": "Lopeta käyttäjänä esiintyminen", + // "nav.subscriptions": "Subscriptions", + "nav.subscriptions": "Tilaukset", + + // "nav.toggle": "Toggle navigation", + "nav.toggle": "Näytä/piilota navigointi", + // "nav.user.description": "User profile bar", + "nav.user.description": "Käyttäjäprofiilipalkki", + + // "none.listelement.badge": "Item", + "none.listelement.badge": "Tietue", // "orgunit.listelement.badge": "Organizational Unit", "orgunit.listelement.badge": "Organisaatioyksikkö", + // "orgunit.listelement.no-title": "Untitled", + "orgunit.listelement.no-title": "Nimetön", + // "orgunit.page.city": "City", "orgunit.page.city": "Kaupunki", @@ -3355,7 +4588,8 @@ // "orgunit.page.titleprefix": "Organizational Unit: ", "orgunit.page.titleprefix": "Organisaatioyksikkö: ", - + // "pagination.options.description": "Pagination options", + "pagination.options.description": "Sivutusvaihtoehdot", // "pagination.results-per-page": "Results Per Page", "pagination.results-per-page": "Tuloksia sivulla", @@ -3369,8 +4603,6 @@ // "pagination.sort-direction": "Sort Options", "pagination.sort-direction": "Lajitteluvalinnat", - - // "person.listelement.badge": "Person", "person.listelement.badge": "Käyttäjä", @@ -3395,6 +4627,9 @@ // "person.page.lastname": "Last Name", "person.page.lastname": "Sukunimi", + // "person.page.name": "Name", + "person.page.name": "Nimi", + // "person.page.link.full": "Show all metadata", "person.page.link.full": "Näytä kaikki metadata", @@ -3408,12 +4643,13 @@ "person.page.titleprefix": "Käyttäjä: ", // "person.search.results.head": "Person Search Results", - "person.search.results.head": "Käyttäjähaun tulokset", - - // "person.search.title": "DSpace Angular :: Person Search", - "person.search.title": "DSpace Angular :: Käyttäjähaku", + "person.search.results.head": "Henkilöhaun tulokset", + // "person-relationships.search.results.head": "Person Search Results", + "person-relationships.search.results.head": "Henkilöhaun tulokset", + // "person.search.title": "Person Search", + "person.search.title": "Henkilöhaku", // "process.new.select-parameters": "Parameters", "process.new.select-parameters": "Parametrit", @@ -3421,8 +4657,8 @@ // "process.new.cancel": "Cancel", "process.new.cancel": "Peruuta", - // "process.new.submit": "Submit", - "process.new.submit": "Lähetä", + // "process.new.submit": "Save", + "process.new.submit": "Tallenna", // "process.new.select-script": "Script", "process.new.select-script": "Skripti", @@ -3463,6 +4699,9 @@ // "process.new.notification.error.content": "An error occurred while creating this process", "process.new.notification.error.content": "Virhe prosessia luotaessa", + // "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", + "process.new.notification.error.max-upload.content": "Tiedoston koko ylittää latauksen maksimikoon", + // "process.new.header": "Create a new process", "process.new.header": "Luo uusi prosessi", @@ -3472,18 +4711,16 @@ // "process.new.breadcrumbs": "Create a new process", "process.new.breadcrumbs": "Luo uusi prosessi", + // "process.detail.arguments": "Arguments", + "process.detail.arguments": "Perustelut", + // "process.detail.arguments.empty": "This process doesn't contain any arguments", + "process.detail.arguments.empty": "Prosessiin ei liity perusteluja", - // "process.detail.arguments" : "Arguments", - "process.detail.arguments": "Muuttujat", - - // "process.detail.arguments.empty" : "This process doesn't contain any arguments", - "process.detail.arguments.empty": "Prosessiin ei liity muuttujia", - - // "process.detail.back" : "Back", + // "process.detail.back": "Back", "process.detail.back": "Paluu", - // "process.detail.output" : "Process Output", + // "process.detail.output": "Process Output", "process.detail.output": "Prosessin tulos", // "process.detail.logs.button": "Retrieve process output", @@ -3495,48 +4732,70 @@ // "process.detail.logs.none": "This process has no output", "process.detail.logs.none": "Prosessilla ei tulosta", - // "process.detail.output-files" : "Output Files", + // "process.detail.output-files": "Output Files", "process.detail.output-files": "Tulostiedostot", - // "process.detail.output-files.empty" : "This process doesn't contain any output files", + // "process.detail.output-files.empty": "This process doesn't contain any output files", "process.detail.output-files.empty": "Prosessilla ei ole tulostiedostoja", - // "process.detail.script" : "Script", + // "process.detail.script": "Script", "process.detail.script": "Skripti", - // "process.detail.title" : "Process: {{ id }} - {{ name }}", + // "process.detail.title": "Process: {{ id }} - {{ name }}", "process.detail.title": "Prosessi: {{ id }} - {{ name }}", - // "process.detail.start-time" : "Start time", + // "process.detail.start-time": "Start time", "process.detail.start-time": "Aloitusaika", - // "process.detail.end-time" : "Finish time", + // "process.detail.end-time": "Finish time", "process.detail.end-time": "Lopetusaika", - // "process.detail.status" : "Status", + // "process.detail.status": "Status", "process.detail.status": "Tila", - // "process.detail.create" : "Create similar process", + // "process.detail.create": "Create similar process", "process.detail.create": "Luo vastaava prosessi", + // "process.detail.actions": "Actions", + "process.detail.actions": "Toiminnot", + + // "process.detail.delete.button": "Delete process", + "process.detail.delete.button": "Poista prosessi", + + // "process.detail.delete.header": "Delete process", + "process.detail.delete.header": "Poista prosessi", + + // "process.detail.delete.body": "Are you sure you want to delete the current process?", + "process.detail.delete.body": "Haluatko varmasti poistaa nykyisen prosessin?", + + // "process.detail.delete.cancel": "Cancel", + "process.detail.delete.cancel": "Peruuta", + + // "process.detail.delete.confirm": "Delete process", + "process.detail.delete.confirm": "Poista prosessi", + + // "process.detail.delete.success": "The process was successfully deleted.", + "process.detail.delete.success": "Prosessi on poistettu.", + // "process.detail.delete.error": "Something went wrong when deleting the process", + "process.detail.delete.error": "Virhe prosessia poistettaessa", - // "process.overview.table.finish" : "Finish time", - "process.overview.table.finish": "Lopetusaika", + // "process.overview.table.finish": "Finish time (UTC)", + "process.overview.table.finish": "Lopetusaika (UTC)", - // "process.overview.table.id" : "Process ID", + // "process.overview.table.id": "Process ID", "process.overview.table.id": "Prosessin ID", - // "process.overview.table.name" : "Name", + // "process.overview.table.name": "Name", "process.overview.table.name": "Nimi", - // "process.overview.table.start" : "Start time", - "process.overview.table.start": "Aloitusaika", + // "process.overview.table.start": "Start time (UTC)", + "process.overview.table.start": "Aloitusaika (UTC)", - // "process.overview.table.status" : "Status", + // "process.overview.table.status": "Status", "process.overview.table.status": "Tila", - // "process.overview.table.user" : "User", + // "process.overview.table.user": "User", "process.overview.table.user": "Käyttäjä", // "process.overview.title": "Processes Overview", @@ -3548,6 +4807,32 @@ // "process.overview.new": "New", "process.overview.new": "Uusi", + // "process.overview.table.actions": "Actions", + "process.overview.table.actions": "Toiminnot", + + // "process.overview.delete": "Delete {{count}} processes", + "process.overview.delete": "Poista {{count}} prosessi(a)", + + // "process.overview.delete.clear": "Clear delete selection", + "process.overview.delete.clear": "Tyhjennä poistettavien valinta", + + // "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}} prosessi(a) poistetaan. Odota poiston päättymistä. Poisto saattaa kestää hetken.", + + // "process.overview.delete.body": "Are you sure you want to delete {{count}} process(es)?", + "process.overview.delete.body": "Haluatko varmasti poistaa {{count}} prosessin/prosessia?", + + // "process.overview.delete.header": "Delete processes", + "process.overview.delete.header": "Poista prosessi", + + // "process.bulk.delete.error.head": "Error on deleteing process", + "process.bulk.delete.error.head": "Virhe poistettaessa prosessia", + + // "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": "Prosessia, jonka ID on {{processId}}, ei voitu poistaa. Muiden prosessien poistamista jatketaan.", + + // "process.bulk.delete.success": "{{count}} process(es) have been succesfully deleted", + "process.bulk.delete.success": "{{count}} prosessi(a) poistettu", // "profile.breadcrumbs": "Update Profile", "profile.breadcrumbs": "Päivitä profiili", @@ -3558,11 +4843,14 @@ // "profile.card.security": "Security", "profile.card.security": "Suojaus", - // "profile.form.submit": "Update Profile", - "profile.form.submit": "Päivitä profiili", + // "profile.form.submit": "Save", + "profile.form.submit": "Tallenna", // "profile.groups.head": "Authorization groups you belong to", - "profile.groups.head": "Ryhmät, joihin kuulut", + "profile.groups.head": "Käyttöoikeusryhmät, joihin kuulut", + + // "profile.special.groups.head": "Authorization special groups you belong to", + "profile.special.groups.head": "Erityiset käyttöoikeusryhmät, joihin kuulut", // "profile.head": "Update Profile", "profile.head": "Päivitä profiili", @@ -3603,11 +4891,8 @@ // "profile.security.form.error.matching-passwords": "The passwords do not match.", "profile.security.form.error.matching-passwords": "Salasanat eivät täsmää.", - // "profile.security.form.error.password-length": "The password should be at least 6 characters long.", - "profile.security.form.error.password-length": "Salasanan on oltava vähintään 6 merkkiä pitkä.", - - // "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. It should be at least six characters long.", - "profile.security.form.info": "Voit kirjoittaa uuden salasanan alla olevaan kenttään ja varmentaa sen kirjoittamalla sen uudelleen seuraavaan kenttään. Salasanan pituus on vähintään kuusi merkkiä.", + // "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.", + "profile.security.form.info": "Voit kirjoittaa uuden salasanan alla olevaan kenttään ja varmentaa sen kirjoittamalla sen uudelleen seuraavaan kenttään.", // "profile.security.form.label.password": "Password", "profile.security.form.label.password": "Salasana", @@ -3615,6 +4900,9 @@ // "profile.security.form.label.passwordrepeat": "Retype to confirm", "profile.security.form.label.passwordrepeat": "Kirjoita uudelleen", + // "profile.security.form.label.current-password": "Current password", + "profile.security.form.label.current-password": "Nykyinen salasana", + // "profile.security.form.notifications.success.content": "Your changes to the password were saved.", "profile.security.form.notifications.success.content": "Muuttunut salasana on tallennettu.", @@ -3624,16 +4912,20 @@ // "profile.security.form.notifications.error.title": "Error changing passwords", "profile.security.form.notifications.error.title": "Virhe salasanaa muutettaessa", - // "profile.security.form.notifications.error.not-long-enough": "The password has to be at least 6 characters long.", - "profile.security.form.notifications.error.not-long-enough": "Salasanan on oltava vähintään 6 merkkiä pitkä.", + // "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": "Tapahtui virhe salasanaa muutettaessa. Tarkista, että nykyinen salasana on oikea.", // "profile.security.form.notifications.error.not-same": "The provided passwords are not the same.", "profile.security.form.notifications.error.not-same": "Annetut salasanat eivät täsmää.", + // "profile.security.form.notifications.error.general": "Please fill required fields of security form.", + "profile.security.form.notifications.error.general": "Täytä suojauslomakkeen vaaditut kentät.", + // "profile.title": "Update Profile", "profile.title": "Päivitä profiili", - + // "profile.card.researcher": "Researcher Profile", + "profile.card.researcher": "Tutkijaprofiili", // "project.listelement.badge": "Research Project", "project.listelement.badge": "Tutkimusprojekti", @@ -3668,7 +4960,8 @@ // "project.search.results.head": "Project Search Results", "project.search.results.head": "Projektihaun tulokset", - + // "project-relationships.search.results.head": "Project Search Results", + "project-relationships.search.results.head": "Projektihaun tulokset", // "publication.listelement.badge": "Publication", "publication.listelement.badge": "Julkaisu", @@ -3697,9 +4990,20 @@ // "publication.search.results.head": "Publication Search Results", "publication.search.results.head": "Aineistohaun tulokset", - // "publication.search.title": "DSpace Angular :: Publication Search", - "publication.search.title": "DSpace Angular :: Aineistohaku", + // "publication-relationships.search.results.head": "Publication Search Results", + "publication-relationships.search.results.head": "Aineistohaun tulokset", + + // "publication.search.title": "Publication Search", + "publication.search.title": "Aineistohaku", + // "media-viewer.next": "Next", + "media-viewer.next": "Seuraava", + + // "media-viewer.previous": "Previous", + "media-viewer.previous": "Edellinen", + + // "media-viewer.playlist": "Playlist", + "media-viewer.playlist": "Soittolista", // "register-email.title": "New user registration", "register-email.title": "Uuden käyttäjän rekisteröinti", @@ -3734,8 +5038,8 @@ // "register-page.create-profile.security.header": "Security", "register-page.create-profile.security.header": "Suojaus", - // "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. It should be at least six characters long.", - "register-page.create-profile.security.info": "Syötä salasana alla olevaan kenttään ja vahvista se kirjoittamalla salasana uudelleen seuraavaan kenttään. Salasanan on oltava vähintään kuusi merkkiä pitkä.", + // "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.", + "register-page.create-profile.security.info": "Syötä salasana alla olevaan kenttään ja vahvista se kirjoittamalla salasana uudelleen seuraavaan kenttään.", // "register-page.create-profile.security.label.password": "Password *", "register-page.create-profile.security.label.password": "Salasana *", @@ -3749,14 +5053,11 @@ // "register-page.create-profile.security.error.matching-passwords": "The passwords do not match.", "register-page.create-profile.security.error.matching-passwords": "Salasanat eivät täsmää.", - // "register-page.create-profile.security.error.password-length": "The password should be at least 6 characters long.", - "register-page.create-profile.security.error.password-length": "Salasanan on oltava vähintään 6 merkkiä pitkä.", - // "register-page.create-profile.submit": "Complete Registration", "register-page.create-profile.submit": "Viimeistele rekisteröinti", // "register-page.create-profile.submit.error.content": "Something went wrong while registering a new user.", - "register-page.create-profile.submit.error.content": "Tapahtui virhe uuden käyttäjän rekisteröinnissä.", + "register-page.create-profile.submit.error.content": "Virhe uuden käyttäjän rekisteröinnissä.", // "register-page.create-profile.submit.error.head": "Registration failed", "register-page.create-profile.submit.error.head": "Rekisteröinti epäonnistui", @@ -3767,7 +5068,6 @@ // "register-page.create-profile.submit.success.head": "Registration completed", "register-page.create-profile.submit.success.head": "Rekisteröinti valmis", - // "register-page.registration.header": "New user registration", "register-page.registration.header": "Uuden käyttäjän rekisteröinti", @@ -3780,8 +5080,11 @@ // "register-page.registration.email.error.required": "Please fill in an email address", "register-page.registration.email.error.required": "Anna sähköpostiosoite", - // "register-page.registration.email.error.pattern": "Please fill in a valid email address", - "register-page.registration.email.error.pattern": "Anna toimiva sähköpostiosoite, ole hyvä", + // "register-page.registration.email.error.not-email-form": "Please fill in a valid email address.", + "register-page.registration.email.error.not-email-form": "Anna toimiva sähköpostiosoite", + + // "register-page.registration.email.error.not-valid-domain": "Use email with allowed domains: {{ domains }}", + "register-page.registration.email.error.not-valid-domain": "Käytä sähköpostiosoitetta näillä verkkoalueilla: {{ domains }}", // "register-page.registration.email.hint": "This address will be verified and used as your login name.", "register-page.registration.email.hint": "Osoite varmistetaan, ja se toimii käyttäjätunnuksenasi kirjautumisessa.", @@ -3801,7 +5104,29 @@ // "register-page.registration.error.content": "An error occured when registering the following email address: {{ email }}", "register-page.registration.error.content": "Virhe rekisteröitäessä tätä sähköpostiosoitetta: {{ email }}", + // "register-page.registration.error.recaptcha": "Error when trying to authenticate with recaptcha", + "register-page.registration.error.recaptcha": "Virhe autentikoitaessa recaptcha-toiminnolla", + + // "register-page.registration.google-recaptcha.must-accept-cookies": "In order to register you must accept the <b>Registration and Password recovery</b> (Google reCaptcha) cookies.", + "register-page.registration.google-recaptcha.must-accept-cookies": "Rekisteröityäksesi sinun on hyväksyttävä <b>Rekisteröinnin ja salasanan palauttamisen</b> (Google reCaptcha) evästeet.", + + // "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": "Annettu sähköpostiosoite ei ole rekisteröinnille sallittujen verkkoalueiden joukossa. Sallitut verkkoalueet ovat {{ domains }}", + + // "register-page.registration.google-recaptcha.open-cookie-settings": "Open cookie settings", + "register-page.registration.google-recaptcha.open-cookie-settings": "Avaa evästeasetukset", + // "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + + // "register-page.registration.google-recaptcha.notification.message.error": "An error occurred during reCaptcha verification", + "register-page.registration.google-recaptcha.notification.message.error": "Virhe reCaptcha-todennuksessa", + + // "register-page.registration.google-recaptcha.notification.message.expired": "Verification expired. Please verify again.", + "register-page.registration.google-recaptcha.notification.message.expired": "Todentaminen vanhentunut. Todenna uudelleen.", + + // "register-page.registration.info.maildomain": "Accounts can be registered for mail addresses of the domains", + "register-page.registration.info.maildomain": "Tili voidaan rekisteröidä näiden verkkoalueiden sähköpostiosoitteille", // "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": "Ei {{ type }}-tyyppistä yhteysvastaavuutta kahden tietueen välillä", @@ -3857,7 +5182,23 @@ // "relationships.isContributorOf": "Contributors", "relationships.isContributorOf": "Muut tekijät", + // "relationships.isContributorOf.OrgUnit": "Contributor (Organizational Unit)", + "relationships.isContributorOf.OrgUnit": "Osallistuja (Organisaatioyksikkö)", + + // "relationships.isContributorOf.Person": "Contributor", + "relationships.isContributorOf.Person": "Osallistuja", + // "relationships.isFundingAgencyOf.OrgUnit": "Funder", + "relationships.isFundingAgencyOf.OrgUnit": "Rahoittaja", + + // "repository.image.logo": "Repository logo", + "repository.image.logo": "Julkaisuarkiston logo", + + // "repository.title": "DSpace Repository", + "repository.title": "Julkaisuarkisto", + + // "repository.title.prefix": "DSpace Repository :: ", + "repository.title.prefix": "Julkaisuarkisto :: ", // "resource-policies.add.button": "Add", "resource-policies.add.button": "Lisää", @@ -3910,6 +5251,12 @@ // "resource-policies.edit.page.failure.content": "An error occurred while editing the resource policy.", "resource-policies.edit.page.failure.content": "Virhe muokattaessa resurssikäytäntöä.", + // "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": "Tapahtui virhe muokattaessa resurssikäytännön kohdetta (käyttäjä tai ryhmä).", + + // "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": "Tapahtui virhe resurssikäytäntöä muokattaessa. Kohde (käyttäjä tai ryhmä) on päivitetty onnistuneesti.", + // "resource-policies.edit.page.success.content": "Operation successful", "resource-policies.edit.page.success.content": "Toiminto onnistui", @@ -3943,10 +5290,25 @@ // "resource-policies.form.eperson-group-list.table.headers.name": "Name", "resource-policies.form.eperson-group-list.table.headers.name": "Nimi", + // "resource-policies.form.eperson-group-list.modal.header": "Cannot change type", + "resource-policies.form.eperson-group-list.modal.header": "Tyypin muuttaminen ei onnistu", + + // "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": "Käyttäjän korvaaminen ryhmällä ei ole mahdollista.", + + // "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": "Ryhmän korvaaminen käyttäjällä ei ole mahdollista.", + + // "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": "Poista nykyinen resurssikäytäntö ja luo uusi halutulla tyypillä.", + + // "resource-policies.form.eperson-group-list.modal.close": "Ok", + "resource-policies.form.eperson-group-list.modal.close": "Ok", + // "resource-policies.form.date.end.label": "End Date", "resource-policies.form.date.end.label": "Loppupäivämäärä", - // "resource-policies.form.date.start.label": "Start Date + // "resource-policies.form.date.start.label": "Start Date", "resource-policies.form.date.start.label": "Alkupäivämäärä", // "resource-policies.form.description.label": "Description", @@ -4009,21 +5371,19 @@ // "resource-policies.table.headers.title.for.collection": "Policies for Collection", "resource-policies.table.headers.title.for.collection": "Kokoelmakäytännöt", - - // "search.description": "", "search.description": "", // "search.switch-configuration.title": "Show", "search.switch-configuration.title": "Näytä", - // "search.title": "DSpace Angular :: Search", - "search.title": "DSpace Angular :: Hae", + // "search.title": "Search", + "search.title": "Hae", // "search.breadcrumbs": "Search", "search.breadcrumbs": "Hae", - // "search.search-form.placeholder": "Search the repository ...", + // "search.search-form.placeholder": "Search the repository ...", "search.search-form.placeholder": "Hae julkaisuarkistosta ...", // "search.filters.applied.f.author": "Author", @@ -4038,7 +5398,7 @@ // "search.filters.applied.f.dateSubmitted": "Date submitted", "search.filters.applied.f.dateSubmitted": "Tallennusajankohta", - // "search.filters.applied.f.discoverable": "Private", + // "search.filters.applied.f.discoverable": "Non-discoverable", "search.filters.applied.f.discoverable": "Yksityinen", // "search.filters.applied.f.entityType": "Item Type", @@ -4068,28 +5428,41 @@ // "search.filters.applied.f.birthDate.min": "Start birth date", "search.filters.applied.f.birthDate.min": "Varhaisin syntymäaika", + // "search.filters.applied.f.supervisedBy": "Supervised by", + "search.filters.applied.f.supervisedBy": "Ohjaajana:", + // "search.filters.applied.f.withdrawn": "Withdrawn", "search.filters.applied.f.withdrawn": "Poistettu käytöstä", - - // "search.filters.filter.author.head": "Author", "search.filters.filter.author.head": "Tekijä", // "search.filters.filter.author.placeholder": "Author name", "search.filters.filter.author.placeholder": "Tekijän nimi", + // "search.filters.filter.author.label": "Search author name", + "search.filters.filter.author.label": "Hae tekijän nimellä", + // "search.filters.filter.birthDate.head": "Birth Date", "search.filters.filter.birthDate.head": "Syntymäaika", // "search.filters.filter.birthDate.placeholder": "Birth Date", "search.filters.filter.birthDate.placeholder": "Syntymäaika", + // "search.filters.filter.birthDate.label": "Search birth date", + "search.filters.filter.birthDate.label": "Hae syntymäajalla", + + // "search.filters.filter.collapse": "Collapse filter", + "search.filters.filter.collapse": "Sulje suodatin", + // "search.filters.filter.creativeDatePublished.head": "Date Published", - "search.filters.filter.creativeDatePublished.head": "Julkaisuajankohta", + "search.filters.filter.creativeDatePublished.head": "Julkaisuaika", // "search.filters.filter.creativeDatePublished.placeholder": "Date Published", - "search.filters.filter.creativeDatePublished.placeholder": "Julkaisuajankohta", + "search.filters.filter.creativeDatePublished.placeholder": "Julkaisuaika", + + // "search.filters.filter.creativeDatePublished.label": "Search date published", + "search.filters.filter.creativeDatePublished.label": "Hae julkaisuaikaa", // "search.filters.filter.creativeWorkEditor.head": "Editor", "search.filters.filter.creativeWorkEditor.head": "Toimittaja", @@ -4097,26 +5470,41 @@ // "search.filters.filter.creativeWorkEditor.placeholder": "Editor", "search.filters.filter.creativeWorkEditor.placeholder": "Toimittaja", + // "search.filters.filter.creativeWorkEditor.label": "Search editor", + "search.filters.filter.creativeWorkEditor.label": "Hae toimittajaa", + // "search.filters.filter.creativeWorkKeywords.head": "Subject", "search.filters.filter.creativeWorkKeywords.head": "Asiasana", // "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", "search.filters.filter.creativeWorkKeywords.placeholder": "Asiasana", + // "search.filters.filter.creativeWorkKeywords.label": "Search subject", + "search.filters.filter.creativeWorkKeywords.label": "Hae asiasanaa", + // "search.filters.filter.creativeWorkPublisher.head": "Publisher", "search.filters.filter.creativeWorkPublisher.head": "Julkaisija", // "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", "search.filters.filter.creativeWorkPublisher.placeholder": "Julkaisija", + // "search.filters.filter.creativeWorkPublisher.label": "Search publisher", + "search.filters.filter.creativeWorkPublisher.label": "Hae julkaisijaa", + // "search.filters.filter.dateIssued.head": "Date", "search.filters.filter.dateIssued.head": "Päivämäärä", - // "search.filters.filter.dateIssued.max.placeholder": "Minimum Date", - "search.filters.filter.dateIssued.max.placeholder": "Alkupäivämäärä", + // "search.filters.filter.dateIssued.max.placeholder": "Maximum Date", + "search.filters.filter.dateIssued.max.placeholder": "Suurin päivämäärä", + + // "search.filters.filter.dateIssued.max.label": "End", + "search.filters.filter.dateIssued.max.label": "Loppu", - // "search.filters.filter.dateIssued.min.placeholder": "Maximum Date", - "search.filters.filter.dateIssued.min.placeholder": "Loppupäivämäärä", + // "search.filters.filter.dateIssued.min.placeholder": "Minimum Date", + "search.filters.filter.dateIssued.min.placeholder": "Pienin päivämäärä", + + // "search.filters.filter.dateIssued.min.label": "Start", + "search.filters.filter.dateIssued.min.label": "Alku", // "search.filters.filter.dateSubmitted.head": "Date submitted", "search.filters.filter.dateSubmitted.head": "Tallennusajankohta", @@ -4124,7 +5512,10 @@ // "search.filters.filter.dateSubmitted.placeholder": "Date submitted", "search.filters.filter.dateSubmitted.placeholder": "Tallennnusajankohta", - // "search.filters.filter.discoverable.head": "Private", + // "search.filters.filter.dateSubmitted.label": "Search date submitted", + "search.filters.filter.dateSubmitted.label": "Hakupäivä lähetetty", + + // "search.filters.filter.discoverable.head": "Non-discoverable", "search.filters.filter.discoverable.head": "Yksityinen", // "search.filters.filter.withdrawn.head": "Withdrawn", @@ -4136,6 +5527,12 @@ // "search.filters.filter.entityType.placeholder": "Item Type", "search.filters.filter.entityType.placeholder": "Tietueen tyyppi", + // "search.filters.filter.entityType.label": "Search item type", + "search.filters.filter.entityType.label": "Hae tietueen tyyppiä", + + // "search.filters.filter.expand": "Expand filter", + "search.filters.filter.expand": "Laajenna suodinta", + // "search.filters.filter.has_content_in_original_bundle.head": "Has files", "search.filters.filter.has_content_in_original_bundle.head": "On tiedostoja", @@ -4145,53 +5542,80 @@ // "search.filters.filter.itemtype.placeholder": "Type", "search.filters.filter.itemtype.placeholder": "Tyyppi", + // "search.filters.filter.itemtype.label": "Search type", + "search.filters.filter.itemtype.label": "Hakutyyppi", + // "search.filters.filter.jobTitle.head": "Job Title", "search.filters.filter.jobTitle.head": "Tehtävänimike", // "search.filters.filter.jobTitle.placeholder": "Job Title", "search.filters.filter.jobTitle.placeholder": "Tehtävänimike", + // "search.filters.filter.jobTitle.label": "Search job title", + "search.filters.filter.jobTitle.label": "Hae tehtävänimikettä", + // "search.filters.filter.knowsLanguage.head": "Known language", "search.filters.filter.knowsLanguage.head": "Tunnettu kieli", // "search.filters.filter.knowsLanguage.placeholder": "Known language", "search.filters.filter.knowsLanguage.placeholder": "Tunnettu kieli", + // "search.filters.filter.knowsLanguage.label": "Search known language", + "search.filters.filter.knowsLanguage.label": "Hae tunnettua kieltä", + // "search.filters.filter.namedresourcetype.head": "Status", "search.filters.filter.namedresourcetype.head": "Tila", // "search.filters.filter.namedresourcetype.placeholder": "Status", "search.filters.filter.namedresourcetype.placeholder": "Tila", + // "search.filters.filter.namedresourcetype.label": "Search status", + "search.filters.filter.namedresourcetype.label": "Haun tila", + // "search.filters.filter.objectpeople.head": "People", "search.filters.filter.objectpeople.head": "Käyttäjät", // "search.filters.filter.objectpeople.placeholder": "People", "search.filters.filter.objectpeople.placeholder": "Käyttäjät", + // "search.filters.filter.objectpeople.label": "Search people", + "search.filters.filter.objectpeople.label": "Hae ihmisiä", + // "search.filters.filter.organizationAddressCountry.head": "Country", "search.filters.filter.organizationAddressCountry.head": "Maa", // "search.filters.filter.organizationAddressCountry.placeholder": "Country", "search.filters.filter.organizationAddressCountry.placeholder": "Maa", + // "search.filters.filter.organizationAddressCountry.label": "Search country", + "search.filters.filter.organizationAddressCountry.label": "Hae maata", + // "search.filters.filter.organizationAddressLocality.head": "City", "search.filters.filter.organizationAddressLocality.head": "Kaupunki", // "search.filters.filter.organizationAddressLocality.placeholder": "City", "search.filters.filter.organizationAddressLocality.placeholder": "Kaupunki", + // "search.filters.filter.organizationAddressLocality.label": "Search city", + "search.filters.filter.organizationAddressLocality.label": "Hae kaupunkia", + // "search.filters.filter.organizationFoundingDate.head": "Date Founded", "search.filters.filter.organizationFoundingDate.head": "Perustamispäivämäärä", // "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", "search.filters.filter.organizationFoundingDate.placeholder": "Perustamispäivämäärä", + // "search.filters.filter.organizationFoundingDate.label": "Search date founded", + "search.filters.filter.organizationFoundingDate.label": "Hae perustamispäivämäärää", + // "search.filters.filter.scope.head": "Scope", "search.filters.filter.scope.head": "Rajaus", // "search.filters.filter.scope.placeholder": "Scope filter", - "search.filters.filter.scope.placeholder": "Haun tarkennus", + "search.filters.filter.scope.placeholder": "Hakusuodattimet", + + // "search.filters.filter.scope.label": "Search scope filter", + "search.filters.filter.scope.label": "Hae hakusuodatinta", // "search.filters.filter.show-less": "Collapse", "search.filters.filter.show-less": "Sulje", @@ -4205,13 +5629,29 @@ // "search.filters.filter.subject.placeholder": "Subject", "search.filters.filter.subject.placeholder": "Asiasana", + // "search.filters.filter.subject.label": "Search subject", + "search.filters.filter.subject.label": "Hae asiasanaa", + // "search.filters.filter.submitter.head": "Submitter", "search.filters.filter.submitter.head": "Tallentaja", // "search.filters.filter.submitter.placeholder": "Submitter", "search.filters.filter.submitter.placeholder": "Tallentaja", + // "search.filters.filter.submitter.label": "Search submitter", + "search.filters.filter.submitter.label": "Hae tallentajaa", + + // "search.filters.filter.show-tree": "Browse {{ name }} tree", + "search.filters.filter.show-tree": "Selaa {{ name }}-puuta", + + // "search.filters.filter.supervisedBy.head": "Supervised By", + "search.filters.filter.supervisedBy.head": "Ohjaajana:", + // "search.filters.filter.supervisedBy.placeholder": "Supervised By", + "search.filters.filter.supervisedBy.placeholder": "Ohjaajana:", + + // "search.filters.filter.supervisedBy.label": "Search Supervised By", + "search.filters.filter.supervisedBy.label": "Hae ohjaajan mukaan", // "search.filters.entityType.JournalIssue": "Journal Issue", "search.filters.entityType.JournalIssue": "Kausijulkaisun numero", @@ -4240,25 +5680,23 @@ // "search.filters.withdrawn.false": "No", "search.filters.withdrawn.false": "Ei", - // "search.filters.head": "Filters", "search.filters.head": "Suodattimet", // "search.filters.reset": "Reset filters", "search.filters.reset": "Tyhjennä suodattimet", - + // "search.filters.search.submit": "Submit", + "search.filters.search.submit": "Lähetä", // "search.form.search": "Search", "search.form.search": "Hae", - // "search.form.search_dspace": "Search DSpace", - "search.form.search_dspace": "Hae arkistosta", - - // "search.form.search_mydspace": "Search MyDSpace", - "search.form.search_mydspace": "Hae omista tiedoista", - + // "search.form.search_dspace": "All repository", + "search.form.search_dspace": "Koko julkaisuarkisto", + // "search.form.scope.all": "All of DSpace", + "search.form.scope.all": "Koko julkaisuarkisto", // "search.results.head": "Search Results", "search.results.head": "Hakutulokset", @@ -4272,7 +5710,17 @@ // "search.results.empty": "Your search returned no results.", "search.results.empty": "Ei hakutuloksia.", + // "search.results.view-result": "View", + "search.results.view-result": "Näytä", + + // "search.results.response.500": "An error occurred during query execution, please try again later", + "search.results.response.500": "Virhe hakua suoritettaessa, yritä myöhemmin uudelleen", + // "default.search.results.head": "Search Results", + "default.search.results.head": "Hakutulokset", + + // "default-relationships.search.results.head": "Search Results", + "default-relationships.search.results.head": "Hakutulokset", // "search.sidebar.close": "Back to results", "search.sidebar.close": "Paluu tuloksiin", @@ -4295,8 +5743,6 @@ // "search.sidebar.settings.title": "Settings", "search.sidebar.settings.title": "Asetukset", - - // "search.view-switch.show-detail": "Show detail", "search.view-switch.show-detail": "Näytä lisätiedot", @@ -4306,8 +5752,6 @@ // "search.view-switch.show-list": "Show as list", "search.view-switch.show-list": "Näytä luettelona", - - // "sorting.ASC": "Ascending", "sorting.ASC": "Laskeva", @@ -4320,10 +5764,29 @@ // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Nimeke (Ö-A)", - // "sorting.score.DESC": "Relevance", - "sorting.score.DESC": "Relevanssi", + // "sorting.score.ASC": "Least Relevant", + "sorting.score.ASC": "Vähiten relevantti", + // "sorting.score.DESC": "Most Relevant", + "sorting.score.DESC": "Relevantein", + // "sorting.dc.date.issued.ASC": "Date Issued Ascending", + "sorting.dc.date.issued.ASC": "Julkaisuaika nouseva", + + // "sorting.dc.date.issued.DESC": "Date Issued Descending", + "sorting.dc.date.issued.DESC": "Julkaisuaika laskeva", + + // "sorting.dc.date.accessioned.ASC": "Accessioned Date Ascending", + "sorting.dc.date.accessioned.ASC": "Hyväksymispäivä nouseva", + + // "sorting.dc.date.accessioned.DESC": "Accessioned Date Descending", + "sorting.dc.date.accessioned.DESC": "Hyväksymispäivä laskeva", + + // "sorting.lastModified.ASC": "Last modified Ascending", + "sorting.lastModified.ASC": "Viimeksi muokattu nouseva", + + // "sorting.lastModified.DESC": "Last modified Descending", + "sorting.lastModified.DESC": "Viimeksi muokattu laskeva", // "statistics.title": "Statistics", "statistics.title": "Tilastot", @@ -4358,12 +5821,19 @@ // "statistics.table.header.views": "Views", "statistics.table.header.views": "Katseluita", + // "statistics.table.no-name": "(object name could not be loaded)", + "statistics.table.no-name": "(kohteen nimeä ei voitu ladata)", + // "submission.edit.breadcrumbs": "Edit Submission", + "submission.edit.breadcrumbs": "Muokkaa tallennusta", // "submission.edit.title": "Edit Submission", "submission.edit.title": "Muokkaa tallennusta", - // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + // "submission.general.cancel": "Cancel", + "submission.general.cancel": "Peruuta", + + // "submission.general.cannot_submit": "You don't have permission to make a new submission.", "submission.general.cannot_submit": "Sinulla ei ole oikeuksia aineiston tallentamiseen.", // "submission.general.deposit": "Deposit", @@ -4384,21 +5854,50 @@ // "submission.general.discard.submit": "Discard", "submission.general.discard.submit": "Hylkää", + // "submission.general.info.saved": "Saved", + "submission.general.info.saved": "Tallennettu", + + // "submission.general.info.pending-changes": "Unsaved changes", + "submission.general.info.pending-changes": "Tallentamattomat muutokset", + // "submission.general.save": "Save", "submission.general.save": "Tallenna", // "submission.general.save-later": "Save for later", "submission.general.save-later": "Tallenna myöhemmäksi", - // "submission.import-external.page.title": "Import metadata from an external source", "submission.import-external.page.title": "Importoi metadata ulkoisesta lähteestä", // "submission.import-external.title": "Import metadata from an external source", "submission.import-external.title": "Importoi metadata ulkoisesta lähteestä", + // "submission.import-external.title.Journal": "Import a journal from an external source", + "submission.import-external.title.Journal": "Importoi Muokkaa kausijulkaisu ulkoisesta lähteestä", + + // "submission.import-external.title.JournalIssue": "Import a journal issue from an external source", + "submission.import-external.title.JournalIssue": "Importoi kausijulkaisun numero ulkoisesta lähteestä", + + // "submission.import-external.title.JournalVolume": "Import a journal volume from an external source", + "submission.import-external.title.JournalVolume": "Importoi kausijulkaisun vuosikerta ulkoisesta lähteestä", + + // "submission.import-external.title.OrgUnit": "Import a publisher from an external source", + "submission.import-external.title.OrgUnit": "Importoi julkaisija ulkoisesta lähteestä", + + // "submission.import-external.title.Person": "Import a person from an external source", + "submission.import-external.title.Person": "Importoi käyttäjä ulkoisesta lähteestä", + + // "submission.import-external.title.Project": "Import a project from an external source", + "submission.import-external.title.Project": "Importoi projekti ulkoisesta lähteestä", + + // "submission.import-external.title.Publication": "Import a publication from an external source", + "submission.import-external.title.Publication": "Importoi julkaisu ulkoisesta lähteestä", + + // "submission.import-external.title.none": "Import metadata from an external source", + "submission.import-external.title.none": "Importoi metadata ulkoisesta lähteestä", + // "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", - "submission.import-external.page.hint": "Anna hakulauseke etsiäksesi verkosta arkistoon importoitavia tietueita.", + "submission.import-external.page.hint": "Anna hakulauseke etsiäksesi verkosta julkaisuarkistoon importoitavia tietueita.", // "submission.import-external.back-to-my-dspace": "Back to MyDSpace", "submission.import-external.back-to-my-dspace": "Paluu omiin tietoihin", @@ -4418,27 +5917,84 @@ // "submission.import-external.source.arxiv": "arXiv", "submission.import-external.source.arxiv": "arXiv", + // "submission.import-external.source.ads": "NASA/ADS", + "submission.import-external.source.ads": "NASA/ADS", + + // "submission.import-external.source.cinii": "CiNii", + "submission.import-external.source.cinii": "CiNii", + + // "submission.import-external.source.crossref": "CrossRef", + "submission.import-external.source.crossref": "CrossRef", + + // "submission.import-external.source.datacite": "DataCite", + "submission.import-external.source.datacite": "DataCite", + + // "submission.import-external.source.scielo": "SciELO", + "submission.import-external.source.scielo": "SciELO", + + // "submission.import-external.source.scopus": "Scopus", + "submission.import-external.source.scopus": "Scopus", + + // "submission.import-external.source.vufind": "VuFind", + "submission.import-external.source.vufind": "VuFind", + + // "submission.import-external.source.wos": "Web Of Science", + "submission.import-external.source.wos": "Web Of Science", + + // "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.orcidWorks": "ORCID", + + // "submission.import-external.source.epo": "European Patent Office (EPO)", + "submission.import-external.source.epo": "Euroopan patenttivirasto (EPO)", + // "submission.import-external.source.loading": "Loading ...", "submission.import-external.source.loading": "Ladataan ...", // "submission.import-external.source.sherpaJournal": "SHERPA Journals", "submission.import-external.source.sherpaJournal": "SHERPA-kausijulkaisut", + // "submission.import-external.source.sherpaJournalIssn": "SHERPA Journals by ISSN", + "submission.import-external.source.sherpaJournalIssn": "SHERPA-kausijulkaisut ISSN-tunnuksen mukaan", + // "submission.import-external.source.sherpaPublisher": "SHERPA Publishers", "submission.import-external.source.sherpaPublisher": "SHERPA-kustantajat", + // "submission.import-external.source.openAIREFunding": "Funding OpenAIRE API", + "submission.import-external.source.openAIREFunding": "OpenAIRE API-rahoitus", + // "submission.import-external.source.orcid": "ORCID", "submission.import-external.source.orcid": "ORCID-tunniste", // "submission.import-external.source.pubmed": "Pubmed", "submission.import-external.source.pubmed": "Pubmed", + // "submission.import-external.source.pubmedeu": "Pubmed Europe", + "submission.import-external.source.pubmedeu": "Euroopan Pubmed", + // "submission.import-external.source.lcname": "Library of Congress Names", "submission.import-external.source.lcname": "Library of Congress -nimet", // "submission.import-external.preview.title": "Item Preview", "submission.import-external.preview.title": "Tietueen esikatselu", + // "submission.import-external.preview.title.Publication": "Publication Preview", + "submission.import-external.preview.title.Publication": "Julkaisun esikatselu", + + // "submission.import-external.preview.title.none": "Item Preview", + "submission.import-external.preview.title.none": "Tietueen esikatselu", + + // "submission.import-external.preview.title.Journal": "Journal Preview", + "submission.import-external.preview.title.Journal": "Kausijulkaisun esikatselu", + + // "submission.import-external.preview.title.OrgUnit": "Organizational Unit Preview", + "submission.import-external.preview.title.OrgUnit": "Organisaatioyksikön esikatselu", + + // "submission.import-external.preview.title.Person": "Person Preview", + "submission.import-external.preview.title.Person": "Käyttäjän esikatselu", + + // "submission.import-external.preview.title.Project": "Project Preview", + "submission.import-external.preview.title.Project": "Projektin esikatselu", + // "submission.import-external.preview.subtitle": "The metadata below was imported from an external source. It will be pre-filled when you start the submission.", "submission.import-external.preview.subtitle": "Alla oleva metadata importoitiin ulkoisesta lähteestä. Sillä esitäytetään metadata, kun aloitat tallennuksen.", @@ -4469,6 +6025,48 @@ // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Import remote journal volume", "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importoi kausijulkaisun vuosikerta ulkoisesta lähteestä", + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Project", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekti", + + // "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": "Importoi tietue ulkoisesta lähteestä", + + // "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": "Importoi tapahtuma ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Import remote product", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Importoi tuote ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Import remote equipment", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importoi laite ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Import remote organizational unit", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importoi organisaatioyksikkö ulkoisesta lähteestä", + + // "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": "Importoi rahoitus ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Import remote person", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Importoi käyttäjä ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Import remote patent", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Importoi patentti ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Import remote project", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Importoi projekti ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Import remote publication", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Importoi julkaisu ulkoisesta lähteestä", + + // "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "New Entity Added!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Uusi entiteetti lisätty", + + // "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Project", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekti", + + // "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Funding OpenAIRE API", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Funding OpenAIRE API-rahoitus", + // "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Import Remote Author", "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Importoi tekijä ulkoisesta lähteestä", @@ -4562,6 +6160,9 @@ // "submission.sections.describe.relationship-lookup.search-tab.search": "Go", "submission.sections.describe.relationship-lookup.search-tab.search": "Ok", + // "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Search...", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Haetaan...", + // "submission.sections.describe.relationship-lookup.search-tab.select-all": "Select all", "submission.sections.describe.relationship-lookup.search-tab.select-all": "Valitse kaikki", @@ -4637,13 +6238,39 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Search for Organizational Units", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Hae organisaatioyksiköitä", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Funding OpenAIRE API", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "OpenAIRE API -rahoitus", + + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projects", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projektit", + + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Funder of the Project", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Projektin rahoittaja", + + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Tekijän julkaisu", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Funding OpenAIRE API", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "OpenAIRE API API-rahoitus", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Project", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekti", + + // "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projects", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projektit", + + // "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Funder of the Project", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Projektin rahoittaja", + + // "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Search...", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Haetaan...", + // "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Current Selection ({{ count }})", "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Nykyinen valinta ({{ count }})", // "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Journal Issues", "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Kausijulkaisun numerot", - // "submission.sections.describe.relationship-lookup.title.JournalIssue": "Journal Issues", "submission.sections.describe.relationship-lookup.title.JournalIssue": "Kausijulkaisun numerot", @@ -4689,8 +6316,11 @@ // "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Parent Organizational Unit", "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Ylempi organisaatioyksikkö", + // "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Julkaisu", + // "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown", - "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Vaihda valikon tilaa", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Näytä/piilota pudotusvalikko", // "submission.sections.describe.relationship-lookup.selection-tab.settings": "Settings", "submission.sections.describe.relationship-lookup.selection-tab.settings": "Asetukset", @@ -4767,6 +6397,24 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Search Results", "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Hakutulokset", + // "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Hakutulokset", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Hakutulokset", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Hakutulokset", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Hakutulokset", + + // "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Hakutulokset", + + // "submission.sections.describe.relationship-lookup.selection-tab.title": "Search Results", + "submission.sections.describe.relationship-lookup.selection-tab.title": "Hakutulokset", + // "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": "Haluatko tallentaa nimen \"{{ value }}\" käyttäjän vaihtoehtoiseksi nimeksi, jota muutkin voivat käyttää uudelleen myös tulevissa tallennuksissa? Ellet tallenna nimeä, voit silti käyttää sitä tässä tallennuksessa.", @@ -4792,14 +6440,17 @@ "submission.sections.ccLicense.option.select": "Valitse vaihtoehto…", // "submission.sections.ccLicense.link": "You’ve selected the following license:", - "submission.sections.ccLicense.link": "Olet valinunt seuraavan lisenssin:", + "submission.sections.ccLicense.link": "Olet valinnut seuraavan lisenssin:", // "submission.sections.ccLicense.confirmation": "I grant the license above", - "submission.sections.ccLicense.confirmation": "Myönnän yllä olevan lisenssin", + "submission.sections.ccLicense.confirmation": "Hyväksyn yllä olevan lisenssin", // "submission.sections.general.add-more": "Add more", "submission.sections.general.add-more": "Lisää enemmän", + // "submission.sections.general.cannot_deposit": "Deposit cannot be completed due to errors in the form.<br>Please fill out all required fields to complete the deposit.", + "submission.sections.general.cannot_deposit": "Tallennus ei onnistu, koska lomakkeella on virheitä.<br>Täytä kaikki pakolliset kentät viimeistelläksesi tallennuksen.", + // "submission.sections.general.collection": "Collection", "submission.sections.general.collection": "Kokoelma", @@ -4839,7 +6490,26 @@ // "submission.sections.general.sections_not_valid": "There are incomplete sections.", "submission.sections.general.sections_not_valid": "Tallennuksessa keskeneräisiä osioita.", + // "submission.sections.identifiers.info": "The following identifiers will be created for your item:", + "submission.sections.identifiers.info": "Tietueellesi luodaan seuraavat tunnisteet:", + + // "submission.sections.identifiers.no_handle": "No handles have been minted for this item.", + "submission.sections.identifiers.no_handle": "Tietueelle ei ole luotu handleja.", + // "submission.sections.identifiers.no_doi": "No DOIs have been minted for this item.", + "submission.sections.identifiers.no_doi": "Tietueelle ei ole luotu DOI-tunnuksia.", + + // "submission.sections.identifiers.handle_label": "Handle: ", + "submission.sections.identifiers.handle_label": "Handle: ", + + // "submission.sections.identifiers.doi_label": "DOI: ", + "submission.sections.identifiers.doi_label": "DOI: ", + + // "submission.sections.identifiers.otherIdentifiers_label": "Other identifiers: ", + "submission.sections.identifiers.otherIdentifiers_label": "Muut tunnisteet: ", + + // "submission.sections.submit.progressbar.accessCondition": "Item access conditions", + "submission.sections.submit.progressbar.accessCondition": "Tietueen pääsyoikeudet", // "submission.sections.submit.progressbar.CClicense": "Creative commons license", "submission.sections.submit.progressbar.CClicense": "Creative commons -lisenssi", @@ -4859,19 +6529,65 @@ // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", "submission.sections.submit.progressbar.detect-duplicate": "Mahdollisia kaksoiskappaleita", + // "submission.sections.submit.progressbar.identifiers": "Identifiers", + "submission.sections.submit.progressbar.identifiers": "Tunnisteet", + // "submission.sections.submit.progressbar.license": "Deposit license", "submission.sections.submit.progressbar.license": "Tallennuslisenssi", + // "submission.sections.submit.progressbar.sherpapolicy": "Sherpa policies", + "submission.sections.submit.progressbar.sherpapolicy": "Sherpa-käytännöt", + // "submission.sections.submit.progressbar.upload": "Upload files", "submission.sections.submit.progressbar.upload": "Lataa tiedostoja", + // "submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information", + "submission.sections.submit.progressbar.sherpaPolicies": "Tietoa julkaisijan open access -käytännöistä", + + // "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": "Ei tietoa julkausijan käytännöistä. Jos työlläsi on ISSN-tunnus, syötä se alapuolella olevan kenttään nähdäksesi siihen liittyvät julkaisijan open access -käytännöt.", + + // "submission.sections.status.errors.title": "Errors", + "submission.sections.status.errors.title": "Virheet", + // "submission.sections.status.valid.title": "Valid", + "submission.sections.status.valid.title": "Hyväksytty", + + // "submission.sections.status.warnings.title": "Warnings", + "submission.sections.status.warnings.title": "Varoitukset", + + // "submission.sections.status.errors.aria": "has errors", + "submission.sections.status.errors.aria": "sisältää virheitä", + + // "submission.sections.status.valid.aria": "is valid", + "submission.sections.status.valid.aria": "on validi", + + // "submission.sections.status.warnings.aria": "has warnings", + "submission.sections.status.warnings.aria": "sisältää varoituksia", + + // "submission.sections.status.info.title": "Additional Information", + "submission.sections.status.info.title": "Lisätiedot", + + // "submission.sections.status.info.aria": "Additional Information", + "submission.sections.status.info.aria": "Lisätiedot", + + // "submission.sections.toggle.open": "Open section", + "submission.sections.toggle.open": "Avaa osio", + + // "submission.sections.toggle.close": "Close section", + "submission.sections.toggle.close": "Sulje osio", + + // "submission.sections.toggle.aria.open": "Expand {{sectionHeader}} section", + "submission.sections.toggle.aria.open": "Laajenna {{sectionHeader}}-osio", + + // "submission.sections.toggle.aria.close": "Collapse {{sectionHeader}} section", + "submission.sections.toggle.aria.close": "Sulje {{sectionHeader}}-osio", // "submission.sections.upload.delete.confirm.cancel": "Cancel", "submission.sections.upload.delete.confirm.cancel": "Peruuta", // "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", - "submission.sections.upload.delete.confirm.info": "Tätä toimintoa ei voi peruuttaa. Oletko varma?", + "submission.sections.upload.delete.confirm.info": "Tätä toimintoa ei voi perua. Oletko varma?", // "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", "submission.sections.upload.delete.confirm.submit": "Kyllä, olen varma", @@ -4882,18 +6598,36 @@ // "submission.sections.upload.delete.submit": "Delete", "submission.sections.upload.delete.submit": "Poista", + // "submission.sections.upload.download.title": "Download bitstream", + "submission.sections.upload.download.title": "Lataa tiedosto", + // "submission.sections.upload.drop-message": "Drop files to attach them to the item", "submission.sections.upload.drop-message": "Pudota tiedostot liittääksesi ne tietueeseen", + // "submission.sections.upload.edit.title": "Edit bitstream", + "submission.sections.upload.edit.title": "Muokkaa tiedostoa", + // "submission.sections.upload.form.access-condition-label": "Access condition type", "submission.sections.upload.form.access-condition-label": "Pääsyoikeustyyppi", + // "submission.sections.upload.form.access-condition-hint": "Select an access condition to apply on the bitstream once the item is deposited", + "submission.sections.upload.form.access-condition-hint": "Valitse pääsyoikeus, jota sovelletaan tiedostoon tietueen tallentamisen jälkeen", + // "submission.sections.upload.form.date-required": "Date is required.", "submission.sections.upload.form.date-required": "Päivämäärä on pakollinen tieto.", + // "submission.sections.upload.form.date-required-from": "Grant access from date is required.", + "submission.sections.upload.form.date-required-from": "Pääsyoikeuden alkupäivä on pakollinen tieto.", + + // "submission.sections.upload.form.date-required-until": "Grant access until date is required.", + "submission.sections.upload.form.date-required-until": "Pääsyoikeuden loppupäivä on pakollinen tieto.", + // "submission.sections.upload.form.from-label": "Grant access from", "submission.sections.upload.form.from-label": "Pääsyoikeus alkaa", + // "submission.sections.upload.form.from-hint": "Select the date from which the related access condition is applied", + "submission.sections.upload.form.from-hint": "Valitse päivämäärä josta lukien pääsyoikeutta sovelletaan", + // "submission.sections.upload.form.from-placeholder": "From", "submission.sections.upload.form.from-placeholder": "Alkaen", @@ -4906,6 +6640,9 @@ // "submission.sections.upload.form.until-label": "Grant access until", "submission.sections.upload.form.until-label": "Pääsyoikeus päättyy", + // "submission.sections.upload.form.until-hint": "Select the date until which the related access condition is applied", + "submission.sections.upload.form.until-hint": "Valitse päivämäärä, johon asti pääsyoikeus on voimassa", + // "submission.sections.upload.form.until-placeholder": "Until", "submission.sections.upload.form.until-placeholder": "Asti", @@ -4915,7 +6652,7 @@ // "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": "Yksittäisten tiedostojen pääsyrajoitusten lisäksi {{collectionName}}-kokoelmaan ladatut tiedostot ovat seuraavien ryhmien saatavilla:", - // "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 <strong>upload additional files just dragging & dropping them everywhere in the page</strong>", + // "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 <strong>upload additional files by dragging & dropping them anywhere on the page.</strong>", "submission.sections.upload.info": "Tietueen kaikki tiedostot on lueteltu tässä. Voit päivittää tiedoston metadataa ja pääsyehtoja tai <strong>ladata lisää tiedostoja raahaamalla ne mihin hyvänsä sivun kohtaan.</strong>", // "submission.sections.upload.no-entry": "No", @@ -4936,18 +6673,149 @@ // "submission.sections.upload.upload-successful": "Upload successful", "submission.sections.upload.upload-successful": "Lataus valmis", + // "submission.sections.accesses.form.discoverable-description": "When checked, this item will be discoverable in search/browse. When unchecked, the item will only be available via a direct link and will never appear in search/browse.", + "submission.sections.accesses.form.discoverable-description": "Kun tämä on valittu, tietue on löydettävissä haussa ja selailtaessa. Kun tätä ei ole valittu, tietue on saatavilla vain suoran linkin kautta, eikä se näy haussa tai selailtaessa.", + + // "submission.sections.accesses.form.discoverable-label": "Discoverable", + "submission.sections.accesses.form.discoverable-label": "Löydettävissä", + + // "submission.sections.accesses.form.access-condition-label": "Access condition type", + "submission.sections.accesses.form.access-condition-label": "Pääsyoikeustyyppi", + + // "submission.sections.accesses.form.access-condition-hint": "Select an access condition to apply on the item once it is deposited", + "submission.sections.accesses.form.access-condition-hint": "Valitse pääsyoikeus, jota sovelletaan tietueeseen tallentamisen jälkeen", + + // "submission.sections.accesses.form.date-required": "Date is required.", + "submission.sections.accesses.form.date-required": "Päivämäärä on pakollinen tieto.", + + // "submission.sections.accesses.form.date-required-from": "Grant access from date is required.", + "submission.sections.accesses.form.date-required-from": "Pääsyoikeuden alkupäivä on pakollinen tieto.", + + // "submission.sections.accesses.form.date-required-until": "Grant access until date is required.", + "submission.sections.accesses.form.date-required-until": "Pääsyoikeuden loppupäivä on pakollinen tieto.", + + // "submission.sections.accesses.form.from-label": "Grant access from", + "submission.sections.accesses.form.from-label": "Pääsyoikeus alkaa", + + // "submission.sections.accesses.form.from-hint": "Select the date from which the related access condition is applied", + "submission.sections.accesses.form.from-hint": "Valitse päivämäärä, josta alkaen pääsyoikeutta sovelletaan", + + // "submission.sections.accesses.form.from-placeholder": "From", + "submission.sections.accesses.form.from-placeholder": "Alkaen", + + // "submission.sections.accesses.form.group-label": "Group", + "submission.sections.accesses.form.group-label": "Ryhmä", + + // "submission.sections.accesses.form.group-required": "Group is required.", + "submission.sections.accesses.form.group-required": "Ryhmä on pakollinen tieto.", + + // "submission.sections.accesses.form.until-label": "Grant access until", + "submission.sections.accesses.form.until-label": "Pääsyoikeus päättyy", + + // "submission.sections.accesses.form.until-hint": "Select the date until which the related access condition is applied", + "submission.sections.accesses.form.until-hint": "Valitse päivämäärä, johon asti pääsyoikeutta sovelletaan", + + // "submission.sections.accesses.form.until-placeholder": "Until", + "submission.sections.accesses.form.until-placeholder": "Asti", + + // "submission.sections.license.granted-label": "I confirm the license above", + "submission.sections.license.granted-label": "Vahvistan edellä olevan lisenssin", + + // "submission.sections.license.required": "You must accept the license", + "submission.sections.license.required": "Sinun on hyväksyttävä lisenssi", + + // "submission.sections.license.notgranted": "You must accept the license", + "submission.sections.license.notgranted": "Sinun on hyväksyttävä lisenssi", + + // "submission.sections.sherpa.publication.information": "Publication information", + "submission.sections.sherpa.publication.information": "Julkaisun tiedot", + + // "submission.sections.sherpa.publication.information.title": "Title", + "submission.sections.sherpa.publication.information.title": "Nimeke", + + // "submission.sections.sherpa.publication.information.issns": "ISSNs", + "submission.sections.sherpa.publication.information.issns": "ISSN-tunnukset", + + // "submission.sections.sherpa.publication.information.url": "URL", + "submission.sections.sherpa.publication.information.url": "URL", + + // "submission.sections.sherpa.publication.information.publishers": "Publisher", + "submission.sections.sherpa.publication.information.publishers": "Julkaisija", + + // "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", + "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", + + // "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", + "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", + + // "submission.sections.sherpa.publisher.policy": "Publisher Policy", + "submission.sections.sherpa.publisher.policy": "Julkaisukäytännöt", + + // "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": "Alla olevat tiedot on noudettu Sherpa Romeosta. Julkaisijan käytännöt määrittävät, vaaditaanko embargoa ja mitkä tiedostoista ovat ladattavissa. Jos sinulla on kysyttävää, ota yhteyttä ylläpitäjään.", + + // "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": "Tämän kausijulkaisun käytäntöjen sallimat Open Access -reitit on lueteltu alla artikkeliversioittain. Napsauttamalla polkua saat yksityiskohtaisempia tietoja", + + // "submission.sections.sherpa.publisher.policy.more.information": "For more information, please see the following links:", + "submission.sections.sherpa.publisher.policy.more.information": "Lisätietoa saat seuraavista linkeistä:", + + // "submission.sections.sherpa.publisher.policy.version": "Version", + "submission.sections.sherpa.publisher.policy.version": "Versio", + // "submission.sections.sherpa.publisher.policy.embargo": "Embargo", + "submission.sections.sherpa.publisher.policy.embargo": "Embargo", - // "submission.submit.title": "Tallennus", - "submission.submit.title": "Julkaisu", + // "submission.sections.sherpa.publisher.policy.noembargo": "No Embargo", + "submission.sections.sherpa.publisher.policy.noembargo": "Ei embargoa", + // "submission.sections.sherpa.publisher.policy.nolocation": "None", + "submission.sections.sherpa.publisher.policy.nolocation": "Ei mitään", + // "submission.sections.sherpa.publisher.policy.license": "License", + "submission.sections.sherpa.publisher.policy.license": "Lisenssi", + + // "submission.sections.sherpa.publisher.policy.prerequisites": "Prerequisites", + "submission.sections.sherpa.publisher.policy.prerequisites": "Vaatimukset", + + // "submission.sections.sherpa.publisher.policy.location": "Location", + "submission.sections.sherpa.publisher.policy.location": "Sijainti", + + // "submission.sections.sherpa.publisher.policy.conditions": "Conditions", + "submission.sections.sherpa.publisher.policy.conditions": "Ehdot", + + // "submission.sections.sherpa.publisher.policy.refresh": "Refresh", + "submission.sections.sherpa.publisher.policy.refresh": "Päivitä", + + // "submission.sections.sherpa.record.information": "Record Information", + "submission.sections.sherpa.record.information": "Tietueen tiedot", + + // "submission.sections.sherpa.record.information.id": "ID", + "submission.sections.sherpa.record.information.id": "ID", + + // "submission.sections.sherpa.record.information.date.created": "Date Created", + "submission.sections.sherpa.record.information.date.created": "Luontipäivä", + + // "submission.sections.sherpa.record.information.date.modified": "Last Modified", + "submission.sections.sherpa.record.information.date.modified": "Viimeksi muokattu", + + // "submission.sections.sherpa.record.information.uri": "URI", + "submission.sections.sherpa.record.information.uri": "URI", + + // "submission.sections.sherpa.error.message": "There was an error retrieving sherpa informations", + "submission.sections.sherpa.error.message": "Virhe haettaessa Sherpa-tietoja", + + // "submission.submit.breadcrumbs": "New submission", + "submission.submit.breadcrumbs": "Uusi tallennus", + + // "submission.submit.title": "New submission", + "submission.submit.title": "Uusi tallennus", // "submission.workflow.generic.delete": "Delete", "submission.workflow.generic.delete": "Poista", - // "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": "Valitse \"Poista\" hylätäksesi tietueen. Poisto pyydetään vielä vahvistamaan.", + // "submission.workflow.generic.delete-help": "Select this option to discard this item. You will then be asked to confirm it.", + "submission.workflow.generic.delete-help": "Valitse hylätäksesi tietueen. Poisto pyydetään vielä vahvistamaan.", // "submission.workflow.generic.edit": "Edit", "submission.workflow.generic.edit": "Muokkaa", @@ -4961,7 +6829,17 @@ // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", "submission.workflow.generic.view-help": "Valitse tämä katsoaksesi tietueen metadataa.", + // "submission.workflow.generic.submit_select_reviewer": "Select Reviewer", + "submission.workflow.generic.submit_select_reviewer": "Valitse tarkastaja", + // "submission.workflow.generic.submit_select_reviewer-help": "", + "submission.workflow.generic.submit_select_reviewer-help": "", + + // "submission.workflow.generic.submit_score": "Rate", + "submission.workflow.generic.submit_score": "Arvioi", + + // "submission.workflow.generic.submit_score-help": "", + "submission.workflow.generic.submit_score-help": "", // "submission.workflow.tasks.claimed.approve": "Approve", "submission.workflow.tasks.claimed.approve": "Hyväksy", @@ -4975,6 +6853,12 @@ // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", "submission.workflow.tasks.claimed.edit_help": "Valitse tämä muuttaaksesi tietueen metadataa.", + // "submission.workflow.tasks.claimed.decline": "Decline", + "submission.workflow.tasks.claimed.decline": "Hylkää", + + // "submission.workflow.tasks.claimed.decline_help": "", + "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.", "submission.workflow.tasks.claimed.reject.reason.info": "Syötä kenttään syy tallennuksen hylkäämiselle. Kerro myös, voiko tallentaja korjata ongelman ja lähettää aineiston uudelleen.", @@ -4999,8 +6883,6 @@ // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", "submission.workflow.tasks.claimed.return_help": "Palauta tehtävä tehtäväjonoon, jotta toinen käyttäjä voi suorittaa tehtävän.", - - // "submission.workflow.tasks.generic.error": "Error occurred during operation...", "submission.workflow.tasks.generic.error": "Virhe toimintoa suoritettaessa...", @@ -5013,8 +6895,6 @@ // "submission.workflow.tasks.generic.success": "Operation successful", "submission.workflow.tasks.generic.success": "Toiminto onnistui", - - // "submission.workflow.tasks.pool.claim": "Claim", "submission.workflow.tasks.pool.claim": "Ota itsellesi", @@ -5027,12 +6907,146 @@ // "submission.workflow.tasks.pool.show-detail": "Show detail", "submission.workflow.tasks.pool.show-detail": "Näytä lisätiedot", + // "submission.workspace.generic.view": "View", + "submission.workspace.generic.view": "Näytå", + // "submission.workspace.generic.view-help": "Select this option to view the item's metadata.", + "submission.workspace.generic.view-help": "Valitse tarkastellaksesi tietueen metadataa.", - // "title": "DSpace", - "title": "Julkaisuarkisto", + // "submitter.empty": "N/A", + "submitter.empty": "Ei saatavilla", + + // "subscriptions.title": "Subscriptions", + "subscriptions.title": "Tilaukset", + + // "subscriptions.item": "Subscriptions for items", + "subscriptions.item": "Tietueiden tilaukset", + + // "subscriptions.collection": "Subscriptions for collections", + "subscriptions.collection": "Kokoelmien tilaukset", + + // "subscriptions.community": "Subscriptions for communities", + "subscriptions.community": "Yhteisöjen tilaukset", + + // "subscriptions.subscription_type": "Subscription type", + "subscriptions.subscription_type": "Tilaustyyppi", + + // "subscriptions.frequency": "Subscription frequency", + "subscriptions.frequency": "Tilaustiheys", + + // "subscriptions.frequency.D": "Daily", + "subscriptions.frequency.D": "Päivittäin", + + // "subscriptions.frequency.M": "Monthly", + "subscriptions.frequency.M": "Kuukausittain", + + // "subscriptions.frequency.W": "Weekly", + "subscriptions.frequency.W": "Viikoittain", + + // "subscriptions.tooltip": "Subscribe", + "subscriptions.tooltip": "Tilaa", + + // "subscriptions.modal.title": "Subscriptions", + "subscriptions.modal.title": "Tilaukset", + + // "subscriptions.modal.type-frequency": "Type and frequency", + "subscriptions.modal.type-frequency": "Tyyppi ja tiheys", + + // "subscriptions.modal.close": "Close", + "subscriptions.modal.close": "Sulje", + + // "subscriptions.modal.delete-info": "To remove this subscription, please visit the \"Subscriptions\" page under your user profile", + "subscriptions.modal.delete-info": "Voit poistaa tilauksen käyttäjäprofiilisi \"Tilaukset\"-sivulla ", + + // "subscriptions.modal.new-subscription-form.type.content": "Content", + "subscriptions.modal.new-subscription-form.type.content": "Sisältö", + + // "subscriptions.modal.new-subscription-form.frequency.D": "Daily", + "subscriptions.modal.new-subscription-form.frequency.D": "Päivittäin", + + // "subscriptions.modal.new-subscription-form.frequency.W": "Weekly", + "subscriptions.modal.new-subscription-form.frequency.W": "Viikottain", + + // "subscriptions.modal.new-subscription-form.frequency.M": "Monthly", + "subscriptions.modal.new-subscription-form.frequency.M": "Kuukausittain", + + // "subscriptions.modal.new-subscription-form.submit": "Submit", + "subscriptions.modal.new-subscription-form.submit": "Lähetä", + + // "subscriptions.modal.new-subscription-form.processing": "Processing...", + "subscriptions.modal.new-subscription-form.processing": "Käsitellään...", + + // "subscriptions.modal.create.success": "Subscribed to {{ type }} successfully.", + "subscriptions.modal.create.success": "Tilaus {{ type }} onnistui.", + + // "subscriptions.modal.delete.success": "Subscription deleted successfully", + "subscriptions.modal.delete.success": "Tilaus poistettu", + + // "subscriptions.modal.update.success": "Subscription to {{ type }} updated successfully", + "subscriptions.modal.update.success": "Tilaus {{ type }} päivitetty", + + // "subscriptions.modal.create.error": "An error occurs during the subscription creation", + "subscriptions.modal.create.error": "Virhe tilausta luotaessa", + + // "subscriptions.modal.delete.error": "An error occurs during the subscription delete", + "subscriptions.modal.delete.error": "Virhe tilausta poistettaessa", + + // "subscriptions.modal.update.error": "An error occurs during the subscription update", + "subscriptions.modal.update.error": "Virhe tilausta päivitettäessä", + + // "subscriptions.table.dso": "Subject", + "subscriptions.table.dso": "Asiasana", + + // "subscriptions.table.subscription_type": "Subscription Type", + "subscriptions.table.subscription_type": "Tilaustyyppi", + + // "subscriptions.table.subscription_frequency": "Subscription Frequency", + "subscriptions.table.subscription_frequency": "Tilaustiheys", + + // "subscriptions.table.action": "Action", + "subscriptions.table.action": "Toiminto", + + // "subscriptions.table.edit": "Edit", + "subscriptions.table.edit": "Muokkaa", + + // "subscriptions.table.delete": "Delete", + "subscriptions.table.delete": "Poista", + + // "subscriptions.table.not-available": "Not available", + "subscriptions.table.not-available": "Ei saatavilla", + + // "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": "Tilattu tietue on poistettu, tai sinulla ei ole oikeuksia nähdä sitä", + + // "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.", + "subscriptions.table.empty.message": "Sinulla ei tällä hetkellä ole tilauksia. Voit tilata yhteisön tai kokoelman sähköposti-ilmoitukset kohteen sivulla olevalla tilauspainikkeella.", + + // "thumbnail.default.alt": "Thumbnail Image", + "thumbnail.default.alt": "Pienoiskuva", + + // "thumbnail.default.placeholder": "No Thumbnail Available", + "thumbnail.default.placeholder": "Ei pienoiskuvaa saatavilla", + + // "thumbnail.project.alt": "Project Logo", + "thumbnail.project.alt": "Projektin logo", + + // "thumbnail.project.placeholder": "Project Placeholder Image", + "thumbnail.project.placeholder": "Projektin paikkamerkin kuva", + + // "thumbnail.orgunit.alt": "OrgUnit Logo", + "thumbnail.orgunit.alt": "Organisaatioykiskön logo", + + // "thumbnail.orgunit.placeholder": "OrgUnit Placeholder Image", + "thumbnail.orgunit.placeholder": "Organisaatioyksikön paikkamerkin kuva", + // "thumbnail.person.alt": "Profile Picture", + "thumbnail.person.alt": "Profiilikuva", + // "thumbnail.person.placeholder": "No Profile Picture Available", + "thumbnail.person.placeholder": "Ei profiilikuva saatavilla", + + // "title": "DSpace", + "title": "Julkaisuarkisto", // "vocabulary-treeview.header": "Hierarchical tree view", "vocabulary-treeview.header": "Hierarkkinen puunäkymä", @@ -5055,7 +7069,8 @@ // "vocabulary-treeview.tree.description.srsc": "Research Subject Categories", "vocabulary-treeview.tree.description.srsc": "Tutkimusaiheiden kategoriat", - + // "vocabulary-treeview.info": "Select a subject to add as search filter", + "vocabulary-treeview.info": "Valitse asiasana hakusuodattimeksi", // "uploader.browse": "browse", "uploader.browse": "selaa", @@ -5063,6 +7078,9 @@ // "uploader.drag-message": "Drag & Drop your files here", "uploader.drag-message": "Raahaa tiedostot tähän", + // "uploader.delete.btn-title": "Delete", + "uploader.delete.btn-title": "Poista", + // "uploader.or": ", or ", "uploader.or": " tai", @@ -5081,30 +7099,44 @@ // "virtual-metadata.delete-relationship.modal-head": "Select the items for which you want to save the virtual metadata as real metadata", "virtual-metadata.delete-relationship.modal-head": "Valitse tietueet, joiden virtuaalisen metadatan haluat tallentaa varsinaiseksi metadataksi", + // "supervisedWorkspace.search.results.head": "Supervised Items", + "supervisedWorkspace.search.results.head": "Valvotut tietueet", + // "workspace.search.results.head": "Your submissions", + "workspace.search.results.head": "Tallennuksesi", // "workflowAdmin.search.results.head": "Administer Workflow", "workflowAdmin.search.results.head": "Hallinnoi työnkulkua", + // "workflow.search.results.head": "Workflow tasks", + "workflow.search.results.head": "Työnkulun tehtävät", + + // "supervision.search.results.head": "Workflow and Workspace tasks", + "supervision.search.results.head": "Työnkulun ja työtilan tehtävät", + // "workflow-item.edit.breadcrumbs": "Edit workflowitem", + "workflow-item.edit.breadcrumbs": "Muokkaa työnkulun tietuetta", + + // "workflow-item.edit.title": "Edit workflowitem", + "workflow-item.edit.title": "Muokkaa työnkulun tietuetta", // "workflow-item.delete.notification.success.title": "Deleted", "workflow-item.delete.notification.success.title": "Poistettu", // "workflow-item.delete.notification.success.content": "This workflow item was successfully deleted", - "workflow-item.delete.notification.success.content": "Tarkastamaton tietue poistettu", + "workflow-item.delete.notification.success.content": "Työnkulun tietue poistettu", // "workflow-item.delete.notification.error.title": "Something went wrong", "workflow-item.delete.notification.error.title": "Tapahtui virhe", // "workflow-item.delete.notification.error.content": "The workflow item could not be deleted", - "workflow-item.delete.notification.error.content": "Tarkastamatonta tietuetta ei voitu poistaa", + "workflow-item.delete.notification.error.content": "Työnkulun tietuetta ei voitu poistaa", // "workflow-item.delete.title": "Delete workflow item", - "workflow-item.delete.title": "Poista tarkastamaton tietue", + "workflow-item.delete.title": "Poista työnkulkuun tietue", // "workflow-item.delete.header": "Delete workflow item", - "workflow-item.delete.header": "Poista tarkastamaton tietue", + "workflow-item.delete.header": "Poista työnkulkuun tietue", // "workflow-item.delete.button.cancel": "Cancel", "workflow-item.delete.button.cancel": "Peruuta", @@ -5112,30 +7144,566 @@ // "workflow-item.delete.button.confirm": "Delete", "workflow-item.delete.button.confirm": "Poista", - // "workflow-item.send-back.notification.success.title": "Sent back to submitter", "workflow-item.send-back.notification.success.title": "Lähetetty takaisin tallentajalle", // "workflow-item.send-back.notification.success.content": "This workflow item was successfully sent back to the submitter", - "workflow-item.send-back.notification.success.content": "Tarkastamaton tietue lähetetty takaisin tallentajalle", + "workflow-item.send-back.notification.success.content": "Työnkulun tietue lähetetty takaisin tallentajalle", // "workflow-item.send-back.notification.error.title": "Something went wrong", "workflow-item.send-back.notification.error.title": "Tapahtui virhe", // "workflow-item.send-back.notification.error.content": "The workflow item could not be sent back to the submitter", - "workflow-item.send-back.notification.error.content": "Tarkastamatonta tietuetta ei voitu lähettää takaisin tallentajalle", + "workflow-item.send-back.notification.error.content": "Työnkulun tietuetta ei voitu lähettää takaisin tallentajalle", // "workflow-item.send-back.title": "Send workflow item back to submitter", - "workflow-item.send-back.title": "Lähetä tarkastamaton tietue takaisin tallentajalle", + "workflow-item.send-back.title": "Lähetä työnkulkuun tietue takaisin tallentajalle", // "workflow-item.send-back.header": "Send workflow item back to submitter", - "workflow-item.send-back.header": "Lähetä tarkastamaton tietue takaisin tallentajalle", + "workflow-item.send-back.header": "Lähetä työnkulun tietue takaisin tallentajalle", // "workflow-item.send-back.button.cancel": "Cancel", "workflow-item.send-back.button.cancel": "Peruuta", - // "workflow-item.send-back.button.confirm": "Send back" + // "workflow-item.send-back.button.confirm": "Send back", "workflow-item.send-back.button.confirm": "Lähetä takaisin", + // "workflow-item.view.breadcrumbs": "Workflow View", + "workflow-item.view.breadcrumbs": "Työnkulkunäkymä", + + // "workspace-item.view.breadcrumbs": "Workspace View", + "workspace-item.view.breadcrumbs": "Työnkulkunäkymä", + + // "workspace-item.view.title": "Workspace View", + "workspace-item.view.title": "Työnkulkunäkymä", + + // "workspace-item.delete.breadcrumbs": "Workspace Delete", + "workspace-item.delete.breadcrumbs": "Työnkulku - poisto", + + // "workspace-item.delete.header": "Delete workspace item", + "workspace-item.delete.header": "Poista työnkulun tietue", + + // "workspace-item.delete.button.confirm": "Delete", + "workspace-item.delete.button.confirm": "Poista", + + // "workspace-item.delete.button.cancel": "Cancel", + "workspace-item.delete.button.cancel": "Peruuta", + + // "workspace-item.delete.notification.success.title": "Deleted", + "workspace-item.delete.notification.success.title": "Poistettu", + + // "workspace-item.delete.title": "This workspace item was successfully deleted", + "workspace-item.delete.title": "Työnkulun tietue poistettu", + + // "workspace-item.delete.notification.error.title": "Something went wrong", + "workspace-item.delete.notification.error.title": "Tapahtui virhe", + + // "workspace-item.delete.notification.error.content": "The workspace item could not be deleted", + "workspace-item.delete.notification.error.content": "Työnkulun tietuetta ei voitu poistaa", + + // "workflow-item.advanced.title": "Advanced workflow", + "workflow-item.advanced.title": "Laajennettu työnkulku", + + // "workflow-item.selectrevieweraction.notification.success.title": "Selected reviewer", + "workflow-item.selectrevieweraction.notification.success.title": "Valittu tarkastaja", + + // "workflow-item.selectrevieweraction.notification.success.content": "The reviewer for this workflow item has been successfully selected", + "workflow-item.selectrevieweraction.notification.success.content": "Työnkulun tarkastaja on valittu", + + // "workflow-item.selectrevieweraction.notification.error.title": "Something went wrong", + "workflow-item.selectrevieweraction.notification.error.title": "Tapahtui virhe", + + // "workflow-item.selectrevieweraction.notification.error.content": "Couldn't select the reviewer for this workflow item", + "workflow-item.selectrevieweraction.notification.error.content": "Työnkulun tietueelle ei voitu valita tarkastajaa", + + // "workflow-item.selectrevieweraction.title": "Select Reviewer", + "workflow-item.selectrevieweraction.title": "Valitse tarkastaja", + + // "workflow-item.selectrevieweraction.header": "Select Reviewer", + "workflow-item.selectrevieweraction.header": "Valitse tarkastaja", + + // "workflow-item.selectrevieweraction.button.cancel": "Cancel", + "workflow-item.selectrevieweraction.button.cancel": "Peruuta", + + // "workflow-item.selectrevieweraction.button.confirm": "Confirm", + "workflow-item.selectrevieweraction.button.confirm": "Vahvista", + + // "workflow-item.scorereviewaction.notification.success.title": "Rating review", + "workflow-item.scorereviewaction.notification.success.title": "Arviointikatselmus", + + // "workflow-item.scorereviewaction.notification.success.content": "The rating for this item workflow item has been successfully submitted", + "workflow-item.scorereviewaction.notification.success.content": "Tietueen arviointi on lähetetty", + + // "workflow-item.scorereviewaction.notification.error.title": "Something went wrong", + "workflow-item.scorereviewaction.notification.error.title": "Tapahtui virhe", + + // "workflow-item.scorereviewaction.notification.error.content": "Couldn't rate this item", + "workflow-item.scorereviewaction.notification.error.content": "Tietueen arviointi epäonnistui", + + // "workflow-item.scorereviewaction.title": "Rate this item", + "workflow-item.scorereviewaction.title": "Arvioi tietue", + + // "workflow-item.scorereviewaction.header": "Rate this item", + "workflow-item.scorereviewaction.header": "Arvioi tietue", + + // "workflow-item.scorereviewaction.button.cancel": "Cancel", + "workflow-item.scorereviewaction.button.cancel": "Peruuta", + + // "workflow-item.scorereviewaction.button.confirm": "Confirm", + "workflow-item.scorereviewaction.button.confirm": "Vahvista", + + // "idle-modal.header": "Session will expire soon", + "idle-modal.header": "Istunto vanhenee pian", + + // "idle-modal.info": "For security reasons, user sessions expire after {{ timeToExpire }} minutes of inactivity. Your session will expire soon. Would you like to extend it or log out?", + "idle-modal.info": "Turvallisuussyistä käyttäjän istunto vanhenee, kun käyttäjä on ollut epäaktiivinen {{ timeToExpire }} minuuttia. Istuntosi vanhenee pian. Haluatko pidentää istuntoasi vai kirjautua ulos?", + + // "idle-modal.log-out": "Log out", + "idle-modal.log-out": "Kirjaudu ulos", + + // "idle-modal.extend-session": "Extend session", + "idle-modal.extend-session": "Pidennä istuntoa", + + // "researcher.profile.action.processing": "Processing...", + "researcher.profile.action.processing": "Käsitellään...", + + // "researcher.profile.associated": "Researcher profile associated", + "researcher.profile.associated": "Tutkijaprofiili liitetty", + + // "researcher.profile.change-visibility.fail": "An unexpected error occurs while changing the profile visibility", + "researcher.profile.change-visibility.fail": "Odottamaton virhe muutettaessa profiilin näkyvyyttä", + + // "researcher.profile.create.new": "Create new", + "researcher.profile.create.new": "Luo uusi", + + // "researcher.profile.create.success": "Researcher profile created successfully", + "researcher.profile.create.success": "Tutkijaprofiili luotu", + + // "researcher.profile.create.fail": "An error occurs during the researcher profile creation", + "researcher.profile.create.fail": "Virhe luotaessa tutkijaprofiilia", + + // "researcher.profile.delete": "Delete", + "researcher.profile.delete": "Poista", + + // "researcher.profile.expose": "Expose", + "researcher.profile.expose": "Paljasta", + + // "researcher.profile.hide": "Hide", + "researcher.profile.hide": "Piilota", + + // "researcher.profile.not.associated": "Researcher profile not yet associated", + "researcher.profile.not.associated": "Tutkijaprofiilia ei ole vielä liitetty", + + // "researcher.profile.view": "View", + "researcher.profile.view": "Näytä", + + // "researcher.profile.private.visibility": "PRIVATE", + "researcher.profile.private.visibility": "YKSITYINEN", + + // "researcher.profile.public.visibility": "PUBLIC", + "researcher.profile.public.visibility": "JULKINEN", + + // "researcher.profile.status": "Status:", + "researcher.profile.status": "Tila :", + + // "researcherprofile.claim.not-authorized": "You are not authorized to claim this item. For more details contact the administrator(s).", + "researcherprofile.claim.not-authorized": "Sinulla ei ole valtuuksia ottaa itsellesi tätä tietuetta. Lisätietoa saat ylläpitäjiltä.", + + // "researcherprofile.error.claim.body": "An error occurred while claiming the profile, please try again later", + "researcherprofile.error.claim.body": "Tapahtui virhe profiilia haettaessa, yritä myöhemmin uudelleen", + + // "researcherprofile.error.claim.title": "Error", + "researcherprofile.error.claim.title": "Virhe", + + // "researcherprofile.success.claim.body": "Profile claimed with success", + "researcherprofile.success.claim.body": "Profiili haettu", + + // "researcherprofile.success.claim.title": "Success", + "researcherprofile.success.claim.title": "Valmis", + + // "person.page.orcid.create": "Create an ORCID ID", + "person.page.orcid.create": "Luo ORCID-tunniste", + + // "person.page.orcid.granted-authorizations": "Granted authorizations", + "person.page.orcid.granted-authorizations": "Myönnetyt valtuudet", + + // "person.page.orcid.grant-authorizations": "Grant authorizations", + "person.page.orcid.grant-authorizations": "Myönnä valtuuksia", + + // "person.page.orcid.link": "Connect to ORCID ID", + "person.page.orcid.link": "Yhdistä ORCID-tunniste", + + // "person.page.orcid.link.processing": "Linking profile to ORCID...", + "person.page.orcid.link.processing": "Liitetään profiilia ORCID-tunnisteeseen...", + + // "person.page.orcid.link.error.message": "Something went wrong while connecting the profile with ORCID. If the problem persists, contact the administrator.", + "person.page.orcid.link.error.message": "Virhe yhdistettäessä profiilia ORCID-tunnisteeseen. Jos virhe jatkuu, ota yhteyttä ylläpitäjään.", + + // "person.page.orcid.orcid-not-linked-message": "The ORCID iD of this profile ({{ orcid }}) has not yet been connected to an account on the ORCID registry or the connection is expired.", + "person.page.orcid.orcid-not-linked-message": "Tämän profiilin ORCID-tunnistetta ({{ orcid }}) ei ole vielä yhdistetty tiliin ORCID-rekisterissä tai yhteys on vanhentunut.", + + // "person.page.orcid.unlink": "Disconnect from ORCID", + "person.page.orcid.unlink": "Katkaise yhteys ORCIDiin", + + // "person.page.orcid.unlink.processing": "Processing...", + "person.page.orcid.unlink.processing": "Käsitellään...", + + // "person.page.orcid.missing-authorizations": "Missing authorizations", + "person.page.orcid.missing-authorizations": "Puuttuvia valtuuksia", + + // "person.page.orcid.missing-authorizations-message": "The following authorizations are missing:", + "person.page.orcid.missing-authorizations-message": "Seuraavat valtuudet puuttuvat:", + + // "person.page.orcid.no-missing-authorizations-message": "Great! This box is empty, so you have granted all access rights to use all functions offers by your institution.", + "person.page.orcid.no-missing-authorizations-message": "Hyvä! Tämä laatikko on tyhjä, joten olet myöntänyt kaikki käyttöoikeudet instituutiosi tarjoamiin toimintoihin.", + + // "person.page.orcid.no-orcid-message": "No ORCID iD associated yet. By clicking on the button below it is possible to link this profile with an ORCID account.", + "person.page.orcid.no-orcid-message": "ORCID-tunnistetta ei ole vielä liitetty. Painamalla alapuolella olevaa painiketta voit yhdistää tämän profiilin ORCID-tiliin.", + + // "person.page.orcid.profile-preferences": "Profile preferences", + "person.page.orcid.profile-preferences": "Profiiliasetukset", + + // "person.page.orcid.funding-preferences": "Funding preferences", + "person.page.orcid.funding-preferences": "Rahoitusasetukset", + + // "person.page.orcid.publications-preferences": "Publication preferences", + "person.page.orcid.publications-preferences": "Julkaisuasetukset", + + // "person.page.orcid.remove-orcid-message": "If you need to remove your ORCID, please contact the repository administrator", + "person.page.orcid.remove-orcid-message": "Jos haluat poistaa ORCID-tunnuksesi, ota yhteyttä julkaisuarkiston ylläpitäjään", + + // "person.page.orcid.save.preference.changes": "Update settings", + "person.page.orcid.save.preference.changes": "Muokkaa asetuksia", + + // "person.page.orcid.sync-profile.affiliation": "Affiliation", + "person.page.orcid.sync-profile.affiliation": "Affiliaatio", + + // "person.page.orcid.sync-profile.biographical": "Biographical data", + "person.page.orcid.sync-profile.biographical": "Elämäkerralliset tiedot", + + // "person.page.orcid.sync-profile.education": "Education", + "person.page.orcid.sync-profile.education": "Koulutus", + + // "person.page.orcid.sync-profile.identifiers": "Identifiers", + "person.page.orcid.sync-profile.identifiers": "Tunnisteet", + + // "person.page.orcid.sync-fundings.all": "All fundings", + "person.page.orcid.sync-fundings.all": "Kaikki rahoitukset", + + // "person.page.orcid.sync-fundings.mine": "My fundings", + "person.page.orcid.sync-fundings.mine": "Omat rahoitukset", + + // "person.page.orcid.sync-fundings.my_selected": "Selected fundings", + "person.page.orcid.sync-fundings.my_selected": "Valitut rahoitukset", + + // "person.page.orcid.sync-fundings.disabled": "Disabled", + "person.page.orcid.sync-fundings.disabled": "Poistettu käytöstä", + + // "person.page.orcid.sync-publications.all": "All publications", + "person.page.orcid.sync-publications.all": "Kaikki julkaisut", + + // "person.page.orcid.sync-publications.mine": "My publications", + "person.page.orcid.sync-publications.mine": "Omat julkaisut", + + // "person.page.orcid.sync-publications.my_selected": "Selected publications", + "person.page.orcid.sync-publications.my_selected": "Valitut julkaisut", + + // "person.page.orcid.sync-publications.disabled": "Disabled", + "person.page.orcid.sync-publications.disabled": "Poistettu käytöstä", + + // "person.page.orcid.sync-queue.discard": "Discard the change and do not synchronize with the ORCID registry", + "person.page.orcid.sync-queue.discard": "Hylkää muutos. Älä synkronoi ORCID-rekisterin kanssa.", + + // "person.page.orcid.sync-queue.discard.error": "The discarding of the ORCID queue record failed", + "person.page.orcid.sync-queue.discard.error": "ORCID-jonotietueen hylkääminen epäonnistui", + + // "person.page.orcid.sync-queue.discard.success": "The ORCID queue record have been discarded successfully", + "person.page.orcid.sync-queue.discard.success": "ORCID-jonotietue hylätty", + + // "person.page.orcid.sync-queue.empty-message": "The ORCID queue registry is empty", + "person.page.orcid.sync-queue.empty-message": "ORCID-jonorekisteri on tyhjä", + + // "person.page.orcid.sync-queue.table.header.type": "Type", + "person.page.orcid.sync-queue.table.header.type": "Tyyppi", + + // "person.page.orcid.sync-queue.table.header.description": "Description", + "person.page.orcid.sync-queue.table.header.description": "Kuvaus", + + // "person.page.orcid.sync-queue.table.header.action": "Action", + "person.page.orcid.sync-queue.table.header.action": "Toiminto", + + // "person.page.orcid.sync-queue.description.affiliation": "Affiliations", + "person.page.orcid.sync-queue.description.affiliation": "Affiliaatiot", + + // "person.page.orcid.sync-queue.description.country": "Country", + "person.page.orcid.sync-queue.description.country": "Maa", + + // "person.page.orcid.sync-queue.description.education": "Educations", + "person.page.orcid.sync-queue.description.education": "Koulutukset", + + // "person.page.orcid.sync-queue.description.external_ids": "External ids", + "person.page.orcid.sync-queue.description.external_ids": "Ulkoiset tunnisteet", + + // "person.page.orcid.sync-queue.description.other_names": "Other names", + "person.page.orcid.sync-queue.description.other_names": "Muut nimet", + + // "person.page.orcid.sync-queue.description.qualification": "Qualifications", + "person.page.orcid.sync-queue.description.qualification": "Pätevyydet", + + // "person.page.orcid.sync-queue.description.researcher_urls": "Researcher urls", + "person.page.orcid.sync-queue.description.researcher_urls": "Tutkijan URL-osoitteet", + + // "person.page.orcid.sync-queue.description.keywords": "Keywords", + "person.page.orcid.sync-queue.description.keywords": "Avainsanat", + + // "person.page.orcid.sync-queue.tooltip.insert": "Add a new entry in the ORCID registry", + "person.page.orcid.sync-queue.tooltip.insert": "Lisää uusi kohde ORCID-rekisteriin", + + // "person.page.orcid.sync-queue.tooltip.update": "Update this entry on the ORCID registry", + "person.page.orcid.sync-queue.tooltip.update": "Päivitä tämä kohde ORCID-rekisterissä", + + // "person.page.orcid.sync-queue.tooltip.delete": "Remove this entry from the ORCID registry", + "person.page.orcid.sync-queue.tooltip.delete": "Poista tämä kohde ORCID-rekisteristä", + + // "person.page.orcid.sync-queue.tooltip.publication": "Publication", + "person.page.orcid.sync-queue.tooltip.publication": "Julkaisu", + + // "person.page.orcid.sync-queue.tooltip.project": "Project", + "person.page.orcid.sync-queue.tooltip.project": "Projekti", + + // "person.page.orcid.sync-queue.tooltip.affiliation": "Affiliation", + "person.page.orcid.sync-queue.tooltip.affiliation": "Affiliaatio", + + // "person.page.orcid.sync-queue.tooltip.education": "Education", + "person.page.orcid.sync-queue.tooltip.education": "Koulutus", + + // "person.page.orcid.sync-queue.tooltip.qualification": "Qualification", + "person.page.orcid.sync-queue.tooltip.qualification": "Pätevyys", + + // "person.page.orcid.sync-queue.tooltip.other_names": "Other name", + "person.page.orcid.sync-queue.tooltip.other_names": "Toinen nimi", + + // "person.page.orcid.sync-queue.tooltip.country": "Country", + "person.page.orcid.sync-queue.tooltip.country": "Maa", + + // "person.page.orcid.sync-queue.tooltip.keywords": "Keyword", + "person.page.orcid.sync-queue.tooltip.keywords": "Asiasana", + + // "person.page.orcid.sync-queue.tooltip.external_ids": "External identifier", + "person.page.orcid.sync-queue.tooltip.external_ids": "Ulkoinen tunniste", + + // "person.page.orcid.sync-queue.tooltip.researcher_urls": "Researcher url", + "person.page.orcid.sync-queue.tooltip.researcher_urls": "Tutkijan URL-osoite", + + // "person.page.orcid.sync-queue.send": "Synchronize with ORCID registry", + "person.page.orcid.sync-queue.send": "Synkronoi ORCID-rekisterin kanssa", + + // "person.page.orcid.sync-queue.send.unauthorized-error.title": "The submission to ORCID failed for missing authorizations.", + "person.page.orcid.sync-queue.send.unauthorized-error.title": "ORCID-tunnisteen lähettäminen epäonnistui puuttuvien käyttöoikeuksien takia.", + + // "person.page.orcid.sync-queue.send.unauthorized-error.content": "Click <a href='{{orcid}}'>here</a> to grant again the required permissions. If the problem persists, contact the administrator", + "person.page.orcid.sync-queue.send.unauthorized-error.content": "Napsauta <a href='{{orcid}}'>tästä</a> myöntääksesi vaaditut käyttöoikeudet. Jos virhe jatkuu, ota yhteyttä ylläpitäjään.", + + // "person.page.orcid.sync-queue.send.bad-request-error": "The submission to ORCID failed because the resource sent to ORCID registry is not valid", + "person.page.orcid.sync-queue.send.bad-request-error": "ORCID-lähetys epäonnistui, koska ORCID-rekisteriin lähetetty resurssi ei ole kelvollinen", + + // "person.page.orcid.sync-queue.send.error": "The submission to ORCID failed", + "person.page.orcid.sync-queue.send.error": "ORCID-lähetys epäonnistui", + + // "person.page.orcid.sync-queue.send.conflict-error": "The submission to ORCID failed because the resource is already present on the ORCID registry", + "person.page.orcid.sync-queue.send.conflict-error": "ORCID-lähetys epäonnistui, koska lähetetty resurssi on jo ORCID-rekisterissä", + + // "person.page.orcid.sync-queue.send.not-found-warning": "The resource does not exists anymore on the ORCID registry.", + "person.page.orcid.sync-queue.send.not-found-warning": "Resurssia ei enää ole ORCID-rekisterissä..", + + // "person.page.orcid.sync-queue.send.success": "The submission to ORCID was completed successfully", + "person.page.orcid.sync-queue.send.success": "ORCID-lähetys onnistui", + + // "person.page.orcid.sync-queue.send.validation-error": "The data that you want to synchronize with ORCID is not valid", + "person.page.orcid.sync-queue.send.validation-error": "ORCIDin kanssa synkronoitava data ei ole kelvollista", + + // "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "The amount's currency is required", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Valuutta on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.external-id.required": "The resource to be sent requires at least one identifier", + "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Lähetettävällä resurssilla on oltava ainakin yksi tunniste", + + // "person.page.orcid.sync-queue.send.validation-error.title.required": "The title is required", + "person.page.orcid.sync-queue.send.validation-error.title.required": "Nimeke on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.type.required": "The dc.type is required", + "person.page.orcid.sync-queue.send.validation-error.type.required": "dc.type on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.start-date.required": "The start date is required", + "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Alkupäivämäärä on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.funder.required": "The funder is required", + "person.page.orcid.sync-queue.send.validation-error.funder.required": "Rahoittaja on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Invalid 2 digits ISO 3166 country", + "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Virheelliset kaksi merkkiä ISO 3166 -maatunnisteessa", + + // "person.page.orcid.sync-queue.send.validation-error.organization.required": "The organization is required", + "person.page.orcid.sync-queue.send.validation-error.organization.required": "Organisaatio on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "The organization's name is required", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Organisaation nimi on pakollinen tieto", + + // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "The publication date must be one year after 1900", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Julkaisuajan on oltava vuoden 1900 jälkeen", + + // "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "The organization to be sent requires an address", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Organisaatiolla on oltava osoite", + + // "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "The address of the organization to be sent requires a city", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Organisaation osoitteessa on oltava kaupunki", + + // "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", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Organisaation osoitteessa on oltava oikeelliset kaksi ISO 3166 -maatunnisteen merkkiä", + + // "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", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Tunniste vaaditaan organisaatioiden erottelemiseksi. Tuetut tunnisteet ovat GRID, Ringgold, Legal Entity identifier -tunnisteet (LEIt) ja Crossrefin rahoittaharekisterin tunnisteet (FUNDREF)", + + // "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "The organization's identifiers requires a value", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Organisaation tunnisteilla on oltava arvo", + + // "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "The organization's identifiers requires a source", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Organisaation tunnisteilla on oltava lähde", + + // "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "The source of one of the organization identifiers is invalid. Supported sources are RINGGOLD, GRID, LEI and FUNDREF", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Organisaation tunnisteen lähde ei ole validi. Tuetut lähteet ovat RINGGOLD, GRID, LEI ja FUNDREF", + + // "person.page.orcid.synchronization-mode": "Synchronization mode", + "person.page.orcid.synchronization-mode": "Synkronointimoodi", + + // "person.page.orcid.synchronization-mode.batch": "Batch", + "person.page.orcid.synchronization-mode.batch": "Erä", + + // "person.page.orcid.synchronization-mode.label": "Synchronization mode", + "person.page.orcid.synchronization-mode.label": "Synkronointimoodi", + + // "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).", + "person.page.orcid.synchronization-mode-message": "Valitse, miten haluat synkronoinnin ORCIDiin tapahtuvan. Vaihtoehdot ovat \"Manuaalinen\" (sinun on lähetettävä tietosi ORCIDiin manuaalisesti) tai \"Erä\" (järjestelmä lähettää tietosi ORCIDiin ajastetun skriptin avulla).", + + // "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": "Valitse, lähetetäänkö linkitetyt projektisi ORCID-rekisterin rahoitustietoluetteloon.", + + // "person.page.orcid.synchronization-mode-publication-message": "Select whether to send your linked Publication entities to your ORCID record's list of works.", + "person.page.orcid.synchronization-mode-publication-message": "Valitse, lähetetäänkö linkitetyt julkaisusi ORCID-rekisterin luetteloon.", + + // "person.page.orcid.synchronization-mode-profile-message": "Select whether to send your biographical data or personal identifiers to your ORCID record.", + "person.page.orcid.synchronization-mode-profile-message": "Valitse, lähetetäänkö elämäkerralliset tietosi tai henkilökohtaiset tunnisteesi ORCID-rekisteriin.", + + // "person.page.orcid.synchronization-settings-update.success": "The synchronization settings have been updated successfully", + "person.page.orcid.synchronization-settings-update.success": "Synkronisointiasetukset päivitetty", + + // "person.page.orcid.synchronization-settings-update.error": "The update of the synchronization settings failed", + "person.page.orcid.synchronization-settings-update.error": "Synkronisointiasetusten päivittäminen epäonnistui", + + // "person.page.orcid.synchronization-mode.manual": "Manual", + "person.page.orcid.synchronization-mode.manual": "Manuaalinen", + + // "person.page.orcid.scope.authenticate": "Get your ORCID iD", + "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.activities-update": "Add/update your research activities", + "person.page.orcid.scope.activities-update": "Lisää/päivitä tutkimustoimiasi", + + // "person.page.orcid.scope.person-update": "Add/update other information about you", + "person.page.orcid.scope.person-update": "Lisää/päivitä muita tietojasi", + + // "person.page.orcid.unlink.success": "The disconnection between the profile and the ORCID registry was successful", + "person.page.orcid.unlink.success": "Yhteys katkaistu profiilin ja ORCID-rekisterin välillä", + + // "person.page.orcid.unlink.error": "An error occurred while disconnecting between the profile and the ORCID registry. Try again", + "person.page.orcid.unlink.error": "Tapahtui virhe katkaistaessa yhteyttä profiilin ja ORCID-rekisterin välillä. Yritä uudelleen", + + // "person.orcid.sync.setting": "ORCID Synchronization settings", + "person.orcid.sync.setting": "ORCIDin synkronisointiasetukset", + + // "person.orcid.registry.queue": "ORCID Registry Queue", + "person.orcid.registry.queue": "ORCIDin rekisteröintijono", + + // "person.orcid.registry.auth": "ORCID Authorizations", + "person.orcid.registry.auth": "ORCID-käyttöoikeudet", + + // "home.recent-submissions.head": "Recent Submissions", + "home.recent-submissions.head": "Viimeksi tallennetut", + + // "listable-notification-object.default-message": "This object couldn't be retrieved", + "listable-notification-object.default-message": "Kohdetta ei voitu noutaa", + + // "system-wide-alert-banner.retrieval.error": "Something went wrong retrieving the system-wide alert banner", + "system-wide-alert-banner.retrieval.error": "Virhe noudettaessa järjestelmänlaajuista hälytysbanneria", + + // "system-wide-alert-banner.countdown.prefix": "In", + "system-wide-alert-banner.countdown.prefix": "Aikaa", + + // "system-wide-alert-banner.countdown.days": "{{days}} day(s),", + "system-wide-alert-banner.countdown.days": "{{days}} päivää(ä),", + + // "system-wide-alert-banner.countdown.hours": "{{hours}} hour(s) and", + "system-wide-alert-banner.countdown.hours": "{{hours}} tunti(a) and", + + // "system-wide-alert-banner.countdown.minutes": "{{minutes}} minute(s):", + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minuutti(a):", + + // "menu.section.system-wide-alert": "System-wide Alert", + "menu.section.system-wide-alert": "Järjestelmänlaajuinen hälytys", + + // "system-wide-alert.form.header": "System-wide Alert", + "system-wide-alert.form.header": "Järjestelmänlaajuinen hälytys", + + // "system-wide-alert-form.retrieval.error": "Something went wrong retrieving the system-wide alert", + "system-wide-alert-form.retrieval.error": "Virhe noudettaessa järjestelmänlaajuista hälytystä", + + // "system-wide-alert.form.cancel": "Cancel", + "system-wide-alert.form.cancel": "Peruuta", + + // "system-wide-alert.form.save": "Save", + "system-wide-alert.form.save": "Tallenna", + + // "system-wide-alert.form.label.active": "ACTIVE", + "system-wide-alert.form.label.active": "AKTIIVINEN", + + // "system-wide-alert.form.label.inactive": "INACTIVE", + "system-wide-alert.form.label.inactive": "EI-AKTIIVINEN", + + // "system-wide-alert.form.error.message": "The system wide alert must have a message", + "system-wide-alert.form.error.message": "Järjestelmänlaajuisessa hälytyksessä on oltava viesti", + + // "system-wide-alert.form.label.message": "Alert message", + "system-wide-alert.form.label.message": "Hälytysviesti", + + // "system-wide-alert.form.label.countdownTo.enable": "Enable a countdown timer", + "system-wide-alert.form.label.countdownTo.enable": "Ota käyttöön lähtölaskennan ajastin", + + // "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": "Vinkki: Aseta lähtölaskennan ajastin. Kun se on käytössä, voidaan päivämäärä asettaa tulevaisuuteen, jolloin järjestelmänlaajuinen hälytysbanneri suorittaa lähtölaskennan asetettuun päivämäärään. Kun ajastin päättyy, hälytys katoaa. Palvelinta EI pysäytetä automaattisesti.", + + // "system-wide-alert.form.label.preview": "System-wide alert preview", + "system-wide-alert.form.label.preview": "Järjestelmänlaajuisen hälytyksen esikatselu", + + // "system-wide-alert.form.update.success": "The system-wide alert was successfully updated", + "system-wide-alert.form.update.success": "Järjestelmänlaajuinen hälytys päivitetty", + + // "system-wide-alert.form.update.error": "Something went wrong when updating the system-wide alert", + "system-wide-alert.form.update.error": "Virhe päivitettäessä järjestelmänlaajuista hälytystä", + + // "system-wide-alert.form.create.success": "The system-wide alert was successfully created", + "system-wide-alert.form.create.success": "Järjestelmänlaajuinen hälytys luotu", + + // "system-wide-alert.form.create.error": "Something went wrong when creating the system-wide alert", + "system-wide-alert.form.create.error": "Virhe luotaessa järjestelmänlaajuista hälytystä", + + // "admin.system-wide-alert.breadcrumbs": "System-wide Alerts", + "admin.system-wide-alert.breadcrumbs": "Järjestelmänlaajuiset hälytykset", + + // "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 e6546b4499fe87a9308dab7ff2c6767f9f256c67 Mon Sep 17 00:00:00 2001 From: milanmajchrak <milan.majchrak@dataquest.sk> Date: Thu, 20 Jul 2023 12:46:30 +0200 Subject: [PATCH 071/282] Show error message from the error response --- src/app/profile-page/profile-page.component.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/app/profile-page/profile-page.component.ts b/src/app/profile-page/profile-page.component.ts index 343314999ba..d49bdedb838 100644 --- a/src/app/profile-page/profile-page.component.ts +++ b/src/app/profile-page/profile-page.component.ts @@ -161,7 +161,7 @@ export class ProfilePageComponent implements OnInit { } else { this.notificationsService.error( this.translate.instant(this.PASSWORD_NOTIFICATIONS_PREFIX + 'error.title'), - this.translate.instant(this.PASSWORD_NOTIFICATIONS_PREFIX + 'error.change-failed') + this.getPasswordErrorMessage(response) ); } }); @@ -199,4 +199,18 @@ export class ProfilePageComponent implements OnInit { return this.isResearcherProfileEnabled$.asObservable(); } + /** + * Returns an error message from a password validation request with a specific reason or + * a default message without specific reason. + * @param response from the validation password patch request. + */ + getPasswordErrorMessage(response) { + if (response.hasFailed && isNotEmpty(response.errorMessage)) { + // Response has a specific error message. Show this message in the error notification. + return this.translate.instant(response.errorMessage); + } + // Show default error message notification. + return this.translate.instant(this.PASSWORD_NOTIFICATIONS_PREFIX + 'error.change-failed'); + } + } From 4c8ec8a4f22fcc4930b898581de098e317e08b5d Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 4 Aug 2023 12:44:13 -0600 Subject: [PATCH 072/282] =?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 @@ <ng-container *ngIf="fileData"> <div class="row"> - <div class="col-md-2"> - <!--ds-themed-thumbnail [thumbnail]="bitstreamsList[bitstreamKey].url | async"></ds-themed-thumbnail--> - <ds-themed-thumbnail [thumbnail]="fileData?.thumbnail"></ds-themed-thumbnail> - </div> - <div class="col-md-10"> + <div class="col-md-12"> <div class="float-left w-75"> <h3>{{fileName}} <span class="text-muted">({{fileData?.sizeBytes | dsFileSize}})</span></h3> </div> <div class="float-right w-15"> <ng-container> - <ds-themed-file-download-link [cssClasses]="'btn btn-link-focus'" [isBlank]="true" [bitstream]="getBitstream()" [enableRequestACopy]="false"> + <ds-themed-file-download-link [cssClasses]="'btn btn-link-focus'" [isBlank]="true" + [bitstream]="getBitstream()" [enableRequestACopy]="false"> <i class="fa fa-download fa-2x text-normal" aria-hidden="true"></i> </ds-themed-file-download-link> <button class="btn btn-link-focus" @@ -46,7 +43,9 @@ <h4 class="modal-title text-danger">{{ 'submission.sections.upload.delete.confir <p>{{ 'submission.sections.upload.delete.confirm.info' | translate }}</p> </div> <div class="modal-footer"> - <button type="button" class="btn btn-secondary" (click)="c('cancel')">{{ 'submission.sections.upload.delete.confirm.cancel' | translate }}</button> - <button type="button" class="btn btn-danger" (click)="c('ok')">{{ 'submission.sections.upload.delete.confirm.submit' | translate }}</button> + <button type="button" class="btn btn-secondary" + (click)="c('cancel')">{{ 'submission.sections.upload.delete.confirm.cancel' | translate }}</button> + <button type="button" class="btn btn-danger" + (click)="c('ok')">{{ 'submission.sections.upload.delete.confirm.submit' | translate }}</button> </div> </ng-template> 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 @@ <h5 *ngIf="metadata[fileTitleKey].indexOf(entry) === 0"> </ng-container> <ng-container *ngFor="let entry of getAllMetadataValue(fileDescrKey)"> <ng-container *ngIf="entry.value !== ''"> - {{entry.value | dsTruncate:['150']}} + {{entry.value | dsTruncate:['150']}} </ng-container> <ng-container *ngIf="entry.value === ''"> - <span *ngIf="metadata[fileDescrKey].indexOf(entry) === 0" class="text-muted">{{'submission.sections.upload.no-entry' | translate}} {{fileDescrKey}}</span> + <span *ngIf="metadata[fileDescrKey].indexOf(entry) === 0" + class="text-muted">{{'submission.sections.upload.no-entry' | translate}} {{fileDescrKey}}</span> </ng-container> <span class="clearfix"></span> </ng-container> </ng-container> + + <div class="mt-1" *ngIf="fileFormat"> + {{'admin.registries.bitstream-formats.edit.head' | translate:{format: fileFormat} }} + </div> + <div class="mt-1" *ngIf="fileCheckSum"> + Checksum {{fileCheckSum.checkSumAlgorithm}}: {{fileCheckSum.value}} + </div> <span class="clearfix"></span> <ds-submission-section-upload-access-conditions [accessConditions]="fileData.accessConditions"></ds-submission-section-upload-access-conditions> </div> 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 e4b386b8156672b82561cb24e32961498a3e3dce Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 6 Aug 2023 19:57:05 +0200 Subject: [PATCH 073/282] Fix createHeadTags infinite loop when your themes don't override the headTags property --- src/app/app.component.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 669411d9aaf..08e6fc53337 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -316,14 +316,7 @@ export class AppComponent implements OnInit, AfterViewInit { if (hasValue(parentThemeName)) { // inherit the head tags of the parent theme return this.createHeadTags(parentThemeName); - } - const defaultThemeConfig = getDefaultThemeConfig(); - const defaultThemeName = defaultThemeConfig.name; - if ( - hasNoValue(defaultThemeName) || - themeName === defaultThemeName || - themeName === BASE_THEME_NAME - ) { + } else { // last resort, use fallback favicon.ico return [ this.createHeadTag({ @@ -336,9 +329,6 @@ export class AppComponent implements OnInit, AfterViewInit { }) ]; } - - // inherit the head tags of the default theme - return this.createHeadTags(defaultThemeConfig.name); } return headTagConfigs.map(this.createHeadTag.bind(this)); From ec821392565737f768b0cd95917eade7e5ae6589 Mon Sep 17 00:00:00 2001 From: Francesco Bacchelli <francesco.bacchelli@4science.com> Date: Mon, 7 Aug 2023 14:26:42 +0200 Subject: [PATCH 074/282] 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 @@ <h4>{{ (labelPrefix + label + '.select' | translate) }}</h4> [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 <koen.pauwels@atmire.com> Date: Fri, 4 Aug 2023 12:25:20 +0200 Subject: [PATCH 075/282] 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 @@ <h2>{{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle <div class="col-12"> <p> <label for="inheritPoliciesCheckbox"> - <input type="checkbox" name="tc" [(ngModel)]="inheritPolicies" id="inheritPoliciesCheckbox"> + <ng-template #tooltipContent> + The original item read access policy for this item will be replaced by the collection’s one + </ng-template> + <input type="checkbox" name="tc" [(ngModel)]="inheritPolicies" id="inheritPoliciesCheckbox" [ngbTooltip]="tooltipContent" + > {{'item.edit.move.inheritpolicies.checkbox' |translate}} </label> </p> From 6791f6e311ab9ac2900f35c742c09cda9f9cd20e Mon Sep 17 00:00:00 2001 From: Koen Pauwels <koen.pauwels@atmire.com> Date: Fri, 4 Aug 2023 17:10:06 +0200 Subject: [PATCH 076/282] 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 @@ <h2>{{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle <p> <label for="inheritPoliciesCheckbox"> <ng-template #tooltipContent> - The original item read access policy for this item will be replaced by the collection’s one + {{ 'item.edit.move.inheritpolicies.tooltip' | translate }} </ng-template> <input type="checkbox" name="tc" [(ngModel)]="inheritPolicies" id="inheritPoliciesCheckbox" [ngbTooltip]="tooltipContent" > diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..9cf54875931 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2162,6 +2162,8 @@ "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + "item.edit.move.inheritpolicies.tooltip" : "Warning: When enabled, the read access policy for the item and any files associated with the item will be replaced by the default read access policy of the collection. This cannot be undone.", + "item.edit.move.move": "Move", "item.edit.move.processing": "Moving...", From 419868bd8d942ac0a2ba5ce9409023365b2cedf7 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 8 Aug 2023 14:44:01 -0500 Subject: [PATCH 077/282] Enable early release of backport-action to test korthout/backport-action#372 --- .github/workflows/port_merged_pull_request.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml index 50faf3f8867..05dbbf6aa52 100644 --- a/.github/workflows/port_merged_pull_request.yml +++ b/.github/workflows/port_merged_pull_request.yml @@ -27,7 +27,7 @@ jobs: # Port PR to other branch (ONLY if labeled with "port to") # See https://github.com/korthout/backport-action - name: Create backport pull requests - uses: korthout/backport-action@v1 + uses: korthout/backport-action@341-default-mainline with: # Trigger based on a "port to [branch]" label on PR # (This label must specify the branch name to port to) @@ -39,6 +39,9 @@ jobs: # Copy all labels from original PR to (newly created) port PR # NOTE: The labels matching 'label_pattern' are automatically excluded copy_labels_pattern: '.*' + # The --mainline (parent-number) to use when cherry-picking. Value of '1' allows + # merge commits to be cherry picked. See https://git-scm.com/docs/git-cherry-pick + default_mainline: 1 # Use a personal access token (PAT) to create PR as 'dspace-bot' user. # A PAT is required in order for the new PR to trigger its own actions (for CI checks) github_token: ${{ secrets.PR_PORT_TOKEN }} \ No newline at end of file From 765b5c8531d29e8a2a5484d85dd4f09b1c05abe3 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 8 Aug 2023 15:35:17 -0500 Subject: [PATCH 078/282] Revert "Enable early release of backport-action to test korthout/backport-action#372" --- .github/workflows/port_merged_pull_request.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml index 05dbbf6aa52..50faf3f8867 100644 --- a/.github/workflows/port_merged_pull_request.yml +++ b/.github/workflows/port_merged_pull_request.yml @@ -27,7 +27,7 @@ jobs: # Port PR to other branch (ONLY if labeled with "port to") # See https://github.com/korthout/backport-action - name: Create backport pull requests - uses: korthout/backport-action@341-default-mainline + uses: korthout/backport-action@v1 with: # Trigger based on a "port to [branch]" label on PR # (This label must specify the branch name to port to) @@ -39,9 +39,6 @@ jobs: # Copy all labels from original PR to (newly created) port PR # NOTE: The labels matching 'label_pattern' are automatically excluded copy_labels_pattern: '.*' - # The --mainline (parent-number) to use when cherry-picking. Value of '1' allows - # merge commits to be cherry picked. See https://git-scm.com/docs/git-cherry-pick - default_mainline: 1 # Use a personal access token (PAT) to create PR as 'dspace-bot' user. # A PAT is required in order for the new PR to trigger its own actions (for CI checks) github_token: ${{ secrets.PR_PORT_TOKEN }} \ No newline at end of file From 1f68fd63b2f3426ab1360f58cfb653698f979fa1 Mon Sep 17 00:00:00 2001 From: Koen Pauwels <koen.pauwels@atmire.com> Date: Tue, 8 Aug 2023 17:28:05 +0200 Subject: [PATCH 079/282] Fix lint issue. --- src/assets/i18n/en.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 9cf54875931..77584592df3 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2162,7 +2162,7 @@ "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", - "item.edit.move.inheritpolicies.tooltip" : "Warning: When enabled, the read access policy for the item and any files associated with the item will be replaced by the default read access policy of the collection. This cannot be undone.", + "item.edit.move.inheritpolicies.tooltip": "Warning: When enabled, the read access policy for the item and any files associated with the item will be replaced by the default read access policy of the collection. This cannot be undone.", "item.edit.move.move": "Move", From 651305952d706f6c45eb47ff37dfb94f91979760 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Sun, 13 Aug 2023 12:10:25 -0600 Subject: [PATCH 080/282] =?UTF-8?q?=F0=9F=90=9B=20Fix=20Value=20of=20dropd?= =?UTF-8?q?own=20changes=20automatically=20on=20item=20submission=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamic-scrollable-dropdown.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index 6e2d29b7893..1ac38e9943c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -43,7 +43,7 @@ <button class="dropdown-item disabled" *ngIf="optionsList && optionsList.length == 0">{{'form.no-results' | translate}}</button> <button class="dropdown-item collection-item text-truncate" *ngFor="let listEntry of optionsList" - (click)="onSelect(listEntry); sdRef.close()" (mousedown)="onSelect(listEntry); sdRef.close()" + (keydown.enter)="onSelect(listEntry); sdRef.close()" (mousedown)="onSelect(listEntry); sdRef.close()" title="{{ listEntry.display }}" role="option" [attr.id]="listEntry.display == (currentValue|async) ? ('combobox_' + id + '_selected') : null"> {{inputFormatter(listEntry)}} From 25479e17942bbd23e56a5f5a479d2e0dcc798087 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Sun, 13 Aug 2023 12:12:05 -0600 Subject: [PATCH 081/282] =?UTF-8?q?=E2=9C=85change=20test=20event,=20click?= =?UTF-8?q?=20by=20mousedown=20on=20dynamic-scrollable-dropdown.component.?= =?UTF-8?q?spec.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamic-scrollable-dropdown.component.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts index 0fe617e231b..05e46c6e6de 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts @@ -159,14 +159,15 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => { let de: any = scrollableDropdownFixture.debugElement.query(By.css('input.form-control')); let btnEl = de.nativeElement; - btnEl.click(); + const mousedownEvent = new MouseEvent('mousedown'); + + btnEl.dispatchEvent(mousedownEvent); scrollableDropdownFixture.detectChanges(); de = scrollableDropdownFixture.debugElement.queryAll(By.css('button.dropdown-item')); btnEl = de[0].nativeElement; - btnEl.click(); - + btnEl.dispatchEvent(mousedownEvent); scrollableDropdownFixture.detectChanges(); expect((scrollableDropdownComp.model as any).value).toEqual(selectedValue); From 4c419e1eee9aca0287216654da38362bce93044e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 14 Aug 2023 15:54:19 +0200 Subject: [PATCH 082/282] 105265: Made the DsDynamicListComponent's checkbox & radio buttons ids unique for each metadata field to prevent other value-pairs having the same id --- .../ds-dynamic-form-ui/models/list/dynamic-list.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts index bebef5860e1..1fffaeff88b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts @@ -128,7 +128,7 @@ export class DsDynamicListComponent extends DynamicFormControlComponent implemen (v) => v.value === option.value)); const item: ListItem = { - id: value, + id: `${this.model.id}_${value}`, label: option.display, value: checked, index: key From 94c756d52dfedbae470cbb5febab84c69da743cd Mon Sep 17 00:00:00 2001 From: Agustina Martinez <am857@cam.ac.uk> Date: Tue, 15 Aug 2023 16:53:30 +0200 Subject: [PATCH 083/282] Update email-request-copy.component.html Message is optional: remove req in [disabled] --- .../email-request-copy/email-request-copy.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/request-copy/email-request-copy/email-request-copy.component.html b/src/app/request-copy/email-request-copy/email-request-copy.component.html index 70146ab52c6..286e87554b8 100644 --- a/src/app/request-copy/email-request-copy/email-request-copy.component.html +++ b/src/app/request-copy/email-request-copy/email-request-copy.component.html @@ -13,7 +13,7 @@ <ng-content></ng-content> <div class="d-flex flex-row-reverse"> <button (click)="submit()" - [disabled]="!message || message.length === 0 || !subject || subject.length === 0" + [disabled]="!subject || subject.length === 0" class="btn btn-primary" title="{{'grant-deny-request-copy.email.send' | translate }}"> <i class="fas fa-envelope"></i> {{'grant-deny-request-copy.email.send' | translate }} From 0906234a293a3dbe9057ef13cc4c5b690b1cf25b Mon Sep 17 00:00:00 2001 From: Hardy Pottinger <hardy.pottinger@gmail.com> Date: Tue, 15 Aug 2023 10:16:50 -0500 Subject: [PATCH 084/282] 2437 Correct and clarify commented-out code in several custom components - Correct the path in commented-out code in the custom theme's components - Clarify that the workflow-item-sen-back.component.scss file is a stub - It has no corresponding SCSS file in the base theme --- src/themes/custom/app/footer/footer.component.ts | 4 ++-- .../header-nav-wrapper/header-navbar-wrapper.component.ts | 4 ++-- .../app/shared/auth-nav-menu/auth-nav-menu.component.ts | 4 ++-- .../custom/app/shared/object-list/object-list.component.ts | 2 +- .../workflow-item-send-back.component.ts | 5 ++++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/themes/custom/app/footer/footer.component.ts b/src/themes/custom/app/footer/footer.component.ts index de80ceb3112..81286fb6624 100644 --- a/src/themes/custom/app/footer/footer.component.ts +++ b/src/themes/custom/app/footer/footer.component.ts @@ -3,9 +3,9 @@ import { FooterComponent as BaseComponent } from '../../../../app/footer/footer. @Component({ selector: 'ds-footer', - // styleUrls: ['footer.component.scss'], + // styleUrls: ['./footer.component.scss'], styleUrls: ['../../../../app/footer/footer.component.scss'], - // templateUrl: 'footer.component.html' + // templateUrl: './footer.component.html' templateUrl: '../../../../app/footer/footer.component.html' }) export class FooterComponent extends BaseComponent { diff --git a/src/themes/custom/app/header-nav-wrapper/header-navbar-wrapper.component.ts b/src/themes/custom/app/header-nav-wrapper/header-navbar-wrapper.component.ts index 875b5f69b86..e049543630a 100644 --- a/src/themes/custom/app/header-nav-wrapper/header-navbar-wrapper.component.ts +++ b/src/themes/custom/app/header-nav-wrapper/header-navbar-wrapper.component.ts @@ -6,9 +6,9 @@ import { HeaderNavbarWrapperComponent as BaseComponent } from '../../../../app/h */ @Component({ selector: 'ds-header-navbar-wrapper', - // styleUrls: ['header-navbar-wrapper.component.scss'], + // styleUrls: ['./header-navbar-wrapper.component.scss'], styleUrls: ['../../../../app/header-nav-wrapper/header-navbar-wrapper.component.scss'], - // templateUrl: 'header-navbar-wrapper.component.html', + // templateUrl: './header-navbar-wrapper.component.html', templateUrl: '../../../../app/header-nav-wrapper/header-navbar-wrapper.component.html', }) export class HeaderNavbarWrapperComponent extends BaseComponent { diff --git a/src/themes/custom/app/shared/auth-nav-menu/auth-nav-menu.component.ts b/src/themes/custom/app/shared/auth-nav-menu/auth-nav-menu.component.ts index af54aacd444..ff5f09eb76f 100644 --- a/src/themes/custom/app/shared/auth-nav-menu/auth-nav-menu.component.ts +++ b/src/themes/custom/app/shared/auth-nav-menu/auth-nav-menu.component.ts @@ -9,9 +9,9 @@ import { fadeInOut, fadeOut } from '../../../../../app/shared/animations/fade'; */ @Component({ selector: 'ds-auth-nav-menu', - // templateUrl: 'auth-nav-menu.component.html', + // templateUrl: './auth-nav-menu.component.html', templateUrl: '../../../../../app/shared/auth-nav-menu/auth-nav-menu.component.html', - // styleUrls: ['auth-nav-menu.component.scss'], + // styleUrls: ['./auth-nav-menu.component.scss'], styleUrls: ['../../../../../app/shared/auth-nav-menu/auth-nav-menu.component.scss'], animations: [fadeInOut, fadeOut] }) diff --git a/src/themes/custom/app/shared/object-list/object-list.component.ts b/src/themes/custom/app/shared/object-list/object-list.component.ts index 49f464610f5..a3763368702 100644 --- a/src/themes/custom/app/shared/object-list/object-list.component.ts +++ b/src/themes/custom/app/shared/object-list/object-list.component.ts @@ -9,7 +9,7 @@ import { ObjectListComponent as BaseComponent} from '../../../../../app/shared/o selector: 'ds-object-list', // styleUrls: ['./object-list.component.scss'], styleUrls: ['../../../../../app/shared/object-list/object-list.component.scss'], - // templateUrl: 'object-list.component.html' + // templateUrl: './object-list.component.html' templateUrl: '../../../../../app/shared/object-list/object-list.component.html' }) diff --git a/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts b/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts index 49121e64b99..ac8ffc99a99 100644 --- a/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts +++ b/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts @@ -3,7 +3,10 @@ import { WorkflowItemSendBackComponent as BaseComponent } from '../../../../../a @Component({ selector: 'ds-workflow-item-send-back', - // styleUrls: ['workflow-item-send-back.component.scss'], + // NOTE: the SCSS file for workflow-item-action-page does not have a corresponding file in the original + // implementation, so this commented out line below is a stub, here if you + // need it, but you probably don't need it. + // styleUrls: ['./workflow-item-send-back.component.scss'], // templateUrl: './workflow-item-send-back.component.html' templateUrl: '../../../../../app/workflowitems-edit-page/workflow-item-action-page.component.html' }) From 518cc714f2286889d2e66a4f013b954660e7ba5c Mon Sep 17 00:00:00 2001 From: Hardy Pottinger <hardy.pottinger@gmail.com> Date: Tue, 15 Aug 2023 10:26:38 -0500 Subject: [PATCH 085/282] fix lint error in workflow-item-send-back.component.ts --- .../workflow-item-send-back.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts b/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts index ac8ffc99a99..022c46ef22e 100644 --- a/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts +++ b/src/themes/custom/app/workflowitems-edit-page/workflow-item-send-back/workflow-item-send-back.component.ts @@ -6,7 +6,7 @@ import { WorkflowItemSendBackComponent as BaseComponent } from '../../../../../a // NOTE: the SCSS file for workflow-item-action-page does not have a corresponding file in the original // implementation, so this commented out line below is a stub, here if you // need it, but you probably don't need it. - // styleUrls: ['./workflow-item-send-back.component.scss'], + // styleUrls: ['./workflow-item-send-back.component.scss'], // templateUrl: './workflow-item-send-back.component.html' templateUrl: '../../../../../app/workflowitems-edit-page/workflow-item-action-page.component.html' }) From f6649e1c3861012d388ec4d7bf46a54e84fb9962 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 16 Aug 2023 15:15:51 +0200 Subject: [PATCH 086/282] Added support for changing the color of the navbar --- .../expandable-navbar-section.component.scss | 1 + src/app/navbar/navbar.component.scss | 1 + src/styles/_custom_variables.scss | 1 + src/themes/dspace/app/navbar/navbar.component.scss | 4 ++++ 4 files changed, 7 insertions(+) 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 65de77b6007..1bc80d32c57 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,6 +6,7 @@ } .dropdown-menu { + background-color: var(--ds-navbar-bg); overflow: hidden; min-width: 100%; border-top-left-radius: 0; diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss index 441ee82c968..9dc530607cf 100644 --- a/src/app/navbar/navbar.component.scss +++ b/src/app/navbar/navbar.component.scss @@ -1,4 +1,5 @@ nav.navbar { + background-color: var(--ds-navbar-bg); border-bottom: 1px var(--ds-header-navbar-border-bottom-color) solid; align-items: baseline; } diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index ddf490c7a7a..4abe91c368c 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -24,6 +24,7 @@ --ds-header-logo-height-xs: 50px; --ds-header-icon-color: #{$link-color}; --ds-header-icon-color-hover: #{$link-hover-color}; + --ds-navbar-bg: var(--ds-header-bg); --ds-header-navbar-border-top-color: #{$white}; --ds-header-navbar-border-bottom-color: #{$gray-400}; --ds-navbar-link-color: #{$cyan}; diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index d3aea9f0780..06cda777d03 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -4,6 +4,10 @@ nav.navbar { align-items: baseline; } +.navbar-nav { + background-color: var(--ds-navbar-bg); +} + /** Mobile menu styling **/ @media screen and (max-width: map-get($grid-breakpoints, md)-0.02) { .navbar { From 14b1ce5e50f819e1f7b555f205cef8c9b7aee6d8 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 16 Aug 2023 15:16:17 +0200 Subject: [PATCH 087/282] Fixed header bg color not being set in default (no) theme --- src/app/header/header.component.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/header/header.component.scss b/src/app/header/header.component.scss index cca3ed2abb0..fcaedc66e08 100644 --- a/src/app/header/header.component.scss +++ b/src/app/header/header.component.scss @@ -1,3 +1,7 @@ +header { + background-color: var(--ds-header-bg); +} + .navbar-brand img { max-height: var(--ds-header-logo-height); max-width: 100%; From 6c48238fa2d42d3b278741b23e8bd123237e16a1 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Thu, 17 Aug 2023 14:03:28 +0200 Subject: [PATCH 088/282] Fixed breadcrumb padding using incorrect syntax --- src/app/breadcrumbs/breadcrumbs.component.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/breadcrumbs/breadcrumbs.component.scss b/src/app/breadcrumbs/breadcrumbs.component.scss index a4d83b82ea7..52634f2a5b6 100644 --- a/src/app/breadcrumbs/breadcrumbs.component.scss +++ b/src/app/breadcrumbs/breadcrumbs.component.scss @@ -5,8 +5,8 @@ .breadcrumb { border-radius: 0; margin-top: calc(-1 * var(--ds-content-spacing)); - padding-bottom: var(--ds-content-spacing / 3); - padding-top: var(--ds-content-spacing / 3); + padding-bottom: calc(var(--ds-content-spacing) / 3); + padding-top: calc(var(--ds-content-spacing) / 3); background-color: var(--ds-breadcrumb-bg); } From 60706720e47abc19b7528719e63676b9b5fa50be Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 18 Aug 2023 13:20:19 -0600 Subject: [PATCH 089/282] =?UTF-8?q?=F0=9F=90=9B=20fix=20when=20navbar=20ex?= =?UTF-8?q?pands=20on=20firefox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/themes/dspace/app/navbar/navbar.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index d3aea9f0780..2bcd38d5f4d 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -7,7 +7,7 @@ nav.navbar { /** Mobile menu styling **/ @media screen and (max-width: map-get($grid-breakpoints, md)-0.02) { .navbar { - width: 100%; + width: 100vw; background-color: var(--bs-white); position: absolute; overflow: hidden; From 2dc9fd44d7e151f7e96bff16665edf0a09226249 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Sat, 19 Aug 2023 14:40:28 -0600 Subject: [PATCH 090/282] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20chain?= =?UTF-8?q?=20of=20observables=20to=20avoid=20async=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metadata-schema-form.component.ts | 179 ++++++++++-------- 1 file changed, 100 insertions(+), 79 deletions(-) diff --git a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts index 1992289ff77..f5fcdef78de 100644 --- a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts +++ b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts @@ -1,4 +1,10 @@ -import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; +import { + Component, + EventEmitter, + OnDestroy, + OnInit, + Output, +} from '@angular/core'; import { DynamicFormControlModel, DynamicFormGroupModel, @@ -8,20 +14,19 @@ import { import { UntypedFormGroup } from '@angular/forms'; import { RegistryService } from '../../../../core/registry/registry.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; -import { take } from 'rxjs/operators'; +import { switchMap, take } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; -import { combineLatest } from 'rxjs'; +import { Observable, combineLatest } from 'rxjs'; import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model'; @Component({ selector: 'ds-metadata-schema-form', - templateUrl: './metadata-schema-form.component.html' + templateUrl: './metadata-schema-form.component.html', }) /** * A form used for creating and editing metadata schemas */ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { - /** * A unique id used for ds-form */ @@ -53,14 +58,14 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { formLayout: DynamicFormLayout = { name: { grid: { - host: 'col col-sm-6 d-inline-block' - } + host: 'col col-sm-6 d-inline-block', + }, }, namespace: { grid: { - host: 'col col-sm-6 d-inline-block' - } - } + host: 'col col-sm-6 d-inline-block', + }, + }, }; /** @@ -73,63 +78,67 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { */ @Output() submitForm: EventEmitter<any> = new EventEmitter(); - constructor(public registryService: RegistryService, private formBuilderService: FormBuilderService, private translateService: TranslateService) { - } + constructor( + public registryService: RegistryService, + private formBuilderService: FormBuilderService, + private translateService: TranslateService + ) {} ngOnInit() { combineLatest([ this.translateService.get(`${this.messagePrefix}.name`), - this.translateService.get(`${this.messagePrefix}.namespace`) + this.translateService.get(`${this.messagePrefix}.namespace`), ]).subscribe(([name, namespace]) => { this.name = new DynamicInputModel({ - id: 'name', - label: name, - name: 'name', - validators: { - required: null, - pattern: '^[^. ,]*$', - maxLength: 32, - }, - required: true, - errorMessages: { - pattern: 'error.validation.metadata.name.invalid-pattern', - maxLength: 'error.validation.metadata.name.max-length', - }, - }); + id: 'name', + label: name, + name: 'name', + validators: { + required: null, + pattern: '^[^. ,]*$', + maxLength: 32, + }, + required: true, + errorMessages: { + pattern: 'error.validation.metadata.name.invalid-pattern', + maxLength: 'error.validation.metadata.name.max-length', + }, + }); this.namespace = new DynamicInputModel({ - id: 'namespace', - label: namespace, - name: 'namespace', - validators: { - required: null, - maxLength: 256, - }, - required: true, - errorMessages: { - maxLength: 'error.validation.metadata.namespace.max-length', - }, - }); + id: 'namespace', + label: namespace, + name: 'namespace', + validators: { + required: null, + maxLength: 256, + }, + required: true, + errorMessages: { + maxLength: 'error.validation.metadata.namespace.max-length', + }, + }); this.formModel = [ - new DynamicFormGroupModel( - { - id: 'metadatadataschemagroup', - group:[this.namespace, this.name] - }) + new DynamicFormGroupModel({ + id: 'metadatadataschemagroup', + group: [this.namespace, this.name], + }), ]; this.formGroup = this.formBuilderService.createFormGroup(this.formModel); - this.registryService.getActiveMetadataSchema().subscribe((schema: MetadataSchema) => { - if (schema == null) { - this.clearFields(); - } else { - this.formGroup.patchValue({ - metadatadataschemagroup: { - name: schema.prefix, - namespace: schema.namespace, - }, - }); - this.name.disabled = true; - } - }); + this.registryService + .getActiveMetadataSchema() + .subscribe((schema: MetadataSchema) => { + if (schema == null) { + this.clearFields(); + } else { + this.formGroup.patchValue({ + metadatadataschemagroup: { + name: schema.prefix, + namespace: schema.namespace, + }, + }); + this.name.disabled = true; + } + }); }); } @@ -147,30 +156,42 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { * Emit the updated/created schema using the EventEmitter submitForm */ onSubmit(): void { - this.registryService.clearMetadataSchemaRequests().subscribe(); - this.registryService.getActiveMetadataSchema().pipe(take(1)).subscribe( - (schema: MetadataSchema) => { - const values = { - prefix: this.name.value, - namespace: this.namespace.value - }; - if (schema == null) { - this.registryService.createOrUpdateMetadataSchema(Object.assign(new MetadataSchema(), values)).subscribe((newSchema) => { - this.submitForm.emit(newSchema); - }); - } else { - this.registryService.createOrUpdateMetadataSchema(Object.assign(new MetadataSchema(), schema, { - id: schema.id, - prefix: schema.prefix, - namespace: values.namespace, - })).subscribe((updatedSchema: MetadataSchema) => { - this.submitForm.emit(updatedSchema); - }); - } + const clearMetadataSchemaRequests$ = + this.registryService.clearMetadataSchemaRequests(); + + clearMetadataSchemaRequests$ + .pipe( + switchMap(() => + this.registryService.getActiveMetadataSchema().pipe(take(1)) + ), + switchMap((schema: MetadataSchema) => { + const metadataValues = { + prefix: this.name.value, + namespace: this.namespace.value, + }; + + let createOrUpdate$: Observable<MetadataSchema>; + + if (schema == null) { + createOrUpdate$ = this.registryService.createOrUpdateMetadataSchema( + Object.assign(new MetadataSchema(), metadataValues) + ); + } else { + const updatedSchema = Object.assign(new MetadataSchema(), schema, { + namespace: metadataValues.namespace, + }); + createOrUpdate$ = + this.registryService.createOrUpdateMetadataSchema(updatedSchema); + } + + return createOrUpdate$; + }) + ) + .subscribe((updatedOrCreatedSchema: MetadataSchema) => { + this.submitForm.emit(updatedOrCreatedSchema); this.clearFields(); this.registryService.cancelEditMetadataSchema(); - } - ); + }); } /** From 9fb9e5848c70274b7917bead52643e3611308174 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Sat, 19 Aug 2023 15:59:33 -0600 Subject: [PATCH 091/282] =?UTF-8?q?=F0=9F=90=9B=20fix=20bug=20of=20caching?= =?UTF-8?q?=20when=20add=20new=20schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metadata-schema-form.component.ts | 80 ++++++++++--------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts index f5fcdef78de..61766a4a109 100644 --- a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts +++ b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts @@ -14,7 +14,7 @@ import { import { UntypedFormGroup } from '@angular/forms'; import { RegistryService } from '../../../../core/registry/registry.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; -import { switchMap, take } from 'rxjs/operators'; +import { switchMap, take, tap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { Observable, combineLatest } from 'rxjs'; import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model'; @@ -156,42 +156,48 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { * Emit the updated/created schema using the EventEmitter submitForm */ onSubmit(): void { - const clearMetadataSchemaRequests$ = - this.registryService.clearMetadataSchemaRequests(); - - clearMetadataSchemaRequests$ - .pipe( - switchMap(() => - this.registryService.getActiveMetadataSchema().pipe(take(1)) - ), - switchMap((schema: MetadataSchema) => { - const metadataValues = { - prefix: this.name.value, - namespace: this.namespace.value, - }; - - let createOrUpdate$: Observable<MetadataSchema>; - - if (schema == null) { - createOrUpdate$ = this.registryService.createOrUpdateMetadataSchema( - Object.assign(new MetadataSchema(), metadataValues) - ); - } else { - const updatedSchema = Object.assign(new MetadataSchema(), schema, { - namespace: metadataValues.namespace, - }); - createOrUpdate$ = - this.registryService.createOrUpdateMetadataSchema(updatedSchema); - } - - return createOrUpdate$; - }) - ) - .subscribe((updatedOrCreatedSchema: MetadataSchema) => { - this.submitForm.emit(updatedOrCreatedSchema); - this.clearFields(); - this.registryService.cancelEditMetadataSchema(); - }); + this.registryService + .getActiveMetadataSchema() + .pipe( + take(1), + switchMap((schema: MetadataSchema) => { + const metadataValues = { + prefix: this.name.value, + namespace: this.namespace.value, + }; + + let createOrUpdate$: Observable<MetadataSchema>; + + if (schema == null) { + createOrUpdate$ = + this.registryService.createOrUpdateMetadataSchema( + Object.assign(new MetadataSchema(), metadataValues) + ); + } else { + const updatedSchema = Object.assign( + new MetadataSchema(), + schema, + { + namespace: metadataValues.namespace, + } + ); + createOrUpdate$ = + this.registryService.createOrUpdateMetadataSchema( + updatedSchema + ); + } + + return createOrUpdate$; + }), + tap(() => { + this.registryService.clearMetadataSchemaRequests().subscribe(); + }) + ) + .subscribe((updatedOrCreatedSchema: MetadataSchema) => { + this.submitForm.emit(updatedOrCreatedSchema); + this.clearFields(); + this.registryService.cancelEditMetadataSchema(); + }); } /** From 5ef4a827f5a2f4e03fc373eece317fd1e52aaac0 Mon Sep 17 00:00:00 2001 From: Hrafn Malmquist <hrafn.malmquist@gmail.com> Date: Tue, 22 Aug 2023 04:26:53 +0100 Subject: [PATCH 092/282] Replace h5 with a span --- .../community-list/community-list.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index d6fd77e79bb..38c9ed1ad68 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -34,13 +34,13 @@ aria-hidden="true"></span> </button> <div class="d-flex flex-row"> - <h5 class="align-middle pt-2"> + <span class="align-middle pt-2 lead"> <a [routerLink]="node.route" class="lead"> {{ dsoNameService.getName(node.payload) }} </a> <span class="pr-2"> </span> <span *ngIf="node.payload.archivedItemsCount >= 0" class="badge badge-pill badge-secondary align-top archived-items-lead">{{node.payload.archivedItemsCount}}</span> - </h5> + </span> </div> </div> <ds-truncatable [id]="node.id"> From 05c53ad1d49da41af474322364891289494a5f02 Mon Sep 17 00:00:00 2001 From: Hrafn Malmquist <hrafn.malmquist@gmail.com> Date: Tue, 22 Aug 2023 04:27:23 +0100 Subject: [PATCH 093/282] Replace h2 with a h1 --- src/app/community-list-page/community-list-page.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/community-list-page/community-list-page.component.html b/src/app/community-list-page/community-list-page.component.html index 9759f4405da..4392fb87d03 100644 --- a/src/app/community-list-page/community-list-page.component.html +++ b/src/app/community-list-page/community-list-page.component.html @@ -1,4 +1,4 @@ <div class="container"> - <h2>{{ 'communityList.title' | translate }}</h2> + <h1>{{ 'communityList.title' | translate }}</h1> <ds-themed-community-list></ds-themed-community-list> </div> From 5f71de885bc811152729b3fefcb6fefbeda3001e Mon Sep 17 00:00:00 2001 From: Hrafn Malmquist <hrafn.malmquist@gmail.com> Date: Tue, 22 Aug 2023 04:28:28 +0100 Subject: [PATCH 094/282] Add trackby function so cdktree can differentiate between new and old nodes --- .../community-list/community-list.component.html | 2 +- .../community-list/community-list.component.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index 38c9ed1ad68..18e9e84577c 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -1,5 +1,5 @@ <ds-themed-loading *ngIf="(dataSource.loading$ | async) && !loadingNode" class="ds-themed-loading"></ds-themed-loading> -<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl"> +<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl" [trackBy]="trackBy"> <!-- This is the tree node template for show more node --> <cdk-tree-node *cdkTreeNodeDef="let node; when: isShowMore" cdkTreeNodePadding class="example-tree-node show-more-node"> diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index 5b2f9308137..e4ad5d8c29f 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -30,6 +30,7 @@ export class CommunityListComponent implements OnInit, OnDestroy { ); dataSource: CommunityListDatasource; + trackBy = (index, node: FlatNode) => node.id; paginationConfig: FindListOptions; From d9b6e9d81f2fba70f7c13a1377e2f2472c20d592 Mon Sep 17 00:00:00 2001 From: Hrafn Malmquist <hrafn.malmquist@gmail.com> Date: Tue, 22 Aug 2023 04:29:01 +0100 Subject: [PATCH 095/282] Improve documentation --- .../community-list-service.ts | 6 ++--- .../community-list.component.ts | 25 ++++++++++++++----- .../show-more-flat-node.model.ts | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/app/community-list-page/community-list-service.ts b/src/app/community-list-page/community-list-service.ts index 99e9dbeb0de..67715716dad 100644 --- a/src/app/community-list-page/community-list-service.ts +++ b/src/app/community-list-page/community-list-service.ts @@ -25,7 +25,7 @@ import { ShowMoreFlatNode } from './show-more-flat-node.model'; import { FindListOptions } from '../core/data/find-list-options.model'; import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface'; -// Helper method to combine an flatten an array of observables of flatNode arrays +// Helper method to combine and flatten an array of observables of flatNode arrays export const combineAndFlatten = (obsList: Observable<FlatNode[]>[]): Observable<FlatNode[]> => observableCombineLatest([...obsList]).pipe( map((matrix: any[][]) => [].concat(...matrix)), @@ -199,7 +199,7 @@ export class CommunityListService { * Transforms a community in a list of FlatNodes containing firstly a flatnode of the community itself, * followed by flatNodes of its possible subcommunities and collection * It gets called recursively for each subcommunity to add its subcommunities and collections to the list - * Number of subcommunities and collections added, is dependant on the current page the parent is at for respectively subcommunities and collections. + * Number of subcommunities and collections added, is dependent on the current page the parent is at for respectively subcommunities and collections. * @param community Community being transformed * @param level Depth of the community in the list, subcommunities and collections go one level deeper * @param parent Flatnode of the parent community @@ -275,7 +275,7 @@ export class CommunityListService { /** * Checks if a community has subcommunities or collections by querying the respective services with a pageSize = 0 - * Returns an observable that combines the result.payload.totalElements fo the observables that the + * Returns an observable that combines the result.payload.totalElements of the observables that the * respective services return when queried * @param community Community being checked whether it is expandable (if it has subcommunities or collections) */ diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index e4ad5d8c29f..bd1d5ecb78f 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -59,18 +59,28 @@ export class CommunityListComponent implements OnInit, OnDestroy { this.communityListService.saveCommunityListStateToStore(this.expandedNodes, this.loadingNode); } - // whether or not this node has children (subcommunities or collections) + /** + * Whether this node has children (subcommunities or collections) + * @param _ + * @param node + */ hasChild(_: number, node: FlatNode) { return node.isExpandable$; } - // whether or not it is a show more node (contains no data, but is indication that there are more topcoms, subcoms or collections + /** + * Whether this is a show more node that contains no data, but indicates that there is + * one or more community or collection. + * @param _ + * @param node + */ isShowMore(_: number, node: FlatNode) { return node.isShowMoreNode; } /** - * Toggles the expanded variable of a node, adds it to the expanded nodes list and reloads the tree so this node is expanded + * Toggles the expanded variable of a node, adds it to the expanded nodes list and reloads the tree + * so this node is expanded * @param node Node we want to expand */ toggleExpanded(node: FlatNode) { @@ -93,9 +103,12 @@ export class CommunityListComponent implements OnInit, OnDestroy { /** * Makes sure the next page of a node is added to the tree (top community, sub community of collection) - * > Finds its parent (if not top community) and increases its corresponding collection/subcommunity currentPage - * > Reloads tree with new page added to corresponding top community lis, sub community list or collection list - * @param node The show more node indicating whether it's an increase in top communities, sub communities or collections + * > Finds its parent (if not top community) and increases its corresponding collection/subcommunity + * currentPage + * > Reloads tree with new page added to corresponding top community lis, sub community list or + * collection list + * @param node The show more node indicating whether it's an increase in top communities, sub communities + * or collections */ getNextPage(node: FlatNode): void { this.loadingNode = node; diff --git a/src/app/community-list-page/show-more-flat-node.model.ts b/src/app/community-list-page/show-more-flat-node.model.ts index 801c9e7388a..c7b7162d213 100644 --- a/src/app/community-list-page/show-more-flat-node.model.ts +++ b/src/app/community-list-page/show-more-flat-node.model.ts @@ -1,6 +1,6 @@ /** * The show more links in the community tree are also represented by a flatNode so we know where in - * the tree it should be rendered an who its parent is (needed for the action resulting in clicking this link) + * the tree it should be rendered and who its parent is (needed for the action resulting in clicking this link) */ export class ShowMoreFlatNode { } From e59913acab0e782a743a4f18634e2930de9b71e8 Mon Sep 17 00:00:00 2001 From: Hrafn Malmquist <hrafn.malmquist@gmail.com> Date: Tue, 22 Aug 2023 04:59:23 +0100 Subject: [PATCH 096/282] Reorder instance method to come after member declaration --- .../community-list/community-list.component.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index bd1d5ecb78f..90dd6b3c05d 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -28,11 +28,9 @@ export class CommunityListComponent implements OnInit, OnDestroy { treeControl = new FlatTreeControl<FlatNode>( (node: FlatNode) => node.level, (node: FlatNode) => true ); - dataSource: CommunityListDatasource; - trackBy = (index, node: FlatNode) => node.id; - paginationConfig: FindListOptions; + trackBy = (index, node: FlatNode) => node.id; constructor( protected communityListService: CommunityListService, From 4cc4192e93aea3eb7dddc8486fe1fad35b6103bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Fern=C3=A1ndez=20Celorio?= <sfernandez@arvo.es> Date: Tue, 22 Aug 2023 11:59:54 +0200 Subject: [PATCH 097/282] Spanish translation updated to 7.6 --- src/assets/i18n/es.json5 | 766 ++++++++++++++++++++------------------- 1 file changed, 385 insertions(+), 381 deletions(-) diff --git a/src/assets/i18n/es.json5 b/src/assets/i18n/es.json5 index 5a0e40af42b..bd393cda853 100644 --- a/src/assets/i18n/es.json5 +++ b/src/assets/i18n/es.json5 @@ -9,8 +9,6 @@ // "401.unauthorized": "unauthorized", "401.unauthorized": "no autorizado", - - // "403.help": "You don't have permission to access this page. You can use the button below to get back to the home page.", "403.help": "No tiene permisos para acceder a esta página. Puede utilizar el botón de abajo para volver a la página de inicio.", @@ -29,7 +27,6 @@ // "500.link.home-page": "Take me to the home page", "500.link.home-page": "Llévame a la página de inicio", - // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "404.help": "No podemos encontrar la página que busca. La página puede haber sido movida o eliminada. Puede utilizar el botón de abajo para volver a la página de inicio. ", @@ -52,7 +49,7 @@ "error-page.description.404": "página no encontrada", // "error-page.orcid.generic-error": "An error occurred during login via ORCID. Make sure you have shared your ORCID account email address with DSpace. If the error persists, contact the administrator", - "error-page.orcid.generic-error": "Hubo un error en el login via ORCID. Asegúrese que ha compartido el correo electrónico de su cuenta ORCID con Dspace. Si continuase el error, contacte con el administrador", + "error-page.orcid.generic-error": "Hubo un error en el login vía ORCID. Asegúrese que ha compartido el correo electrónico de su cuenta ORCID con Dspace. Si continuase el error, contacte con el administrador", // "access-status.embargo.listelement.badge": "Embargo", "access-status.embargo.listelement.badge": "Embargo", @@ -194,7 +191,8 @@ // "admin.registries.bitstream-formats.table.name": "Name", "admin.registries.bitstream-formats.table.name": "Nombre", - // "admin.registries.bitstream-formats.table.id" : "ID", + + // "admin.registries.bitstream-formats.table.id": "ID", "admin.registries.bitstream-formats.table.id": "ID", // "admin.registries.bitstream-formats.table.return": "Back", @@ -215,8 +213,6 @@ // "admin.registries.bitstream-formats.title": "Bitstream Format Registry", "admin.registries.bitstream-formats.title": "Registro de formato Archivo", - - // "admin.registries.metadata.breadcrumbs": "Metadata registry", "admin.registries.metadata.breadcrumbs": "Registro de metadatos", @@ -256,8 +252,6 @@ // "admin.registries.metadata.title": "Metadata Registry", "admin.registries.metadata.title": "Registro de metadatos", - - // "admin.registries.schema.breadcrumbs": "Metadata schema", "admin.registries.schema.breadcrumbs": "Esquema de metadatos", @@ -275,7 +269,8 @@ // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Campo", - // "admin.registries.schema.fields.table.id" : "ID", + + // "admin.registries.schema.fields.table.id": "ID", "admin.registries.schema.fields.table.id": "ID", // "admin.registries.schema.fields.table.scopenote": "Scope Note", @@ -335,7 +330,29 @@ // "admin.registries.schema.title": "Metadata Schema Registry", "admin.registries.schema.title": "Registro de esquemas de metadatos", + // "admin.access-control.bulk-access.breadcrumbs": "Bulk Access Management", + "admin.access-control.bulk-access.breadcrumbs": "Gestión de Acceso Masivo", + + // "administrativeBulkAccess.search.results.head": "Search Results", + "administrativeBulkAccess.search.results.head": "Resultados de la búsqueda", + + // "admin.access-control.bulk-access": "Bulk Access Management", + "admin.access-control.bulk-access": "Gestión de Acceso Masivo", + + // "admin.access-control.bulk-access.title": "Bulk Access Management", + "admin.access-control.bulk-access.title": "Gestión de Acceso Masivo", + // "admin.access-control.bulk-access-browse.header": "Step 1: Select Objects", + "admin.access-control.bulk-access-browse.header": "Paso 1: Seleccione Objetos", + + // "admin.access-control.bulk-access-browse.search.header": "Search", + "admin.access-control.bulk-access-browse.search.header": "Buscar", + + // "admin.access-control.bulk-access-browse.selected.header": "Current selection({{number}})", + "admin.access-control.bulk-access-browse.selected.header": "Selección actual({{number}})", + + // "admin.access-control.bulk-access-settings.header": "Step 2: Operation to Perform", + "admin.access-control.bulk-access-settings.header": "Paso 2: Operación a realizar", // "admin.access-control.epeople.actions.delete": "Delete EPerson", "admin.access-control.epeople.actions.delete": "Eliminar usuario", @@ -347,7 +364,7 @@ "admin.access-control.epeople.actions.reset": "Restablecer la contraseña", // "admin.access-control.epeople.actions.stop-impersonating": "Stop impersonating EPerson", - "admin.access-control.epeople.actions.stop-impersonating": "Deja de hacerse pasar por usuario", + "admin.access-control.epeople.actions.stop-impersonating": "Dejar de hacerse pasar por usuario", // "admin.access-control.epeople.breadcrumbs": "EPeople", "admin.access-control.epeople.breadcrumbs": "Usuarios", @@ -478,8 +495,6 @@ // "admin.access-control.epeople.notification.deleted.success": "Successfully deleted EPerson: \"{{name}}\"", "admin.access-control.epeople.notification.deleted.success": "Usuario eliminado correctamente: \"{{ name }}\"", - - // "admin.access-control.groups.title": "Groups", "admin.access-control.groups.title": "Grupos", @@ -549,8 +564,6 @@ // "admin.access-control.groups.notification.deleted.failure.content": "Cause: \"{{cause}}\"", "admin.access-control.groups.notification.deleted.failure.content": "Causa: \"{{ cause }}\"", - - // "admin.access-control.groups.form.alert.permanent": "This group is permanent, so it can't be edited or deleted. You can still add and remove group members using this page.", "admin.access-control.groups.form.alert.permanent": "Este grupo es permanente, por lo que no se puede editar ni eliminar. Sin embargo, puedes añadir y eliminar miembros del grupo utilizando esta página.", @@ -791,9 +804,6 @@ // "administrativeView.search.results.head": "Administrative Search", "administrativeView.search.results.head": "Búsqueda administrativa", - - - // "admin.workflow.breadcrumbs": "Administer Workflow", "admin.workflow.breadcrumbs": "Administrar flujo de trabajo", @@ -818,8 +828,6 @@ // "admin.workflow.item.supervision": "Supervision", "admin.workflow.item.supervision": "Supervisión", - - // "admin.metadata-import.breadcrumbs": "Import Metadata", "admin.metadata-import.breadcrumbs": "Importar metadatos", @@ -844,6 +852,9 @@ // "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": "Seleccione la Colección a la que importar. Luego, suelte o busque el archivo zip en formato Simple Archive Format (SAF) que incluye los ítems a importar", + // "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", + "admin.batch-import.page.toggle.help": "Es posible realizar una importación tanto mediante una subida de fichero como a través de una URL. Use el selector de arriba para especificar la fuente de entrada.", + // "admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import", "admin.metadata-import.page.dropMsg": "Suelta un CSV de metadatos para importar", @@ -863,14 +874,26 @@ "admin.metadata-import.page.button.proceed": "Continuar", // "admin.metadata-import.page.button.select-collection": "Select Collection", - "admin.metadata-import.page.button.select-collection": "Selecciona la Colleción", + "admin.metadata-import.page.button.select-collection": "Selecciona la Colección", // "admin.metadata-import.page.error.addFile": "Select file first!", "admin.metadata-import.page.error.addFile": "¡Seleccione el archivo primero!", + // "admin.metadata-import.page.error.addFileUrl": "Insert file url first!", + "admin.metadata-import.page.error.addFileUrl": "¡Seleccione primero la URL del archivo!", + // "admin.batch-import.page.error.addFile": "Select Zip file first!", "admin.batch-import.page.error.addFile": "¡Seleccione el archivo ZIP primero!", + // "admin.metadata-import.page.toggle.upload": "Upload", + "admin.metadata-import.page.toggle.upload": "Subir", + + // "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.toggle.url": "URL", + + // "admin.metadata-import.page.urlMsg": "Insert the batch ZIP url to import", + "admin.metadata-import.page.urlMsg": "¡Seleccione primero la URL del archivo ZIP!", + // "admin.metadata-import.page.validateOnly": "Validate Only", "admin.metadata-import.page.validateOnly": "Solo Validar", @@ -895,14 +918,12 @@ // "advanced-workflow-action.rating.description-requiredDescription": "Please select a rating below and also add a review", "advanced-workflow-action.rating.description-requiredDescription": "Por favor, seleccione una evaluación y también agregue una revisión", - // "advanced-workflow-action.select-reviewer.description-single": "Please select a single reviewer below before submitting", "advanced-workflow-action.select-reviewer.description-single": "Por favor, seleccione un revisor antes de realizar el envío", // "advanced-workflow-action.select-reviewer.description-multiple": "Please select one or more reviewers below before submitting", "advanced-workflow-action.select-reviewer.description-multiple": "Por favor, seleccione uno o mas revisores antes de realizar el envío", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "Usuario", @@ -987,15 +1008,12 @@ // "auth.messages.token-refresh-failed": "Refreshing your session token failed. Please log in again.", "auth.messages.token-refresh-failed": "No se pudo actualizar el token de la sesión. Inicie sesión de nuevo.", - - - // "bitstream.download.page": "Now downloading {{bitstream}}..." , + // "bitstream.download.page": "Now downloading {{bitstream}}...", "bitstream.download.page": "Descargando {{ bitstream }}...", - // "bitstream.download.page.back": "Back" , + // "bitstream.download.page.back": "Back", "bitstream.download.page.back": "Atrás" , - // "bitstream.edit.authorizations.link": "Edit bitstream's Policies", "bitstream.edit.authorizations.link": "Editar las políticas del archivo", @@ -1047,6 +1065,9 @@ // "bitstream.edit.notifications.error.format.title": "An error occurred saving the bitstream's format", "bitstream.edit.notifications.error.format.title": "Se produjo un error al guardar el formato del archivo.", + // "bitstream.edit.notifications.error.primaryBitstream.title": "An error occurred saving the primary bitstream", + "bitstream.edit.notifications.error.primaryBitstream.title": "Se produjo un error al guardar el archivo primario", + // "bitstream.edit.form.iiifLabel.label": "IIIF Label", "bitstream.edit.form.iiifLabel.label": "Etiqueta IIIF", @@ -1071,7 +1092,6 @@ // "bitstream.edit.form.iiifHeight.hint": "The canvas height should usually match the image height.", "bitstream.edit.form.iiifHeight.hint": "La altura del marco normalmente debería coincidir con la altura de la imagen", - // "bitstream.edit.notifications.saved.content": "Your changes to this bitstream were saved.", "bitstream.edit.notifications.saved.content": "Se guardaron sus cambios en este archivo.", @@ -1095,6 +1115,7 @@ // "bitstream-request-a-copy.intro.bitstream.one": "Requesting the following file: ", "bitstream-request-a-copy.intro.bitstream.one": "Solicitando el siguiente fichero: ", + // "bitstream-request-a-copy.intro.bitstream.all": "Requesting all files. ", "bitstream-request-a-copy.intro.bitstream.all": "Solicitando todos los ficheros. ", @@ -1137,8 +1158,6 @@ // "bitstream-request-a-copy.submit.error": "Something went wrong with submitting the item request.", "bitstream-request-a-copy.submit.error": "Hubo un fallo en el envío de la solicitud de ítem.", - - // "browse.back.all-results": "All browse results", "browse.back.all-results": "Todos los resultados de la búsqueda", @@ -1151,8 +1170,11 @@ // "browse.comcol.by.subject": "By Subject", "browse.comcol.by.subject": "Por materia", + // "browse.comcol.by.srsc": "By Subject Category", + "browse.comcol.by.srsc": "Por categoría", + // "browse.comcol.by.title": "By Title", - "browse.comcol.by.title": "Por titulo", + "browse.comcol.by.title": "Por título", // "browse.comcol.head": "Browse", "browse.comcol.head": "Examinar", @@ -1181,6 +1203,9 @@ // "browse.metadata.subject.breadcrumbs": "Browse by Subject", "browse.metadata.subject.breadcrumbs": "Examinar por materia", + // "browse.metadata.srsc.breadcrumbs": "Browse by Subject Category", + "browse.metadata.srsc.breadcrumbs": "Examinar por categoría", + // "browse.metadata.title.breadcrumbs": "Browse by Title", "browse.metadata.title.breadcrumbs": "Examinar por título", @@ -1262,21 +1287,24 @@ // "browse.startsWith.type_text": "Filter results by typing the first few letters", "browse.startsWith.type_text": "Seleccione resultados tecleando las primeras letras", + // "browse.startsWith.input": "Filter", + "browse.startsWith.input": "Filtrar", + + // "browse.taxonomy.button": "Browse", + "browse.taxonomy.button": "Examinar", + // "browse.title": "Browsing {{ collection }} by {{ field }}{{ startsWith }} {{ value }}", "browse.title": "Examinando {{ collection }} por {{ field }} {{ value }}", // "browse.title.page": "Browsing {{ collection }} by {{ field }} {{ value }}", "browse.title.page": "Examinando {{ collection }} por {{ field }} {{ value }}", - // "search.browse.item-back": "Back to Results", "search.browse.item-back": "Volver a los resultados", - // "chips.remove": "Remove chip", "chips.remove": "Quitar chip", - // "claimed-approved-search-result-list-element.title": "Approved", "claimed-approved-search-result-list-element.title": "Aprobado", @@ -1286,7 +1314,6 @@ // "claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow", "claimed-declined-task-search-result-list-element.title": "Declinado, enviar de vuelta al Administrador de Revisión del flujo de trabajo", - // "collection.create.head": "Create a Collection", "collection.create.head": "Crear una colección", @@ -1320,8 +1347,6 @@ // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", "collection.delete.text": "¿Estás seguro de que quieres eliminar la colección \"{{ dso }}\"?", - - // "collection.edit.delete": "Delete this collection", "collection.edit.delete": "Eliminar esta colección", @@ -1331,8 +1356,6 @@ // "collection.edit.breadcrumbs": "Edit Collection", "collection.edit.breadcrumbs": "Editar colección", - - // "collection.edit.tabs.mapper.head": "Item Mapper", "collection.edit.tabs.mapper.head": "Mapeo de ítems", @@ -1393,7 +1416,6 @@ // "collection.edit.item-mapper.tabs.map": "Map new items", "collection.edit.item-mapper.tabs.map": "Asignar nuevos ítems", - // "collection.edit.logo.delete.title": "Delete logo", "collection.edit.logo.delete.title": "Eliminar logo", @@ -1421,21 +1443,23 @@ // "collection.edit.logo.upload": "Drop a Collection Logo to upload", "collection.edit.logo.upload": "Suelta un logotipo de colección para cargarlo", - - // "collection.edit.notifications.success": "Successfully edited the Collection", "collection.edit.notifications.success": "Editó con éxito la colección", // "collection.edit.return": "Back", "collection.edit.return": "Atrás", + // "collection.edit.tabs.access-control.head": "Access Control", + "collection.edit.tabs.access-control.head": "Control de acceso", + // "collection.edit.tabs.access-control.title": "Collection Edit - Access Control", + "collection.edit.tabs.access-control.title": "Edición de colección: Control de acceso", // "collection.edit.tabs.curate.head": "Curate", "collection.edit.tabs.curate.head": "Curar", // "collection.edit.tabs.curate.title": "Collection Edit - Curate", - "collection.edit.tabs.curate.title": "Edición de colección - Curar", + "collection.edit.tabs.curate.title": "Edición de colección: Curar", // "collection.edit.tabs.authorizations.head": "Authorizations", "collection.edit.tabs.authorizations.head": "Autorizaciones", @@ -1518,8 +1542,6 @@ // "collection.edit.tabs.source.title": "Collection Edit - Content Source", "collection.edit.tabs.source.title": "Edición de colección: fuente de contenido", - - // "collection.edit.template.add-button": "Add", "collection.edit.template.add-button": "Agregar", @@ -1556,8 +1578,6 @@ // "collection.edit.template.title": "Edit Template Item", "collection.edit.template.title": "Editar plantilla de ítem", - - // "collection.form.abstract": "Short Description", "collection.form.abstract": "Breve descripción", @@ -1585,13 +1605,9 @@ // "collection.form.entityType": "Entity Type", "collection.form.entityType": "Tipo de entidad", - - // "collection.listelement.badge": "Collection", "collection.listelement.badge": "Colección", - - // "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.head": "Envíos recientes", @@ -1610,8 +1626,6 @@ // "collection.page.news": "News", "collection.page.news": "Noticias", - - // "collection.select.confirm": "Confirm selected", "collection.select.confirm": "Confirmar seleccionado", @@ -1621,63 +1635,81 @@ // "collection.select.table.title": "Title", "collection.select.table.title": "Título", - // "collection.source.controls.head": "Harvest Controls", "collection.source.controls.head": "Controles de recolección", + // "collection.source.controls.test.submit.error": "Something went wrong with initiating the testing of the settings", "collection.source.controls.test.submit.error": "Hubo fallos al realizar las pruebas de comprobación de los ajustes", + // "collection.source.controls.test.failed": "The script to test the settings has failed", "collection.source.controls.test.failed": "La prueba de los ajustes ha fallado", + // "collection.source.controls.test.completed": "The script to test the settings has successfully finished", "collection.source.controls.test.completed": "El script de prueba de los ajustes ha terminado correctamente", + // "collection.source.controls.test.submit": "Test configuration", "collection.source.controls.test.submit": "Probar la configuración", + // "collection.source.controls.test.running": "Testing configuration...", "collection.source.controls.test.running": "Probando la configuración...", + // "collection.source.controls.import.submit.success": "The import has been successfully initiated", "collection.source.controls.import.submit.success": "La importación ha comenzado correctamente", + // "collection.source.controls.import.submit.error": "Something went wrong with initiating the import", "collection.source.controls.import.submit.error": "Hubo algún fallo al iniciar la importación", + // "collection.source.controls.import.submit": "Import now", "collection.source.controls.import.submit": "Importar ahora", + // "collection.source.controls.import.running": "Importing...", "collection.source.controls.import.running": "Importando...", + // "collection.source.controls.import.failed": "An error occurred during the import", "collection.source.controls.import.failed": "Ha ocurrido un error durante la importación", + // "collection.source.controls.import.completed": "The import completed", "collection.source.controls.import.completed": "La importación finalizó", + // "collection.source.controls.reset.submit.success": "The reset and reimport has been successfully initiated", "collection.source.controls.reset.submit.success": "La restauración y reimportación ha comenzado correctamente", + // "collection.source.controls.reset.submit.error": "Something went wrong with initiating the reset and reimport", "collection.source.controls.reset.submit.error": "Ha ocurrido un error al iniciar la restauración y reimportación", + // "collection.source.controls.reset.failed": "An error occurred during the reset and reimport", "collection.source.controls.reset.failed": "Ha ocurrido un error en la restauración y reimportación", + // "collection.source.controls.reset.completed": "The reset and reimport completed", "collection.source.controls.reset.completed": "Restauración y reimportación finalizadas", + // "collection.source.controls.reset.submit": "Reset and reimport", "collection.source.controls.reset.submit": "Restauración y reimportación", + // "collection.source.controls.reset.running": "Resetting and reimporting...", "collection.source.controls.reset.running": "Restaurando y reimportando...", + // "collection.source.controls.harvest.status": "Harvest status:", "collection.source.controls.harvest.status": "Estado de la Recolección:", + // "collection.source.controls.harvest.start": "Harvest start time:", "collection.source.controls.harvest.start": "Comienzo de la recolección:", + // "collection.source.controls.harvest.last": "Last time harvested:", "collection.source.controls.harvest.last": "Fecha de la última recolección:", + // "collection.source.controls.harvest.message": "Harvest info:", "collection.source.controls.harvest.message": "Información de recolección:", + // "collection.source.controls.harvest.no-information": "N/A", "collection.source.controls.harvest.no-information": "N/A", - // "collection.source.update.notifications.error.content": "The provided settings have been tested and didn't work.", "collection.source.update.notifications.error.content": "La configuración proporcionada se ha probado y no funcionó.", // "collection.source.update.notifications.error.title": "Server Error", "collection.source.update.notifications.error.title": "Error del Servidor", - - // "communityList.breadcrumbs": "Community List", "communityList.breadcrumbs": "Lista de comunidades", @@ -1690,8 +1722,6 @@ // "communityList.showMore": "Show More", "communityList.showMore": "Mostrar más", - - // "community.create.head": "Create a Community", "community.create.head": "Crear una comunidad", @@ -1734,7 +1764,6 @@ // "community.edit.breadcrumbs": "Edit Community", "community.edit.breadcrumbs": "Editar comunidad", - // "community.edit.logo.delete.title": "Delete logo", "community.edit.logo.delete.title": "Eliminar logo", @@ -1762,8 +1791,6 @@ // "community.edit.logo.upload": "Drop a Community Logo to upload", "community.edit.logo.upload": "Suelta un logotipo de la comunidad para cargar", - - // "community.edit.notifications.success": "Successfully edited the Community", "community.edit.notifications.success": "Editó con éxito la comunidad", @@ -1776,14 +1803,18 @@ // "community.edit.return": "Back", "community.edit.return": "Atrás", - - // "community.edit.tabs.curate.head": "Curate", "community.edit.tabs.curate.head": "Curar", // "community.edit.tabs.curate.title": "Community Edit - Curate", "community.edit.tabs.curate.title": "Edición de la comunidad - Curar", + // "community.edit.tabs.access-control.head": "Access Control", + "community.edit.tabs.access-control.head": "Control de acceso", + + // "community.edit.tabs.access-control.title": "Community Edit - Access Control", + "community.edit.tabs.access-control.title": "Edición de la comunidad: Control de acceso", + // "community.edit.tabs.metadata.head": "Edit Metadata", "community.edit.tabs.metadata.head": "Editar metadatos", @@ -1802,13 +1833,9 @@ // "community.edit.tabs.authorizations.title": "Community Edit - Authorizations", "community.edit.tabs.authorizations.title": "Edición de la comunidad: autorizaciones", - - // "community.listelement.badge": "Community", "community.listelement.badge": "Comunidad", - - // "comcol-role.edit.no-group": "None", "comcol-role.edit.no-group": "Ninguno", @@ -1827,28 +1854,24 @@ // "comcol-role.edit.delete.error.title": "Failed to delete the '{{ role }}' role's group", "comcol-role.edit.delete.error.title": "Error al borrar el grupo del rol '{{ role }}'", - // "comcol-role.edit.community-admin.name": "Administrators", "comcol-role.edit.community-admin.name": "Administradores", // "comcol-role.edit.collection-admin.name": "Administrators", "comcol-role.edit.collection-admin.name": "Administradores", - // "comcol-role.edit.community-admin.description": "Community administrators can create sub-communities or collections, and manage or assign management for those sub-communities or collections. In addition, they decide who can submit items to any sub-collections, edit item metadata (after submission), and add (map) existing items from other collections (subject to authorization).", "comcol-role.edit.community-admin.description": "Los administradores de la comunidad pueden crear subcomunidades o colecciones y gestionar o asignar la gestión para esas subcomunidades o colecciones. Además, deciden quién puede enviar ítems a las subcolecciones, editar los metadatos del ítem (después del envío) y agregar (mapear) ítems existentes de otras colecciones (sujeto a autorización).", // "comcol-role.edit.collection-admin.description": "Collection administrators decide who can submit items to the collection, edit item metadata (after submission), and add (map) existing items from other collections to this collection (subject to authorization for that collection).", "comcol-role.edit.collection-admin.description": "Los administradores de la colección deciden quién puede enviar ítems a la colección, editar los metadatos del ítem (después del envío) y agregar (mapear) ítems existentes de otras colecciones a esta colección (sujeto a autorización para esa colección).", - // "comcol-role.edit.submitters.name": "Submitters", "comcol-role.edit.submitters.name": "Remitentes", // "comcol-role.edit.submitters.description": "The E-People and Groups that have permission to submit new items to this collection.", "comcol-role.edit.submitters.description": "Los Usuarios y Grupos que tienen permiso para enviar nuevos ítems a esta colección.", - // "comcol-role.edit.item_read.name": "Default item read access", "comcol-role.edit.item_read.name": "Acceso de lectura predeterminado del ítem", @@ -1858,7 +1881,6 @@ // "comcol-role.edit.item_read.anonymous-group": "Default read for incoming items is currently set to Anonymous.", "comcol-role.edit.item_read.anonymous-group": "La lectura predeterminada para los ítems entrantes está configurada actualmente como Anónimo.", - // "comcol-role.edit.bitstream_read.name": "Default bitstream read access", "comcol-role.edit.bitstream_read.name": "Acceso de lectura predeterminado de archivos", @@ -1868,28 +1890,24 @@ // "comcol-role.edit.bitstream_read.anonymous-group": "Default read for incoming bitstreams is currently set to Anonymous.", "comcol-role.edit.bitstream_read.anonymous-group": "La lectura predeterminada para los archivos entrantes se establece actualmente en Anónimo.", - // "comcol-role.edit.editor.name": "Editors", "comcol-role.edit.editor.name": "Editores", // "comcol-role.edit.editor.description": "Editors are able to edit the metadata of incoming submissions, and then accept or reject them.", "comcol-role.edit.editor.description": "Los editores pueden editar los metadatos de los envíos entrantes y luego aceptarlos o rechazarlos.", - // "comcol-role.edit.finaleditor.name": "Final editors", "comcol-role.edit.finaleditor.name": "Editores finales", // "comcol-role.edit.finaleditor.description": "Final editors are able to edit the metadata of incoming submissions, but will not be able to reject them.", "comcol-role.edit.finaleditor.description": "Los editores finales pueden editar los metadatos de los envíos entrantes, pero no podrán rechazarlos.", - // "comcol-role.edit.reviewer.name": "Reviewers", "comcol-role.edit.reviewer.name": "Revisores", // "comcol-role.edit.reviewer.description": "Reviewers are able to accept or reject incoming submissions. However, they are not able to edit the submission's metadata.", "comcol-role.edit.reviewer.description": "Los revisores pueden aceptar o rechazar envíos entrantes. Sin embargo, no pueden editar los metadatos del envío.", - // "comcol-role.edit.scorereviewers.name": "Score Reviewers", "comcol-role.edit.scorereviewers.name": "Revisores de puntuación", @@ -1929,14 +1947,12 @@ // "community.all-lists.head": "Subcommunities and Collections", "community.all-lists.head": "Subcomunidades y colecciones", - // "community.sub-collection-list.head": "Collections of this Community", + // "community.sub-collection-list.head": "Collections in this Community", "community.sub-collection-list.head": "Colecciones de esta comunidad", - // "community.sub-community-list.head": "Communities of this Community", + // "community.sub-community-list.head": "Communities in this Community", "community.sub-community-list.head": "Comunidades de esta comunidad", - - // "cookies.consent.accept-all": "Accept all", "cookies.consent.accept-all": "Aceptar todo", @@ -2015,38 +2031,30 @@ // "cookies.consent.app.description.authentication": "Required for signing you in", "cookies.consent.app.description.authentication": "Requerido para iniciar sesión", - // "cookies.consent.app.title.preferences": "Preferences", "cookies.consent.app.title.preferences": "Preferencias", // "cookies.consent.app.description.preferences": "Required for saving your preferences", "cookies.consent.app.description.preferences": "Requerido para guardar sus preferencias", - - // "cookies.consent.app.title.acknowledgement": "Acknowledgement", "cookies.consent.app.title.acknowledgement": "Reconocimiento", // "cookies.consent.app.description.acknowledgement": "Required for saving your acknowledgements and consents", "cookies.consent.app.description.acknowledgement": "Requerido para guardar sus reconocimientos y consentimientos", - - // "cookies.consent.app.title.google-analytics": "Google Analytics", "cookies.consent.app.title.google-analytics": "Google Analytics", // "cookies.consent.app.description.google-analytics": "Allows us to track statistical data", "cookies.consent.app.description.google-analytics": "Nos permite rastrear datos estadísticos", - - // "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", // "cookies.consent.app.description.google-recaptcha": "We use google reCAPTCHA service during registration and password recovery", "cookies.consent.app.description.google-recaptcha": "Utilizamos el servicio google reCAPTCHA durante el registro y la recuperación de contraseña", - // "cookies.consent.purpose.functional": "Functional", "cookies.consent.purpose.functional": "Funcional", @@ -2059,10 +2067,10 @@ // "cookies.consent.purpose.sharing": "Sharing", "cookies.consent.purpose.sharing": "Compartición", - // "curation-task.task.citationpage.label": "Generate Citation Page", + // "curation-task.task.citationpage.label": "Generate Citation Page", "curation-task.task.citationpage.label": "Generar página de cita", - // "curation-task.task.checklinks.label": "Check Links in Metadata", + // "curation-task.task.checklinks.label": "Check Links in Metadata", "curation-task.task.checklinks.label": "Comprobar enlaces en metadatos", // "curation-task.task.noop.label": "NOOP", @@ -2083,8 +2091,6 @@ // "curation-task.task.register-doi.label": "Register DOI", "curation-task.task.register-doi.label": "Registro DOI", - - // "curation.form.task-select.label": "Task:", "curation.form.task-select.label": "Tarea:", @@ -2112,10 +2118,8 @@ // "curation.form.handle.hint": "Hint: Enter [your-handle-prefix]/0 to run a task across entire site (not all tasks may support this capability)", "curation.form.handle.hint": "Sugerencia: Introduzca [su-prefijo-handle]/0 para ejecutar una tarea en toda su instalación (no todas las tareas permiten esta opción)", - - // "deny-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I regret to inform you that it's not possible to send you a copy of the file(s) you have requested, concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am an author.\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>", - "deny-request-copy.email.message": "Estimado {{ recipientName }},\nEn respuesta a su solicitud, lamento informarle que no es posible enviarle una copia de los archivos que ha solicitado, en relación con el documento: \"{{ itemUrl }}\" ({{ itemName }}), del cual soy autor.\n\nSaludos cordiales,\n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.message": "Estimado {{ recipientName }},\nEn respuesta a su solicitud, lamento informarle de que no es posible enviarle una copia de los archivos que ha solicitado, en relación con el documento: \"{{ itemUrl }}\" ({{ itemName }}), del cual soy autor.\n\nSaludos cordiales,\n{{ authorName }} <{{ authorEmail }}>", // "deny-request-copy.email.subject": "Request copy of document", "deny-request-copy.email.subject": "Solicitar una copia del documento", @@ -2127,17 +2131,16 @@ "deny-request-copy.header": "Denegar copia del documento", // "deny-request-copy.intro": "This message will be sent to the applicant of the request", - "deny-request-copy.intro": "Éste es el texto que será enviado al solicitante.", + "deny-request-copy.intro": "Éste es el texto que será enviado al solicitante", // "deny-request-copy.success": "Successfully denied item request", "deny-request-copy.success": "Solicitud de copia de documento denegada", - - // "dso.name.untitled": "Untitled", "dso.name.untitled": "Sin título", - + // "dso.name.unnamed": "Unnamed", + "dso.name.unnamed": "Sin nombre", // "dso-selector.create.collection.head": "New collection", "dso-selector.create.collection.head": "Nueva colección", @@ -2259,7 +2262,7 @@ // "supervision-group-selector.notification.create.failure.title": "Error", "supervision-group-selector.notification.create.failure.title": "Error", - // "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": "A supervision order already exists on this item for selected group", "supervision-group-selector.notification.create.already-existing": "Ya existe una orden de supervisión para este ítem en el grupo selecionado", // "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", @@ -2374,7 +2377,7 @@ "error.top-level-communities": "Error al recuperar las comunidades de primer nivel", // "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": "Debe conceda esta licencia de depósito para completar el envío. Si no puede conceder esta licencia en este momento, puede guardar su trabajo y regresar más tarde o bien eliminar el envío.", + "error.validation.license.notgranted": "Debe conceder esta licencia de depósito para completar el envío. Si no puede conceder esta licencia en este momento, puede guardar su trabajo y regresar más tarde o bien eliminar el envío.", // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", "error.validation.pattern": "Esta entrada está restringida por este patrón: {{ pattern }}.", @@ -2394,16 +2397,33 @@ // "error.validation.groupExists": "This group already exists", "error.validation.groupExists": "Este grupo ya existe", + // "error.validation.metadata.name.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Element & Qualifier fields instead", + "error.validation.metadata.name.invalid-pattern": "Este campo no puede contener puntos, comas o espacios. Use preferiblemente los campos Elemento y Cualificador", + + // "error.validation.metadata.name.max-length": "This field may not contain more than 32 characters", + "error.validation.metadata.name.max-length": "Este campo no puede contener mas de 32 caracteres", + + // "error.validation.metadata.namespace.max-length": "This field may not contain more than 256 characters", + "error.validation.metadata.namespace.max-length": "Este campo no puede contener mas de 256 caracteres", + + // "error.validation.metadata.element.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Qualifier field instead", + "error.validation.metadata.element.invalid-pattern": "Este campo no puede contener puntos, comas o espacios. Use preferiblemente el campo Cualificador", + + // "error.validation.metadata.element.max-length": "This field may not contain more than 64 characters", + "error.validation.metadata.element.max-length": "Este campo no puede contener mas de 64 caracteres", + + // "error.validation.metadata.qualifier.invalid-pattern": "This field cannot contain dots, commas or spaces", + "error.validation.metadata.qualifier.invalid-pattern": "This field cannot contain dots, commas or spaces", + + // "error.validation.metadata.qualifier.max-length": "This field may not contain more than 64 characters", + "error.validation.metadata.qualifier.max-length": "Este campo no puede contener mas de 64 caracteres", // "feed.description": "Syndication feed", "feed.description": "Hilo de sindicación", - // "file-section.error.header": "Error obtaining files for this item", "file-section.error.header": "Error al obtener archivos para este ítem", - - // "footer.copyright": "copyright © 2002-{{ year }}", "footer.copyright": "copyright © 2002-{{ year }}", @@ -2419,14 +2439,12 @@ // "footer.link.privacy-policy": "Privacy policy", "footer.link.privacy-policy": "Política de privacidad", - // "footer.link.end-user-agreement":"End User Agreement", + // "footer.link.end-user-agreement": "End User Agreement", "footer.link.end-user-agreement": "Acuerdo de usuario final", - // "footer.link.feedback":"Send Feedback", + // "footer.link.feedback": "Send Feedback", "footer.link.feedback": "Enviar Sugerencias", - - // "forgot-email.form.header": "Forgot Password", "forgot-email.form.header": "Olvido de contraseña", @@ -2460,8 +2478,6 @@ // "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": "Ha ocurrido una error intentando restablecer la contraseña para la cuenta asociada al correo electrónico: {{ email }}", - - // "forgot-password.title": "Forgot Password", "forgot-password.title": "Olvido de contraseña", @@ -2504,7 +2520,6 @@ // "forgot-password.form.submit": "Submit password", "forgot-password.form.submit": "Enviar contraseña", - // "form.add": "Add more", "form.add": "Añadir más", @@ -2565,6 +2580,24 @@ // "form.no-value": "No value entered", "form.no-value": "No se introdujo ningún valor", + // "form.other-information.email": "Email", + "form.other-information.email": "Correo electrónico", + + // "form.other-information.first-name": "First Name", + "form.other-information.first-name": "Nombre", + + // "form.other-information.insolr": "In Solr Index", + "form.other-information.insolr": "en el índice Solr", + + // "form.other-information.institution": "Institution", + "form.other-information.institution": "Institución", + + // "form.other-information.last-name": "Last Name", + "form.other-information.last-name": "Apellido", + + // "form.other-information.orcid": "ORCID", + "form.other-information.orcid": "ORCID", + // "form.remove": "Remove", "form.remove": "Eliminar", @@ -2589,16 +2622,14 @@ // "form.repeatable.sort.tip": "Drop the item in the new position", "form.repeatable.sort.tip": "Suelte el ítem en la nueva posición", - - // "grant-deny-request-copy.deny": "Don't send copy", "grant-deny-request-copy.deny": "No envíe copia", // "grant-deny-request-copy.email.back": "Back", "grant-deny-request-copy.email.back": "Atrás", - // "grant-deny-request-copy.email.message": "Message", - "grant-deny-request-copy.email.message": "Mensaje", + // "grant-deny-request-copy.email.message": "Optional additional message", + "grant-deny-request-copy.email.message": "Mensaje adicional (opcional)", // "grant-deny-request-copy.email.message.empty": "Please enter a message", "grant-deny-request-copy.email.message.empty": "Por favor, introduzca un mensaje", @@ -2636,11 +2667,6 @@ // "grant-deny-request-copy.processed": "This request has already been processed. You can use the button below to get back to the home page.", "grant-deny-request-copy.processed": "Esta solicitud ya fue procesada. Puede usar los botones inferiores para regresas a la página de inicio", - - - // "grant-request-copy.email.message": "Dear {{ recipientName }},\nIn response to your request I have the pleasure to send you in attachment a copy of the file(s) concerning the document: \"{{ itemUrl }}\" ({{ itemName }}), of which I am an author.\n\nBest regards,\n{{ authorName }} <{{ authorEmail }}>", - "grant-request-copy.email.message": "Estimado {{ recipientName }},\nRespondiendo a su solicitud, le envío anexada una copia del fichero correspondiente al documento: \"{{ itemUrl }}\" ({{ itemName }}), del que soy autor.\n\nUn cordial saludo,\n{{ authorName }} <{{ authorEmail }}>", - // "grant-request-copy.email.subject": "Request copy of document", "grant-request-copy.email.subject": "Solicitar copia de documento", @@ -2650,24 +2676,23 @@ // "grant-request-copy.header": "Grant document copy request", "grant-request-copy.header": "Conceder solicitud de copia de documento", - // "grant-request-copy.intro": "This message will be sent to the applicant of the request. The requested document(s) will be attached.", - "grant-request-copy.intro": "Este mensaje se enviará al solicitante de la copia. Se le anexará una copia del documento.", + // "grant-request-copy.intro": "A message will be sent to the applicant of the request. The requested document(s) will be attached.", + "grant-request-copy.intro": "Este mensaje se enviará al solicitante de la copia. Se le anexará una copia del documento.", // "grant-request-copy.success": "Successfully granted item request", "grant-request-copy.success": "Solicitud de ítem concedida exitosamente", - // "health.breadcrumbs": "Health", "health.breadcrumbs": "Chequeos", - // "health-page.heading" : "Health", - "health-page.heading": "Chequeos", + // "health-page.heading": "Health", + "health-page.heading": "Chequeos", - // "health-page.info-tab" : "Info", - "health-page.info-tab": "Información", + // "health-page.info-tab": "Info", + "health-page.info-tab": "Información", - // "health-page.status-tab" : "Status", - "health-page.status-tab": "Estado", + // "health-page.status-tab": "Status", + "health-page.status-tab": "Estado", // "health-page.error.msg": "The health check service is temporarily unavailable", "health-page.error.msg": "El servicio de comprobación no se encuentra temporalmente disponible", @@ -2717,7 +2742,6 @@ // "health-page.section.no-issues": "No issues detected", "health-page.section.no-issues": "No se detectaron problemas", - // "home.description": "", "home.description": "", @@ -2736,8 +2760,6 @@ // "home.top-level-communities.help": "Select a community to browse its collections.", "home.top-level-communities.help": "Seleccione una comunidad para explorar sus colecciones.", - - // "info.end-user-agreement.accept": "I have read and I agree to the End User Agreement", "info.end-user-agreement.accept": "He leído y acepto el Acuerdo de usuario final.", @@ -2762,6 +2784,9 @@ // "info.end-user-agreement.title": "End User Agreement", "info.end-user-agreement.title": "Acuerdo de usuario final", + // "info.end-user-agreement.hosting-country": "the United States", + "info.end-user-agreement.hosting-country": "los Estados Unidos de América", + // "info.privacy.breadcrumbs": "Privacy Statement", "info.privacy.breadcrumbs": "Declaracion de privacidad", @@ -2795,47 +2820,39 @@ // "info.feedback.email-label": "Your Email", "info.feedback.email-label": "Su correo electrónico", - // "info.feedback.create.success" : "Feedback Sent Successfully!", + // "info.feedback.create.success": "Feedback Sent Successfully!", "info.feedback.create.success": "Envío exitoso de sugerencia", - // "info.feedback.error.email.required" : "A valid email address is required", + // "info.feedback.error.email.required": "A valid email address is required", "info.feedback.error.email.required": "se requiere una dirección válida de correo electrónico", - // "info.feedback.error.message.required" : "A comment is required", + // "info.feedback.error.message.required": "A comment is required", "info.feedback.error.message.required": "Se requiere un comentario", - // "info.feedback.page-label" : "Page", + // "info.feedback.page-label": "Page", "info.feedback.page-label": "Página", - // "info.feedback.page_help" : "Tha page related to your feedback", + // "info.feedback.page_help": "Tha page related to your feedback", "info.feedback.page_help": "La página relacionada con su sugerencia", - - // "item.alerts.private": "This item is non-discoverable", "item.alerts.private": "Este ítem es privado", // "item.alerts.withdrawn": "This item has been withdrawn", "item.alerts.withdrawn": "Este ítem ha sido retirado", - - // "item.edit.authorizations.heading": "With this editor you can view and alter the policies of an item, plus alter policies of individual item components: bundles and bitstreams. Briefly, an item is a container of bundles, and bundles are containers of bitstreams. Containers usually have ADD/REMOVE/READ/WRITE policies, while bitstreams only have READ/WRITE policies.", "item.edit.authorizations.heading": "Con este editor puede ver y modificar las políticas de un ítem, además de modificar las políticas de los componentes individuales del ítem: paquetes y archivos. Brevemente, un ítem es un contenedor de paquetes y los paquetes son contenedores de archivos. Los contenedores suelen tener políticas AGREGAR/ELIMINAR/LEER/ESCRIBIR, mientras que los archivos solo tienen políticas LEER/ESCRIBIR.", // "item.edit.authorizations.title": "Edit item's Policies", "item.edit.authorizations.title": "Editar las políticas del ítem", - - // "item.badge.private": "Non-discoverable", "item.badge.private": "Privado", // "item.badge.withdrawn": "Withdrawn", "item.badge.withdrawn": "Retirado", - - // "item.bitstreams.upload.bundle": "Bundle", "item.bitstreams.upload.bundle": "Bloque", @@ -2869,8 +2886,6 @@ // "item.bitstreams.upload.title": "Upload bitstream", "item.bitstreams.upload.title": "Subir archivo", - - // "item.edit.bitstreams.bundle.edit.buttons.upload": "Upload", "item.edit.bitstreams.bundle.edit.buttons.upload": "Subir", @@ -2961,8 +2976,6 @@ // "item.edit.bitstreams.upload-button": "Upload", "item.edit.bitstreams.upload-button": "Subir", - - // "item.edit.delete.cancel": "Cancel", "item.edit.delete.cancel": "Cancelar", @@ -2990,7 +3003,6 @@ // "item.edit.tabs.disabled.tooltip": "You're not authorized to access this tab", "item.edit.tabs.disabled.tooltip": "No tienes autorización para acceder a esta pestaña", - // "item.edit.tabs.mapper.head": "Collection Mapper", "item.edit.tabs.mapper.head": "Mapeador de colecciones", @@ -3114,8 +3126,6 @@ // "item.edit.item-mapper.tabs.map": "Map new collections", "item.edit.item-mapper.tabs.map": "Mapear nuevas colecciones", - - // "item.edit.metadata.add-button": "Add", "item.edit.metadata.add-button": "Agregar", @@ -3200,8 +3210,6 @@ // "item.edit.metadata.save-button": "Save", "item.edit.metadata.save-button": "Guardar", - - // "item.edit.modify.overview.field": "Field", "item.edit.modify.overview.field": "Campo", @@ -3211,8 +3219,6 @@ // "item.edit.modify.overview.value": "Value", "item.edit.modify.overview.value": "Valor", - - // "item.edit.move.cancel": "Back", "item.edit.move.cancel": "Atrás", @@ -3252,8 +3258,6 @@ // "item.edit.move.title": "Move item", "item.edit.move.title": "Mover ítem", - - // "item.edit.private.cancel": "Cancel", "item.edit.private.cancel": "Cancelar", @@ -3272,8 +3276,6 @@ // "item.edit.private.success": "The item is now non-discoverable", "item.edit.private.success": "El ítem ahora es privado", - - // "item.edit.public.cancel": "Cancel", "item.edit.public.cancel": "Cancelar", @@ -3292,8 +3294,6 @@ // "item.edit.public.success": "The item is now discoverable", "item.edit.public.success": "El ítem ahora es público", - - // "item.edit.reinstate.cancel": "Cancel", "item.edit.reinstate.cancel": "Cancelar", @@ -3312,8 +3312,6 @@ // "item.edit.reinstate.success": "The item was reinstated successfully", "item.edit.reinstate.success": "El ítem se reintegró correctamente", - - // "item.edit.relationships.discard-button": "Discard", "item.edit.relationships.discard-button": "Descartar", @@ -3359,11 +3357,9 @@ // "item.edit.relationships.no-entity-type": "Add 'dspace.entity.type' metadata to enable relationships for this item", "item.edit.relationships.no-entity-type": "Agregue metadatos 'dspace.entity.type' para habilitar las relaciones para este ítem", - // "item.edit.return": "Back", "item.edit.return": "Atrás", - // "item.edit.tabs.bitstreams.head": "Bitstreams", "item.edit.tabs.bitstreams.head": "Archivos", @@ -3376,6 +3372,15 @@ // "item.edit.tabs.curate.title": "Item Edit - Curate", "item.edit.tabs.curate.title": "Edición de ítem: Curar", + // "item.edit.curate.title": "Curate Item: {{item}}", + "item.edit.curate.title": "Curar ítem: {{item}}", + + // "item.edit.tabs.access-control.head": "Access Control", + "item.edit.tabs.access-control.head": "Control de acceso", + + // "item.edit.tabs.access-control.title": "Item Edit - Access Control", + "item.edit.tabs.access-control.title": "Edición de ítem: Control de acceso", + // "item.edit.tabs.metadata.head": "Metadata", "item.edit.tabs.metadata.head": "Metadatos", @@ -3407,7 +3412,7 @@ "item.edit.tabs.status.buttons.mappedCollections.label": "Administrar colecciones mapeadas", // "item.edit.tabs.status.buttons.move.button": "Move this Item to a different Collection", - "item.edit.tabs.status.buttons.move.button": "Mover éste ítem a una colección diferente", + "item.edit.tabs.status.buttons.move.button": "Mover este ítem a una colección diferente", // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", "item.edit.tabs.status.buttons.move.label": "Mover ítem a otra colección", @@ -3434,7 +3439,7 @@ "item.edit.tabs.status.buttons.unauthorized": "No estás autorizado para realizar esta acción.", // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw this item", - "item.edit.tabs.status.buttons.withdraw.button": "Retirar éste ítem", + "item.edit.tabs.status.buttons.withdraw.button": "Retirar este ítem", // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", "item.edit.tabs.status.buttons.withdraw.label": "Retirar ítem del repositorio", @@ -3475,8 +3480,6 @@ // "item.edit.tabs.view.title": "Item Edit - View", "item.edit.tabs.view.title": "Edición de ítem - Ver", - - // "item.edit.withdraw.cancel": "Cancel", "item.edit.withdraw.cancel": "Cancelar", @@ -3498,7 +3501,6 @@ // "item.orcid.return": "Back", "item.orcid.return": "Atrás", - // "item.listelement.badge": "Item", "item.listelement.badge": "Ítem", @@ -3556,8 +3558,6 @@ // "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group", "workflow-item.search.result.list.element.supervised.remove-tooltip": "Borrar grupo de supervisión", - - // "item.page.abstract": "Abstract", "item.page.abstract": "Resumen", @@ -3648,10 +3648,10 @@ // "item.page.bitstreams.collapse": "Collapse", "item.page.bitstreams.collapse": "Contraer", - // "item.page.filesection.original.bundle" : "Original bundle", + // "item.page.filesection.original.bundle": "Original bundle", "item.page.filesection.original.bundle": "Bloque original", - // "item.page.filesection.license.bundle" : "License bundle", + // "item.page.filesection.license.bundle": "License bundle", "item.page.filesection.license.bundle": "Bloque de licencias", // "item.page.return": "Back", @@ -3696,27 +3696,30 @@ // "item.preview.dc.type": "Type:", "item.preview.dc.type": "Tipo:", - // "item.preview.oaire.citation.issue" : "Issue", + // "item.preview.oaire.citation.issue": "Issue", "item.preview.oaire.citation.issue": "Número", - // "item.preview.oaire.citation.volume" : "Volume", + // "item.preview.oaire.citation.volume": "Volume", "item.preview.oaire.citation.volume": "Volumen", - // "item.preview.dc.relation.issn" : "ISSN", + // "item.preview.dc.relation.issn": "ISSN", "item.preview.dc.relation.issn": "ISSN", - // "item.preview.dc.identifier.isbn" : "ISBN", + // "item.preview.dc.identifier.isbn": "ISBN", "item.preview.dc.identifier.isbn": "ISBN", // "item.preview.dc.identifier": "Identifier:", "item.preview.dc.identifier": "Identificador:", - // "item.preview.dc.relation.ispartof" : "Journal or Serie", + // "item.preview.dc.relation.ispartof": "Journal or Series", "item.preview.dc.relation.ispartof": "Revista o Serie", - // "item.preview.dc.identifier.doi" : "DOI", + // "item.preview.dc.identifier.doi": "DOI", "item.preview.dc.identifier.doi": "DOI", + // "item.preview.dc.publisher": "Publisher:", + "item.preview.dc.publisher": "Editor:", + // "item.preview.person.familyName": "Surname:", "item.preview.person.familyName": "Apellido:", @@ -3744,8 +3747,6 @@ // "item.preview.oaire.fundingStream": "Funding Stream:", "item.preview.oaire.fundingStream": "Línea de financiación:", - - // "item.select.confirm": "Confirm selected", "item.select.confirm": "Confirmar seleccionado", @@ -3761,7 +3762,6 @@ // "item.select.table.title": "Title", "item.select.table.title": "Título", - // "item.version.history.empty": "There are no other versions for this item yet.", "item.version.history.empty": "Aún no hay otras versiones para este ítem.", @@ -3822,11 +3822,9 @@ // "item.version.history.table.action.hasDraft": "A new version cannot be created because there is an inprogress submission in the version history", "item.version.history.table.action.hasDraft": "No es posible crear una nueva versión puesto que existe en el historial de versiones un envío pendiente", - // "item.version.notice": "This is not the latest version of this item. The latest version can be found <a href='{{destination}}'>here</a>.", "item.version.notice": "Esta no es la última versión de este ítem. La última versión se puede encontrar <a href='{{ destination }}'>aquí</a>.", - // "item.version.create.modal.header": "New version", "item.version.create.modal.header": "Nueva versión", @@ -3860,21 +3858,20 @@ // "item.version.create.modal.submitted.text": "The new version is being created. This may take some time if the item has a lot of relationships.", "item.version.create.modal.submitted.text": "Se está creando la nueva versión. Si el ítem tiene muchas relaciones, este proceso podría tardar.", - // "item.version.create.notification.success" : "New version has been created with version number {{version}}", + // "item.version.create.notification.success": "New version has been created with version number {{version}}", "item.version.create.notification.success": "Se ha creado una nueva versión con número {{version}}", - // "item.version.create.notification.failure" : "New version has not been created", + // "item.version.create.notification.failure": "New version has not been created", "item.version.create.notification.failure": "No se ha creado una nueva versión", - // "item.version.create.notification.inProgress" : "A new version cannot be created because there is an inprogress submission in the version history", + // "item.version.create.notification.inProgress": "A new version cannot be created because there is an inprogress submission in the version history", "item.version.create.notification.inProgress": "No es posible crear una nueva versión puesto que existe en el historial de versiones un envío pendiente", - // "item.version.delete.modal.header": "Delete version", "item.version.delete.modal.header": "Borrar versión", // "item.version.delete.modal.text": "Do you want to delete version {{version}}?", - "item.version.delete.modal.text": "Quiere borrar la versión {{version}}?", + "item.version.delete.modal.text": "¿Quiere borrar la versión {{version}}?", // "item.version.delete.modal.button.confirm": "Delete", "item.version.delete.modal.button.confirm": "Borrar", @@ -3888,21 +3885,18 @@ // "item.version.delete.modal.button.cancel.tooltip": "Do not delete this version", "item.version.delete.modal.button.cancel.tooltip": "No borrar esta versión", - // "item.version.delete.notification.success" : "Version number {{version}} has been deleted", + // "item.version.delete.notification.success": "Version number {{version}} has been deleted", "item.version.delete.notification.success": "Se ha borrado la versión número {{version}}", - // "item.version.delete.notification.failure" : "Version number {{version}} has not been deleted", + // "item.version.delete.notification.failure": "Version number {{version}} has not been deleted", "item.version.delete.notification.failure": "No se ha borrado la versión número {{version}}", + // "item.version.edit.notification.success": "The summary of version number {{version}} has been changed", + "item.version.edit.notification.success": "Se ha cambiado el resumen de la versión número {{version}}", - // "item.version.edit.notification.success" : "The summary of version number {{version}} has been changed", - "item.version.edit.notification.success": "Ha cambiado el resumen de la versión número {{version}}", - - // "item.version.edit.notification.failure" : "The summary of version number {{version}} has not been changed", + // "item.version.edit.notification.failure": "The summary of version number {{version}} has not been changed", "item.version.edit.notification.failure": "No ha cambiado el resumen de la versión número {{version}}", - - // "itemtemplate.edit.metadata.add-button": "Add", "itemtemplate.edit.metadata.add-button": "Agregar", @@ -3984,8 +3978,6 @@ // "itemtemplate.edit.metadata.save-button": "Save", "itemtemplate.edit.metadata.save-button": "Guardar", - - // "journal.listelement.badge": "Journal", "journal.listelement.badge": "Revista", @@ -4016,8 +4008,6 @@ // "journal.search.title": "Journal Search", "journal.search.title": "Búsqueda de revistas", - - // "journalissue.listelement.badge": "Journal Issue", "journalissue.listelement.badge": "Número de la revista", @@ -4045,8 +4035,6 @@ // "journalissue.page.titleprefix": "Journal Issue: ", "journalissue.page.titleprefix": "Número de la revista: ", - - // "journalvolume.listelement.badge": "Journal Volume", "journalvolume.listelement.badge": "Volumen de la revista", @@ -4065,7 +4053,6 @@ // "journalvolume.page.volume": "Volume", "journalvolume.page.volume": "Volumen", - // "iiifsearchable.listelement.badge": "Document Media", "iiifsearchable.listelement.badge": "Soporte (media) del documento", @@ -4099,7 +4086,6 @@ // "iiif.page.description": "Description: ", "iiif.page.description": "Descripción: ", - // "loading.bitstream": "Loading bitstream...", "loading.bitstream": "Cargando archivo...", @@ -4154,8 +4140,6 @@ // "loading.top-level-communities": "Loading top-level communities...", "loading.top-level-communities": "Cargando comunidades de primer nivel...", - - // "login.form.email": "Email address", "login.form.email": "Correo electrónico", @@ -4192,8 +4176,6 @@ // "login.breadcrumbs": "Login", "login.breadcrumbs": "Acceso", - - // "logout.form.header": "Log out from DSpace", "logout.form.header": "Cerrar sesión en DSpace", @@ -4203,8 +4185,6 @@ // "logout.title": "Logout", "logout.title": "Cerrar sesión", - - // "menu.header.admin": "Management", "menu.header.admin": "Gestión", @@ -4214,27 +4194,24 @@ // "menu.header.admin.description": "Management menu", "menu.header.admin.description": "Menú de gestión", - - // "menu.section.access_control": "Access Control", "menu.section.access_control": "Control de acceso", // "menu.section.access_control_authorizations": "Authorizations", "menu.section.access_control_authorizations": "Autorizaciones", + // "menu.section.access_control_bulk": "Bulk Access Management", + "menu.section.access_control_bulk": "Gestión de Acceso Masivo", + // "menu.section.access_control_groups": "Groups", "menu.section.access_control_groups": "Grupos", // "menu.section.access_control_people": "People", "menu.section.access_control_people": "Usuarios", - - // "menu.section.admin_search": "Admin Search", "menu.section.admin_search": "Búsqueda de administrador", - - // "menu.section.browse_community": "This Community", "menu.section.browse_community": "Esta comunidad", @@ -4259,22 +4236,21 @@ // "menu.section.browse_global_by_subject": "By Subject", "menu.section.browse_global_by_subject": "Por tema", + // "menu.section.browse_global_by_srsc": "By Subject Category", + "menu.section.browse_global_by_srsc": "Por categoría", + // "menu.section.browse_global_by_title": "By Title", "menu.section.browse_global_by_title": "Por titulo", // "menu.section.browse_global_communities_and_collections": "Communities & Collections", "menu.section.browse_global_communities_and_collections": "Comunidades", - - // "menu.section.control_panel": "Control Panel", "menu.section.control_panel": "Panel de control", // "menu.section.curation_task": "Curation Task", "menu.section.curation_task": "Tareas de curación", - - // "menu.section.edit": "Edit", "menu.section.edit": "Editar", @@ -4287,8 +4263,6 @@ // "menu.section.edit_item": "Item", "menu.section.edit_item": "Ítem", - - // "menu.section.export": "Export", "menu.section.export": "Exportar", @@ -4307,7 +4281,6 @@ // "menu.section.export_batch": "Batch Export (ZIP)", "menu.section.export_batch": "Exportación por lotes (ZIP)", - // "menu.section.icon.access_control": "Access Control menu section", "menu.section.icon.access_control": "Sección del menú de control de acceso", @@ -4356,8 +4329,6 @@ // "menu.section.icon.unpin": "Unpin sidebar", "menu.section.icon.unpin": "Desanclar la barra lateral", - - // "menu.section.import": "Import", "menu.section.import": "Importar", @@ -4367,8 +4338,6 @@ // "menu.section.import_metadata": "Metadata", "menu.section.import_metadata": "Metadatos", - - // "menu.section.new": "New", "menu.section.new": "Nuevo", @@ -4387,24 +4356,18 @@ // "menu.section.new_process": "Process", "menu.section.new_process": "Proceso", - - // "menu.section.pin": "Pin sidebar", "menu.section.pin": "Anclar barra lateral", // "menu.section.unpin": "Unpin sidebar", "menu.section.unpin": "Desanclar la barra lateral", - - // "menu.section.processes": "Processes", "menu.section.processes": "Procesos", // "menu.section.health": "Health", "menu.section.health": "Chequeo", - - // "menu.section.registries": "Registries", "menu.section.registries": "Registros", @@ -4414,16 +4377,12 @@ // "menu.section.registries_metadata": "Metadata", "menu.section.registries_metadata": "Metadatos", - - // "menu.section.statistics": "Statistics", "menu.section.statistics": "Estadísticas", // "menu.section.statistics_task": "Statistics Task", "menu.section.statistics_task": "Tarea de estadísticas", - - // "menu.section.toggle.access_control": "Toggle Access Control section", "menu.section.toggle.access_control": "Alternar sección de control de acceso", @@ -4454,19 +4413,18 @@ // "menu.section.toggle.statistics_task": "Toggle Statistics Task section", "menu.section.toggle.statistics_task": "Alternar sección de Tarea de estadísticas", - // "menu.section.workflow": "Administer Workflow", "menu.section.workflow": "Administrar flujo de trabajo", - // "metadata-export-search.tooltip": "Export search results as CSV", "metadata-export-search.tooltip": "Exportar los resultados de búsqueda a CSV", + // "metadata-export-search.submit.success": "The export was started successfully", "metadata-export-search.submit.success": "La exportación ha comenzado satisfactoriamente", + // "metadata-export-search.submit.error": "Starting the export has failed", "metadata-export-search.submit.error": "Ha fallado el comienzo de la exportación", - // "mydspace.breadcrumbs": "MyDSpace", "mydspace.breadcrumbs": "Mi DSpace", @@ -4593,8 +4551,6 @@ // "mydspace.view-btn": "View", "mydspace.view-btn": "Ver", - - // "nav.browse.header": "All of DSpace", "nav.browse.header": "Todo DSpace", @@ -4628,25 +4584,27 @@ // "nav.search": "Search", "nav.search": "Buscar", + // "nav.search.button": "Submit search", + "nav.search.button": "Buscar", + // "nav.statistics.header": "Statistics", "nav.statistics.header": "Estadísticas", // "nav.stop-impersonating": "Stop impersonating EPerson", - "nav.stop-impersonating": "Dejar de hacerse pasar por usuario", + "nav.stop-impersonating": "Dejar de impersonar al usuario", - // "nav.subscriptions" : "Subscriptions", + // "nav.subscriptions": "Subscriptions", "nav.subscriptions": "Suscripciones", - // "nav.toggle" : "Toggle navigation", + // "nav.toggle": "Toggle navigation", "nav.toggle": "Alternar navegación", - // "nav.user.description" : "User profile bar", + // "nav.user.description": "User profile bar", "nav.user.description": "Barra de perfil de usuario", // "none.listelement.badge": "Item", "none.listelement.badge": "Ítem", - // "orgunit.listelement.badge": "Organizational Unit", "orgunit.listelement.badge": "Unidad organizativa", @@ -4674,8 +4632,6 @@ // "orgunit.page.titleprefix": "Organizational Unit: ", "orgunit.page.titleprefix": "Unidad organizativa: ", - - // "pagination.options.description": "Pagination options", "pagination.options.description": "Opciones de paginación", @@ -4691,8 +4647,6 @@ // "pagination.sort-direction": "Sort Options", "pagination.sort-direction": "Opciones de ordenación", - - // "person.listelement.badge": "Person", "person.listelement.badge": "Persona", @@ -4741,8 +4695,6 @@ // "person.search.title": "Person Search", "person.search.title": "Búsqueda de personas", - - // "process.new.select-parameters": "Parameters", "process.new.select-parameters": "Parámetros", @@ -4791,6 +4743,9 @@ // "process.new.notification.error.content": "An error occurred while creating this process", "process.new.notification.error.content": "Se produjo un error al crear este proceso.", + // "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", + "process.new.notification.error.max-upload.content": "El fichero sobrepasa el límte máximo de subida", + // "process.new.header": "Create a new process", "process.new.header": "Crea un nuevo proceso", @@ -4800,18 +4755,16 @@ // "process.new.breadcrumbs": "Create a new process", "process.new.breadcrumbs": "Crea un nuevo proceso", - - - // "process.detail.arguments" : "Arguments", + // "process.detail.arguments": "Arguments", "process.detail.arguments": "Argumentos", - // "process.detail.arguments.empty" : "This process doesn't contain any arguments", + // "process.detail.arguments.empty": "This process doesn't contain any arguments", "process.detail.arguments.empty": "Este proceso no contiene ningún argumento", - // "process.detail.back" : "Back", + // "process.detail.back": "Back", "process.detail.back": "Atrás", - // "process.detail.output" : "Process Output", + // "process.detail.output": "Process Output", "process.detail.output": "Salida del proceso", // "process.detail.logs.button": "Retrieve process output", @@ -4823,28 +4776,29 @@ // "process.detail.logs.none": "This process has no output", "process.detail.logs.none": "Este proceso no tiene salida", - // "process.detail.output-files" : "Output Files", + // "process.detail.output-files": "Output Files", "process.detail.output-files": "Archivos de salida", - // "process.detail.output-files.empty" : "This process doesn't contain any output files", + // "process.detail.output-files.empty": "This process doesn't contain any output files", "process.detail.output-files.empty": "Este proceso no contiene ningún archivo de salida", - // "process.detail.script" : "Script", + // "process.detail.script": "Script", "process.detail.script": "Secuencia de comandos", - // "process.detail.title" : "Process: {{ id }} - {{ name }}", + // "process.detail.title": "Process: {{ id }} - {{ name }}", + "process.detail.title": "Proceso: {{ id }} - {{ name }}", - // "process.detail.start-time" : "Start time", + // "process.detail.start-time": "Start time", "process.detail.start-time": "Hora de inicio", - // "process.detail.end-time" : "Finish time", + // "process.detail.end-time": "Finish time", "process.detail.end-time": "Hora de finalización", - // "process.detail.status" : "Status", + // "process.detail.status": "Status", "process.detail.status": "Estado", - // "process.detail.create" : "Create similar process", + // "process.detail.create": "Create similar process", "process.detail.create": "Crear un proceso similar", // "process.detail.actions": "Actions", @@ -4871,24 +4825,22 @@ // "process.detail.delete.error": "Something went wrong when deleting the process", "process.detail.delete.error": "Algo falló eliminando el proceso", - - - // "process.overview.table.finish" : "Finish time (UTC)", + // "process.overview.table.finish": "Finish time (UTC)", "process.overview.table.finish": "Hora de finalización (UTC)", - // "process.overview.table.id" : "Process ID", + // "process.overview.table.id": "Process ID", "process.overview.table.id": "ID de proceso", - // "process.overview.table.name" : "Name", + // "process.overview.table.name": "Name", "process.overview.table.name": "Nombre", - // "process.overview.table.start" : "Start time (UTC)", + // "process.overview.table.start": "Start time (UTC)", "process.overview.table.start": "Hora de inicio (UTC)", - // "process.overview.table.status" : "Status", + // "process.overview.table.status": "Status", "process.overview.table.status": "Estado", - // "process.overview.table.user" : "User", + // "process.overview.table.user": "User", "process.overview.table.user": "Usuario", // "process.overview.title": "Processes Overview", @@ -4927,8 +4879,6 @@ // "process.bulk.delete.success": "{{count}} process(es) have been succesfully deleted", "process.bulk.delete.success": "{{count}} proceso(s) se han eliminado correctamente", - - // "profile.breadcrumbs": "Update Profile", "profile.breadcrumbs": "Actualización del perfil", @@ -5058,8 +5008,6 @@ // "project-relationships.search.results.head": "Project Search Results", "project-relationships.search.results.head": "Resultados de búsqueda de proyectos", - - // "publication.listelement.badge": "Publication", "publication.listelement.badge": "Publicación", @@ -5093,7 +5041,6 @@ // "publication.search.title": "Publication Search", "publication.search.title": "Búsqueda de publicaciones", - // "media-viewer.next": "Next", "media-viewer.next": "Siguiente", @@ -5103,7 +5050,6 @@ // "media-viewer.playlist": "Playlist", "media-viewer.playlist": "Lista de reproducción", - // "register-email.title": "New user registration", "register-email.title": "Registro de nuevo usuario", @@ -5167,7 +5113,6 @@ // "register-page.create-profile.submit.success.head": "Registration completed", "register-page.create-profile.submit.success.head": "Registro completado", - // "register-page.registration.header": "New user registration", "register-page.registration.header": "Registro de nuevo usuario", @@ -5209,6 +5154,7 @@ // "register-page.registration.google-recaptcha.must-accept-cookies": "In order to register you must accept the <b>Registration and Password recovery</b> (Google reCaptcha) cookies.", "register-page.registration.google-recaptcha.must-accept-cookies": "Para registrarse debe aceptar las cookies de <b>Registro y recuperación de contraseña</b> (Google reCaptcha).", + // "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": "Este correo electrónico no esta en la lista de dominios que pueden registrarse. Los dominios permitidos son {{ domains }}", @@ -5223,6 +5169,7 @@ // "register-page.registration.google-recaptcha.notification.message.expired": "Verification expired. Please verify again.", "register-page.registration.google-recaptcha.notification.message.expired": "Verificación caducada. Verifique de nuevo.", + // "register-page.registration.info.maildomain": "Accounts can be registered for mail addresses of the domains", "register-page.registration.info.maildomain": "Las cuentas pueden registrarse para las direcciones de correo de los dominios", @@ -5289,16 +5236,14 @@ // "relationships.isFundingAgencyOf.OrgUnit": "Funder", "relationships.isFundingAgencyOf.OrgUnit": "Financiador", - // "repository.image.logo": "Repository logo", "repository.image.logo": "Logotipo del repositorio", - // "repository.title.prefix": "DSpace Angular :: ", - "repository.title.prefix": "DSpace Angular :: ", - - // "repository.title.prefixDSpace": "DSpace Angular ::", - "repository.title.prefixDSpace": "DSpace Angular ::", + // "repository.title": "DSpace Repository", + "repository.title": "Repositorio DSpace", + // "repository.title.prefix": "DSpace Repository :: ", + "repository.title.prefix": "Repositorio DSpace :: ", // "resource-policies.add.button": "Add", "resource-policies.add.button": "Agregar", @@ -5471,8 +5416,6 @@ // "resource-policies.table.headers.title.for.collection": "Policies for Collection", "resource-policies.table.headers.title.for.collection": "Políticas para la colección", - - // "search.description": "", "search.description": "", @@ -5488,7 +5431,6 @@ // "search.search-form.placeholder": "Search the repository ...", "search.search-form.placeholder": "Buscar en el repositorio ...", - // "search.filters.applied.f.author": "Author", "search.filters.applied.f.author": "Autor", @@ -5537,8 +5479,6 @@ // "search.filters.applied.f.withdrawn": "Withdrawn", "search.filters.applied.f.withdrawn": "Retirado", - - // "search.filters.filter.author.head": "Author", "search.filters.filter.author.head": "Autor", @@ -5758,8 +5698,6 @@ // "search.filters.filter.supervisedBy.label": "Search Supervised By", "search.filters.filter.supervisedBy.label": "Búsqueda Supervisada Por", - - // "search.filters.entityType.JournalIssue": "Journal Issue", "search.filters.entityType.JournalIssue": "Número de la revista", @@ -5787,7 +5725,6 @@ // "search.filters.withdrawn.false": "No", "search.filters.withdrawn.false": "No", - // "search.filters.head": "Filters", "search.filters.head": "Filtros", @@ -5797,8 +5734,6 @@ // "search.filters.search.submit": "Submit", "search.filters.search.submit": "Enviar", - - // "search.form.search": "Search", "search.form.search": "Buscar", @@ -5808,8 +5743,6 @@ // "search.form.scope.all": "All of DSpace", "search.form.scope.all": "Todo DSpace", - - // "search.results.head": "Search Results", "search.results.head": "Resultados de la búsqueda", @@ -5834,7 +5767,6 @@ // "default-relationships.search.results.head": "Search Results", "default-relationships.search.results.head": "Resultados de la búsqueda", - // "search.sidebar.close": "Back to results", "search.sidebar.close": "Volver a resultados", @@ -5856,8 +5788,6 @@ // "search.sidebar.settings.title": "Settings", "search.sidebar.settings.title": "Ajustes", - - // "search.view-switch.show-detail": "Show detail", "search.view-switch.show-detail": "Mostrar detalle", @@ -5867,8 +5797,6 @@ // "search.view-switch.show-list": "Show as list", "search.view-switch.show-list": "Mostrar como lista", - - // "sorting.ASC": "Ascending", "sorting.ASC": "Ascendente", @@ -5905,7 +5833,6 @@ // "sorting.lastModified.DESC": "Last modified Descending", "sorting.lastModified.DESC": "Última modificación Descendente", - // "statistics.title": "Statistics", "statistics.title": "Estadísticas", @@ -5942,7 +5869,6 @@ // "statistics.table.no-name": "(object name could not be loaded)", "statistics.table.no-name": "(el nombre del objeto no pudo ser cargado)", - // "submission.edit.breadcrumbs": "Edit Submission", "submission.edit.breadcrumbs": "Editar envío", @@ -5952,7 +5878,7 @@ // "submission.general.cancel": "Cancel", "submission.general.cancel": "Cancelar", - // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + // "submission.general.cannot_submit": "You don't have permission to make a new submission.", "submission.general.cannot_submit": "No tiene los permisos para realizar un nuevo envío.", // "submission.general.deposit": "Deposit", @@ -5985,7 +5911,6 @@ // "submission.general.save-later": "Save for later", "submission.general.save-later": "Guardar para más adelante", - // "submission.import-external.page.title": "Import metadata from an external source", "submission.import-external.page.title": "Importar metadatos desde una fuente externa", @@ -6297,6 +6222,7 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Local Journals ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Revistas locales ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Local Projects ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Proyectos locales ({{ count }})", @@ -6320,16 +6246,18 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Local Journal Issues ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Números de revista locales ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Local Journal Issues ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Números de revista locales ({{ count }})", // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Local Journal Volumes ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Volúmenes de revista locales ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Local Journal Volumes ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Volúmenes de revista locales ({{ count }})", // "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Revistas Sherpa ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Revistas Sherpa ({{ count }})", // "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa Publishers ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Editores Sherpa ({{ count }})", @@ -6379,9 +6307,6 @@ // "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Funder of the Project", "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Financiador del Proyecto", - - - // "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Search...", "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Buscar...", @@ -6390,11 +6315,13 @@ // "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Journal Issues", "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Números de revista", + // "submission.sections.describe.relationship-lookup.title.JournalIssue": "Journal Issues", "submission.sections.describe.relationship-lookup.title.JournalIssue": "Números de revista", // "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Journal Volumes", "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Volúmenes de la revista", + // "submission.sections.describe.relationship-lookup.title.JournalVolume": "Journal Volumes", "submission.sections.describe.relationship-lookup.title.JournalVolume": "Volúmenes de la revista", @@ -6406,6 +6333,7 @@ // "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Funding Agency", "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Agencia financiadora", + // "submission.sections.describe.relationship-lookup.title.Project": "Projects", "submission.sections.describe.relationship-lookup.title.Project": "Proyectos", @@ -6453,6 +6381,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Selected Journal Volume", "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Volumen de revista seleccionada", + // "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Selected Projects", "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Proyectos seleccionados", @@ -6476,6 +6405,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Selected Issue", "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Número de revista seleccionados", + // "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Selected Journal Volume", "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Volúmenes de revista seleccionados", @@ -6484,6 +6414,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Selected Funding", "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Financiamientos seleccionados", + // "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Selected Issue", "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Número seleccionado", @@ -6658,7 +6589,6 @@ // "submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information", "submission.sections.submit.progressbar.sherpaPolicies": "Información sobre políticas editoriales de acceso abierto", - // "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": "No se encuentra disponible la información sobre política editorial. Si tiene un ISSN asociado, introdúzcalo arriba para ver información sobre políticas editoriales de acceso abierto.", @@ -6839,10 +6769,9 @@ // "submission.sections.license.required": "You must accept the license", "submission.sections.license.required": "Debe aceptar la licencia", - // "submission.sections.license.notgranted": "You must accept the license", + // "submission.sections.license.notgranted": "You must accept the license", "submission.sections.license.notgranted": "Debe aceptar la licencia", - // "submission.sections.sherpa.publication.information": "Publication information", "submission.sections.sherpa.publication.information": "Información de la Publicación", @@ -6868,7 +6797,7 @@ "submission.sections.sherpa.publisher.policy": "Política editorial", // "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": "La siguiente informacióm se encontró via Sherpa Romeo. En base a esas políticas, se proporcionan consejos sobre las necesidad de un embargo y de aquellos ficheros que puede utilizar. Si tiene dudas, por favor, contacte con el administrador del repositorio mediante el formulario de sugerencias.", + "submission.sections.sherpa.publisher.policy.description": "La siguiente informacióm se encontró vía Sherpa Romeo. En base a esas políticas, se proporcionan consejos sobre las necesidad de un embargo y de aquellos ficheros que puede utilizar. Si tiene dudas, por favor, contacte con el administrador del repositorio mediante el formulario de sugerencias.", // "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": "Los caminos hacia el Acceso Abierto que esta revista permite se relacionan, por versión de artículo, abajo. Pulse en un camino para una visión mas detallada", @@ -6921,16 +6850,12 @@ // "submission.sections.sherpa.error.message": "There was an error retrieving sherpa informations", "submission.sections.sherpa.error.message": "Hubo un error recuperando la información de Sherpa", - - // "submission.submit.breadcrumbs": "New submission", "submission.submit.breadcrumbs": "Nuevo envío", // "submission.submit.title": "New submission", "submission.submit.title": "Nuevo envío", - - // "submission.workflow.generic.delete": "Delete", "submission.workflow.generic.delete": "Eliminar", @@ -6949,21 +6874,18 @@ // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", "submission.workflow.generic.view-help": "Seleccione esta opción para ver los metadatos del ítem.", - // "submission.workflow.generic.submit_select_reviewer": "Select Reviewer", "submission.workflow.generic.submit_select_reviewer": "Seleccionar revisor", // "submission.workflow.generic.submit_select_reviewer-help": "", "submission.workflow.generic.submit_select_reviewer-help": "", - // "submission.workflow.generic.submit_score": "Rate", "submission.workflow.generic.submit_score": "Evaluar", // "submission.workflow.generic.submit_score-help": "", "submission.workflow.generic.submit_score-help": "", - // "submission.workflow.tasks.claimed.approve": "Approve", "submission.workflow.tasks.claimed.approve": "Aprobar", @@ -7006,8 +6928,6 @@ // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", "submission.workflow.tasks.claimed.return_help": "Devuelva la tarea al pool para que otro usuario pueda realizarla.", - - // "submission.workflow.tasks.generic.error": "Error occurred during operation...", "submission.workflow.tasks.generic.error": "Ocurrió un error durante la operación...", @@ -7020,8 +6940,6 @@ // "submission.workflow.tasks.generic.success": "Operation successful", "submission.workflow.tasks.generic.success": "Operación exitosa", - - // "submission.workflow.tasks.pool.claim": "Claim", "submission.workflow.tasks.pool.claim": "Asumir tarea", @@ -7034,13 +6952,14 @@ // "submission.workflow.tasks.pool.show-detail": "Show detail", "submission.workflow.tasks.pool.show-detail": "Mostrar detalle", - // "submission.workspace.generic.view": "View", "submission.workspace.generic.view": "Ver", // "submission.workspace.generic.view-help": "Select this option to view the item's metadata.", "submission.workspace.generic.view-help": "Seleccione esta opción para ver los metadatos del ítem.", + // "submitter.empty": "N/A", + "submitter.empty": "N/A", // "subscriptions.title": "Subscriptions", "subscriptions.title": "Suscripciones", @@ -7147,7 +7066,6 @@ // "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.", "subscriptions.table.empty.message": "Usted no tiene suscripciones. Para subscribirse a las actualizaciones por correo electrónico de una Comunidad o Colección, utilice el botón de suscripción en la página del objeto.", - // "thumbnail.default.alt": "Thumbnail Image", "thumbnail.default.alt": "Miniatura", @@ -7172,13 +7090,9 @@ // "thumbnail.person.placeholder": "No Profile Picture Available", "thumbnail.person.placeholder": "No hay imagen de perfil disponible", - - // "title": "DSpace", "title": "DSpace", - - // "vocabulary-treeview.header": "Hierarchical tree view", "vocabulary-treeview.header": "Vista de árbol jerárquico", @@ -7230,8 +7144,6 @@ // "virtual-metadata.delete-relationship.modal-head": "Select the items for which you want to save the virtual metadata as real metadata", "virtual-metadata.delete-relationship.modal-head": "Seleccione los ítems para los que desea guardar los metadatos virtuales como metadatos reales", - - // "supervisedWorkspace.search.results.head": "Supervised Items", "supervisedWorkspace.search.results.head": "Ítems supervisados", @@ -7247,8 +7159,6 @@ // "supervision.search.results.head": "Workflow and Workspace tasks", "supervision.search.results.head": "Tareas del flujo de trabajo y del espacio de trabajo", - - // "workflow-item.edit.breadcrumbs": "Edit workflowitem", "workflow-item.edit.breadcrumbs": "Editar ítem del flujo de trabajo", @@ -7279,7 +7189,6 @@ // "workflow-item.delete.button.confirm": "Delete", "workflow-item.delete.button.confirm": "Borrar", - // "workflow-item.send-back.notification.success.title": "Sent back to submitter", "workflow-item.send-back.notification.success.title": "Devolver al remitente", @@ -7313,11 +7222,33 @@ // "workspace-item.view.title": "Workspace View", "workspace-item.view.title": "Vista del flujo de trabajo", + // "workspace-item.delete.breadcrumbs": "Workspace Delete", + "workspace-item.delete.breadcrumbs": "Borrar espacio de trabajo", + + // "workspace-item.delete.header": "Delete workspace item", + "workspace-item.delete.header": "Borrar ítem del espacio de trabajo", + + // "workspace-item.delete.button.confirm": "Delete", + "workspace-item.delete.button.confirm": "Borrar", + + // "workspace-item.delete.button.cancel": "Cancel", + "workspace-item.delete.button.cancel": "Cancelar", + + // "workspace-item.delete.notification.success.title": "Deleted", + "workspace-item.delete.notification.success.title": "Borrado", + + // "workspace-item.delete.title": "This workspace item was successfully deleted", + "workspace-item.delete.title": "Este ítem del espacio de trabajo se eliminó correctamente", + + // "workspace-item.delete.notification.error.title": "Something went wrong", + "workspace-item.delete.notification.error.title": "Algo salió mal", + + // "workspace-item.delete.notification.error.content": "The workspace item could not be deleted", + "workspace-item.delete.notification.error.content": "Este ítem del espacio de trabajo no pudo borrarse", // "workflow-item.advanced.title": "Advanced workflow", "workflow-item.advanced.title": "Flujo de trabajo avanzado", - // "workflow-item.selectrevieweraction.notification.success.title": "Selected reviewer", "workflow-item.selectrevieweraction.notification.success.title": "Revisor seleccionado", @@ -7342,7 +7273,6 @@ // "workflow-item.selectrevieweraction.button.confirm": "Confirm", "workflow-item.selectrevieweraction.button.confirm": "Confirmar", - // "workflow-item.scorereviewaction.notification.success.title": "Rating review", "workflow-item.scorereviewaction.notification.success.title": "Revisión de evaluación", @@ -7379,7 +7309,7 @@ // "idle-modal.extend-session": "Extend session", "idle-modal.extend-session": "Prolongar la sesión", - // "researcher.profile.action.processing" : "Processing...", + // "researcher.profile.action.processing": "Processing...", "researcher.profile.action.processing": "Procesando...", // "researcher.profile.associated": "Researcher profile associated", @@ -7412,10 +7342,10 @@ // "researcher.profile.view": "View", "researcher.profile.view": "Ver", - // "researcher.profile.private.visibility" : "PRIVATE", + // "researcher.profile.private.visibility": "PRIVATE", "researcher.profile.private.visibility": "PRIVADO", - // "researcher.profile.public.visibility" : "PUBLIC", + // "researcher.profile.public.visibility": "PUBLIC", "researcher.profile.public.visibility": "PÚBLICO", // "researcher.profile.status": "Status:", @@ -7424,16 +7354,16 @@ // "researcherprofile.claim.not-authorized": "You are not authorized to claim this item. For more details contact the administrator(s).", "researcherprofile.claim.not-authorized": "No está autorizado pare reclamar este ítem. Contacte con el administrador para mas detalles.", - // "researcherprofile.error.claim.body" : "An error occurred while claiming the profile, please try again later", + // "researcherprofile.error.claim.body": "An error occurred while claiming the profile, please try again later", "researcherprofile.error.claim.body": "Hubo un error reclamando el perfil, por favor, inténtelo mas tarde", - // "researcherprofile.error.claim.title" : "Error", + // "researcherprofile.error.claim.title": "Error", "researcherprofile.error.claim.title": "Error", - // "researcherprofile.success.claim.body" : "Profile claimed with success", + // "researcherprofile.success.claim.body": "Profile claimed with success", "researcherprofile.success.claim.body": "Perfil reclamado con éxito", - // "researcherprofile.success.claim.title" : "Success", + // "researcherprofile.success.claim.title": "Success", "researcherprofile.success.claim.title": "Éxito", // "person.page.orcid.create": "Create an ORCID ID", @@ -7442,7 +7372,7 @@ // "person.page.orcid.granted-authorizations": "Granted authorizations", "person.page.orcid.granted-authorizations": "Autorizaciones concedidas", - // "person.page.orcid.grant-authorizations" : "Grant authorizations", + // "person.page.orcid.grant-authorizations": "Grant authorizations", "person.page.orcid.grant-authorizations": "Conceder autorizaciones", // "person.page.orcid.link": "Connect to ORCID ID", @@ -7458,7 +7388,7 @@ "person.page.orcid.orcid-not-linked-message": "El ORCID iD de este perfil ({{ orcid }}) no se ha conectado aún con una cuenta en el registro ORCID o la conexión caducó.", // "person.page.orcid.unlink": "Disconnect from ORCID", - "person.page.orcid.unlink": "Desconectar de ORCID", + "person.page.orcid.unlink": "Desconectar de ORCID", // "person.page.orcid.unlink.processing": "Processing...", "person.page.orcid.unlink.processing": "Procesando...", @@ -7490,44 +7420,44 @@ // "person.page.orcid.save.preference.changes": "Update settings", "person.page.orcid.save.preference.changes": "Actualizar configuración", - // "person.page.orcid.sync-profile.affiliation" : "Affiliation", + // "person.page.orcid.sync-profile.affiliation": "Affiliation", "person.page.orcid.sync-profile.affiliation": "Afiliación", - // "person.page.orcid.sync-profile.biographical" : "Biographical data", + // "person.page.orcid.sync-profile.biographical": "Biographical data", "person.page.orcid.sync-profile.biographical": "Biografía", - // "person.page.orcid.sync-profile.education" : "Education", + // "person.page.orcid.sync-profile.education": "Education", "person.page.orcid.sync-profile.education": "Grados", - // "person.page.orcid.sync-profile.identifiers" : "Identifiers", + // "person.page.orcid.sync-profile.identifiers": "Identifiers", "person.page.orcid.sync-profile.identifiers": "Identificadores", - // "person.page.orcid.sync-fundings.all" : "All fundings", + // "person.page.orcid.sync-fundings.all": "All fundings", "person.page.orcid.sync-fundings.all": "Todas las financiaciones", - // "person.page.orcid.sync-fundings.mine" : "My fundings", + // "person.page.orcid.sync-fundings.mine": "My fundings", "person.page.orcid.sync-fundings.mine": "Mi financiación", - // "person.page.orcid.sync-fundings.my_selected" : "Selected fundings", + // "person.page.orcid.sync-fundings.my_selected": "Selected fundings", "person.page.orcid.sync-fundings.my_selected": "Financiaciones seleccionadas", - // "person.page.orcid.sync-fundings.disabled" : "Disabled", + // "person.page.orcid.sync-fundings.disabled": "Disabled", "person.page.orcid.sync-fundings.disabled": "Deshabilitado", - // "person.page.orcid.sync-publications.all" : "All publications", + // "person.page.orcid.sync-publications.all": "All publications", "person.page.orcid.sync-publications.all": "Todas las publicaciones", - // "person.page.orcid.sync-publications.mine" : "My publications", + // "person.page.orcid.sync-publications.mine": "My publications", "person.page.orcid.sync-publications.mine": "Mis publicaciones", - // "person.page.orcid.sync-publications.my_selected" : "Selected publications", + // "person.page.orcid.sync-publications.my_selected": "Selected publications", "person.page.orcid.sync-publications.my_selected": "Publicaciones seleccionadas", - // "person.page.orcid.sync-publications.disabled" : "Disabled", + // "person.page.orcid.sync-publications.disabled": "Disabled", "person.page.orcid.sync-publications.disabled": "Deshabilitado", - // "person.page.orcid.sync-queue.discard" : "Discard the change and do not synchronize with the ORCID registry", - "person.page.orcid.sync-queue.discard": "Deshechar el cambio y no sincronizar con ORCID", + // "person.page.orcid.sync-queue.discard": "Discard the change and do not synchronize with the ORCID registry", + "person.page.orcid.sync-queue.discard": "Deshechar el cambio y no sincronizar con el registro ORCID", // "person.page.orcid.sync-queue.discard.error": "The discarding of the ORCID queue record failed", "person.page.orcid.sync-queue.discard.error": "Falló el borrado del registro ORCID en la cola", @@ -7538,13 +7468,13 @@ // "person.page.orcid.sync-queue.empty-message": "The ORCID queue registry is empty", "person.page.orcid.sync-queue.empty-message": "La cola del registro de ORCID está vacía", - // "person.page.orcid.sync-queue.table.header.type" : "Type", + // "person.page.orcid.sync-queue.table.header.type": "Type", "person.page.orcid.sync-queue.table.header.type": "Tipo", - // "person.page.orcid.sync-queue.table.header.description" : "Description", + // "person.page.orcid.sync-queue.table.header.description": "Description", "person.page.orcid.sync-queue.table.header.description": "Descripción", - // "person.page.orcid.sync-queue.table.header.action" : "Action", + // "person.page.orcid.sync-queue.table.header.action": "Action", "person.page.orcid.sync-queue.table.header.action": "Acción", // "person.page.orcid.sync-queue.description.affiliation": "Affiliations", @@ -7610,7 +7540,7 @@ // "person.page.orcid.sync-queue.tooltip.researcher_urls": "Researcher url", "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL del investigador", - // "person.page.orcid.sync-queue.send" : "Synchronize with ORCID registry", + // "person.page.orcid.sync-queue.send": "Synchronize with ORCID registry", "person.page.orcid.sync-queue.send": "Sincronizar con el registro ORCID", // "person.page.orcid.sync-queue.send.unauthorized-error.title": "The submission to ORCID failed for missing authorizations.", @@ -7620,13 +7550,13 @@ "person.page.orcid.sync-queue.send.unauthorized-error.content": "Pulse <a href='{{orcid}}'>aquí</a> para conceder de nuevo los permisos requeridos. Si el problema continuase, contacte con el administrador", // "person.page.orcid.sync-queue.send.bad-request-error": "The submission to ORCID failed because the resource sent to ORCID registry is not valid", - "person.page.orcid.sync-queue.send.bad-request-error": "El envío a ORCID falló debido a que el recurso que se envión no era válido", + "person.page.orcid.sync-queue.send.bad-request-error": "El envío a ORCID falló debido a que el recurso que se envión no era válido", // "person.page.orcid.sync-queue.send.error": "The submission to ORCID failed", "person.page.orcid.sync-queue.send.error": "Falló el envío a ORCID", // "person.page.orcid.sync-queue.send.conflict-error": "The submission to ORCID failed because the resource is already present on the ORCID registry", - "person.page.orcid.sync-queue.send.conflict-error": "El envío a ORCID falló debido a que el recurso ya existía en el registro ORCID", + "person.page.orcid.sync-queue.send.conflict-error": "El envío a ORCID falló debido a que el recurso ya existía en el registro ORCID", // "person.page.orcid.sync-queue.send.not-found-warning": "The resource does not exists anymore on the ORCID registry.", "person.page.orcid.sync-queue.send.not-found-warning": "El recurso no existe ya en el registro ORCID.", @@ -7664,8 +7594,8 @@ // "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "The organization's name is required", "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Se requiere el nombre de la organización", - // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid" : "The publication date must be one year after 1900", - "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "la fecha de la publicación debe ser posterior a 1900", + // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "The publication date must be one year after 1900", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "La fecha de publicación debe ser posterior a 1900", // "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "The organization to be sent requires an address", "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Se requiere la dirección de la organización", @@ -7698,7 +7628,7 @@ "person.page.orcid.synchronization-mode.label": "Modo sincronización", // "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).", - "person.page.orcid.synchronization-mode-message": "Seleccione cómo prefiere realizar la sincronización con ORCID. Puede escoger \"Manual\" (usted envía los datos a ORCID manualmente), o \"Batch\" (el sistema enviará sus datos a ORCID via un programa planificado).", + "person.page.orcid.synchronization-mode-message": "Seleccione cómo prefiere realizar la sincronización con ORCID. Puede escoger \"Manual\" (usted envía los datos a ORCID manualmente), o \"Batch\" (el sistema enviará sus datos a ORCID vía un programa planificado).", // "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": "Seleccione si enviará información de sus entidades conectadas de tipo Proyecto a la información de financiación de ORCID.", @@ -7744,13 +7674,13 @@ // "person.orcid.registry.auth": "ORCID Authorizations", "person.orcid.registry.auth": "Autorizaciones ORCID", + // "home.recent-submissions.head": "Recent Submissions", "home.recent-submissions.head": "Envíos recientes", // "listable-notification-object.default-message": "This object couldn't be retrieved", "listable-notification-object.default-message": "Este objeto no se pudo recuperar", - // "system-wide-alert-banner.retrieval.error": "Something went wrong retrieving the system-wide alert banner", "system-wide-alert-banner.retrieval.error": "Algo salió mal al recuperar el banner de alerta del sistema", @@ -7766,8 +7696,6 @@ // "system-wide-alert-banner.countdown.minutes": "{{minutes}} minute(s):", "system-wide-alert-banner.countdown.minutes": "{{minutes}} minuto(s):", - - // "menu.section.system-wide-alert": "System-wide Alert", "menu.section.system-wide-alert": "Alerta del Sistema", @@ -7822,5 +7750,81 @@ // "admin.system-wide-alert.title": "System-wide Alerts", "admin.system-wide-alert.title": "Alertas del sistema", + // "item-access-control-title": "This form allows you to perform changes to the access conditions of the item's metadata or its bitstreams.", + "item-access-control-title": "Esta pantalla le permite realizar cambios en las condiciones de acceso a los metadatos o a los archivos del ítem.", + + // "collection-access-control-title": "This form allows you to perform changes to the access conditions of all the items owned by this collection. Changes may be performed to either all Item metadata or all content (bitstreams).", + "collection-access-control-title": "Esta pantalla le permite realizar cambios en las condiciones de acceso de todos los ítems de la colección. Puede realizar los cambios a los metadatos o a los archivos de todos los ítems.", + + // "community-access-control-title": "This form allows you to perform changes to the access conditions of all the items owned by any collection under this community. Changes may be performed to either all Item metadata or all content (bitstreams).", + "community-access-control-title": "Esta pantalla le permite realizar cambios en las condiciones de acceso de todos los ítems de todas las colecciones de esta comunidad. Puede realizar los cambios a los metadatos o a los archivos de todos los ítems.", + + // "access-control-item-header-toggle": "Item's Metadata", + "access-control-item-header-toggle": "Metadatos del ítem", + + // "access-control-bitstream-header-toggle": "Bitstreams", + "access-control-bitstream-header-toggle": "Archivos", + + // "access-control-mode": "Mode", + "access-control-mode": "Modo", + + // "access-control-access-conditions": "Access conditions", + "access-control-access-conditions": "Condiciones de accceso", + + // "access-control-no-access-conditions-warning-message": "Currently, no access conditions are specified below. If executed, this will replace the current access conditions with the default access conditions inherited from the owning collection.", + "access-control-no-access-conditions-warning-message": "No ha especificado condiciones de acceso. Si lo ejecuta, se sustituirán las condiciones actuales con las condiones heredadas de la colección de pertenencia.", + + // "access-control-replace-all": "Replace access conditions", + "access-control-replace-all": "Sustituir condiciones de accceso", + + // "access-control-add-to-existing": "Add to existing ones", + "access-control-add-to-existing": "Añadir a las existentes", + + // "access-control-limit-to-specific": "Limit the changes to specific bitstreams", + "access-control-limit-to-specific": "Limitar los cambios a ficheros específicos", + + // "access-control-process-all-bitstreams": "Update all the bitstreams in the item", + "access-control-process-all-bitstreams": "Actualizar todos los archivos del ítem", + + // "access-control-bitstreams-selected": "bitstreams selected", + "access-control-bitstreams-selected": "archivos seleccionados", + + // "access-control-cancel": "Cancel", + "access-control-cancel": "Cancelar", + + // "access-control-execute": "Execute", + "access-control-execute": "Ejecutar", + + // "access-control-add-more": "Add more", + "access-control-add-more": "Añadir mas", + + // "access-control-select-bitstreams-modal.title": "Select bitstreams", + "access-control-select-bitstreams-modal.title": "Seleccionar archivos", + + // "access-control-select-bitstreams-modal.no-items": "No items to show.", + "access-control-select-bitstreams-modal.no-items": "No hay ítems para mostrar.", + + // "access-control-select-bitstreams-modal.close": "Close", + "access-control-select-bitstreams-modal.close": "Cerrar", + + // "access-control-option-label": "Access condition type", + "access-control-option-label": "Tipo de condición de acceso", + + // "access-control-option-note": "Choose an access condition to apply to selected objects.", + "access-control-option-note": "Seleccione una condición de acceso para aplicar a los objetos seleccionados.", + + // "access-control-option-start-date": "Grant access from", + "access-control-option-start-date": "Establecer acceso desde", + + // "access-control-option-start-date-note": "Select the date from which the related access condition is applied", + "access-control-option-start-date-note": "Escoja la fecha desde la cuál se aplicarán las condiciones de acceso especificadas", + + // "access-control-option-end-date": "Grant access until", + "access-control-option-end-date": "Establecer acceso hasta", + + // "access-control-option-end-date-note": "Select the date until which the related access condition is applied", + "access-control-option-end-date-note": "Escoja la fecha hasta la cuál se aplicarán las condiciones de acceso especificadas", + + } From 1885638ba6fadca4c99043db4ce52646bce435a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Fern=C3=A1ndez=20Celorio?= <sfernandez@arvo.es> Date: Tue, 22 Aug 2023 12:57:08 +0200 Subject: [PATCH 098/282] Some lint errors fixed --- src/assets/i18n/es.json5 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/assets/i18n/es.json5 b/src/assets/i18n/es.json5 index bd393cda853..3fb0ac69af7 100644 --- a/src/assets/i18n/es.json5 +++ b/src/assets/i18n/es.json5 @@ -854,7 +854,7 @@ // "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", "admin.batch-import.page.toggle.help": "Es posible realizar una importación tanto mediante una subida de fichero como a través de una URL. Use el selector de arriba para especificar la fuente de entrada.", - + // "admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import", "admin.metadata-import.page.dropMsg": "Suelta un CSV de metadatos para importar", @@ -2677,7 +2677,7 @@ "grant-request-copy.header": "Conceder solicitud de copia de documento", // "grant-request-copy.intro": "A message will be sent to the applicant of the request. The requested document(s) will be attached.", - "grant-request-copy.intro": "Este mensaje se enviará al solicitante de la copia. Se le anexará una copia del documento.", + "grant-request-copy.intro": "Este mensaje se enviará al solicitante de la copia. Se le anexará una copia del documento.", // "grant-request-copy.success": "Successfully granted item request", "grant-request-copy.success": "Solicitud de ítem concedida exitosamente", @@ -2686,13 +2686,13 @@ "health.breadcrumbs": "Chequeos", // "health-page.heading": "Health", - "health-page.heading": "Chequeos", + "health-page.heading": "Chequeos", // "health-page.info-tab": "Info", - "health-page.info-tab": "Información", + "health-page.info-tab": "Información", // "health-page.status-tab": "Status", - "health-page.status-tab": "Estado", + "health-page.status-tab": "Estado", // "health-page.error.msg": "The health check service is temporarily unavailable", "health-page.error.msg": "El servicio de comprobación no se encuentra temporalmente disponible", @@ -4744,7 +4744,7 @@ "process.new.notification.error.content": "Se produjo un error al crear este proceso.", // "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", - "process.new.notification.error.max-upload.content": "El fichero sobrepasa el límte máximo de subida", + "process.new.notification.error.max-upload.content": "El fichero sobrepasa el límte máximo de subida", // "process.new.header": "Create a new process", "process.new.header": "Crea un nuevo proceso", From b439ab4484d864a4cdcf8c17541cf9d00b62b68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dykas?= <96572102+michdyk@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:32:16 +0200 Subject: [PATCH 099/282] Update pl.json5 Update from 7.4 to 7.6 version --- src/assets/i18n/pl.json5 | 4916 ++++++++++++++++++++------------------ 1 file changed, 2619 insertions(+), 2297 deletions(-) diff --git a/src/assets/i18n/pl.json5 b/src/assets/i18n/pl.json5 index 35126537055..7e6ef92c227 100644 --- a/src/assets/i18n/pl.json5 +++ b/src/assets/i18n/pl.json5 @@ -1,2299 +1,2621 @@ { - "401.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", - "401.link.home-page": "Zabierz mnie na stronę główną", - "401.unauthorized": "nieautoryzowany", - "403.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "403.link.home-page": "Zabierz mnie na stronę główną", - "403.forbidden": "zabroniony", - "404.help": "Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", - "404.link.home-page": "Zabierz mnie na stronę główną", - "404.page-not-found": "strona nie została znaleziona", - "admin.curation-tasks.breadcrumbs": "Systemowe zadania administracyjne", - "admin.curation-tasks.title": "Systemowe zadania administracyjne", - "admin.curation-tasks.header": "Systemowe zadania administracyjne", - "admin.registries.bitstream-formats.breadcrumbs": "Rejestr formatów", - "admin.registries.bitstream-formats.create.breadcrumbs": "Format strumienia bitów", - "admin.registries.bitstream-formats.create.failure.content": "Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", - "admin.registries.bitstream-formats.create.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.create.head": "Utwórz nowy format", - "admin.registries.bitstream-formats.create.new": "Dodaj nowy format", - "admin.registries.bitstream-formats.create.success.content": "Nowy format strumienia bitów został pomyślnie utworzony.", - "admin.registries.bitstream-formats.create.success.head": "Udało się", - "admin.registries.bitstream-formats.delete.failure.amount": "Nie udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.delete.success.amount": "Udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.success.head": "Udało się", - "admin.registries.bitstream-formats.description": "Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", - "admin.registries.bitstream-formats.edit.breadcrumbs": "Format strumienia bitów", - "admin.registries.bitstream-formats.edit.description.hint": "", - "admin.registries.bitstream-formats.edit.description.label": "Opis", - "admin.registries.bitstream-formats.edit.extensions.hint": "Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", - "admin.registries.bitstream-formats.edit.extensions.label": "Rozszerzenia plików", - "admin.registries.bitstream-formats.edit.extensions.placeholder": "Wprowadź rozszerzenie pliku bez kropki", - "admin.registries.bitstream-formats.edit.failure.content": "Wystąpił błąd podczas edycji formatu pliku.", - "admin.registries.bitstream-formats.edit.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.edit.head": "Format plików: {{ format }}", - "admin.registries.bitstream-formats.edit.internal.hint": "Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", - "admin.registries.bitstream-formats.edit.internal.label": "Wewnętrzny", - "admin.registries.bitstream-formats.edit.mimetype.hint": "Typ MIME powiązany z tym formatem, nie musi być unikalny.", - "admin.registries.bitstream-formats.edit.mimetype.label": "Typ MIME", - "admin.registries.bitstream-formats.edit.shortDescription.hint": "Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", - "admin.registries.bitstream-formats.edit.shortDescription.label": "Nazwa", - "admin.registries.bitstream-formats.edit.success.content": "Format strumienia bitów został pomyślnie edytowany.", - "admin.registries.bitstream-formats.edit.success.head": "Udało się", - "admin.registries.bitstream-formats.edit.supportLevel.hint": "Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", - "admin.registries.bitstream-formats.edit.supportLevel.label": "Obsługiwany format", - "admin.registries.bitstream-formats.head": "Rejestr formatów", - "admin.registries.bitstream-formats.no-items": "Brak formatów plików do wyświetlenia.", - "admin.registries.bitstream-formats.table.delete": "Usuń zaznaczone", - "admin.registries.bitstream-formats.table.deselect-all": "Odznacz wszystkie", - "admin.registries.bitstream-formats.table.internal": "wewnętrzne", - "admin.registries.bitstream-formats.table.mimetype": "Typ MIME", - "admin.registries.bitstream-formats.table.name": "Nazwa", - "admin.registries.bitstream-formats.table.return": "Powrót", - "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Znane", - "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Wspierane", - "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Nieznane", - "admin.registries.bitstream-formats.table.supportLevel.head": "Obsługiwany format", - "admin.registries.bitstream-formats.title": "Rejestr formatów plików", - "admin.registries.metadata.breadcrumbs": "Rejestr metadanych", - "admin.registries.metadata.description": "W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", - "admin.registries.metadata.form.create": "Utwórz schemat metadanych", - "admin.registries.metadata.form.edit": "Edytuj schemat metadanych", - "admin.registries.metadata.form.name": "Nazwa", - "admin.registries.metadata.form.namespace": "Nazwa schematu", - "admin.registries.metadata.head": "Rejestr metadanych", - "admin.registries.metadata.schemas.no-items": "Brak rejestrów metadanych do pokazania.", - "admin.registries.metadata.schemas.table.delete": "Usuń zaznaczone", - "admin.registries.metadata.schemas.table.id": "ID", - "admin.registries.metadata.schemas.table.name": "Nazwa", - "admin.registries.metadata.schemas.table.namespace": "Nazwa schematu", - "admin.registries.metadata.title": "Rejestr metadanych", - "admin.registries.schema.breadcrumbs": "Schemat metadanych", - "admin.registries.schema.description": "Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", - "admin.registries.schema.fields.head": "Pola schematu metadanych", - "admin.registries.schema.fields.no-items": "Brak pól metadanych do pokazania.", - "admin.registries.schema.fields.table.delete": "Usuń zaznaczone", - "admin.registries.schema.fields.table.field": "Pole", - "admin.registries.schema.fields.table.scopenote": "Uwagi", - "admin.registries.schema.form.create": "Stwórz pole metadanych", - "admin.registries.schema.form.edit": "Edytuj pole metadanych", - "admin.registries.schema.form.element": "Element", - "admin.registries.schema.form.qualifier": "Kwalifikator", - "admin.registries.schema.form.scopenote": "Uwagi", - "admin.registries.schema.head": "Schemat metadanych", - "admin.registries.schema.notification.created": "Udało się utworzyć schemat metdanych \"{{prefix}}\"", - "admin.registries.schema.notification.deleted.failure": "Nie udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.deleted.success": "Udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.edited": "Udało się edytować schemat metadanych \"{{prefix}}\"", - "admin.registries.schema.notification.failure": "Błąd", - "admin.registries.schema.notification.field.created": "Udało się utworzyć pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.field.deleted.failure": "Nie udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.deleted.success": "Udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.edited": "SUdało się edytować pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.success": "Udało się", - "admin.registries.schema.return": "Powrót", - "admin.registries.schema.title": "Rejestr schematów metadanych", - "admin.access-control.epeople.actions.delete": "Usuń użytkownika", - "admin.access-control.epeople.actions.impersonate": "Personifikuj użytkownika", - "admin.access-control.epeople.actions.reset": "Zresetuj hasło", - "admin.access-control.epeople.actions.stop-impersonating": "Przestań personifikować użytkownika", - "admin.access-control.epeople.breadcrumbs": "Użytkownicy", - "admin.access-control.epeople.title": "Użytkownicy", - "admin.access-control.epeople.head": "Użytkownicy", - "admin.access-control.epeople.search.head": "Wyszukaj", - "admin.access-control.epeople.button.see-all": "Przeglądaj wszystko", - "admin.access-control.epeople.search.scope.metadata": "Metadane", - "admin.access-control.epeople.search.scope.email": "E-mail", - "admin.access-control.epeople.search.button": "Wyszukaj", - "admin.access-control.epeople.search.placeholder": "Wyszukaj użytkownika...", - "admin.access-control.epeople.button.add": "Dodaj użytkownika", - "admin.access-control.epeople.table.id": "ID", - "admin.access-control.epeople.table.name": "Nazwa", - "admin.access-control.epeople.table.email": "E-mail", - "admin.access-control.epeople.table.edit": "Edytuj", - "admin.access-control.epeople.table.edit.buttons.edit": "Edytuj \"{{name}}\"", - "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Brak uprawnień do edycji wybranej grupy", - "admin.access-control.epeople.table.edit.buttons.remove": "Usuń \"{{name}}\"", - "admin.access-control.epeople.no-items": "Brak użytkowników do wyświetlenia.", - "admin.access-control.epeople.form.create": "Utwórz użytkownika", - "admin.access-control.epeople.form.edit": "Edytuj użytkownika", - "admin.access-control.epeople.form.firstName": "Imię", - "admin.access-control.epeople.form.lastName": "Nazwisko", - "admin.access-control.epeople.form.email": "E-mail", - "admin.access-control.epeople.form.emailHint": "Adres e-mail musi być poprawny", - "admin.access-control.epeople.form.canLogIn": "Możliwość zalogowania", - "admin.access-control.epeople.form.requireCertificate": "Wymagany certyfikat", - "admin.access-control.epeople.form.return": "Powrót", - "admin.access-control.epeople.form.notification.created.success": "Udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure": "Nie udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.success": "Udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.edited.failure": "Nie udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.success": "Udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.failure": "Nie udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Członek grup:", - "admin.access-control.epeople.form.table.id": "ID", - "admin.access-control.epeople.form.table.name": "Nazwa", - "admin.access-control.epeople.form.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.epeople.form.memberOfNoGroups": "Ten użytkownik nie jest członkiem żadnej grupy", - "admin.access-control.epeople.form.goToGroups": "Dodaj do grup", - "admin.access-control.epeople.notification.deleted.failure": "Nie udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.epeople.notification.deleted.success": "Udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.groups.title": "Grupy", - "admin.access-control.groups.breadcrumbs": "Grupy", - "admin.access-control.groups.singleGroup.breadcrumbs": "Edytuj grupę", - "admin.access-control.groups.title.singleGroup": "Edytuj grupę", - "admin.access-control.groups.title.addGroup": "Nowa grupa", - "admin.access-control.groups.addGroup.breadcrumbs": "Nowa grupa", - "admin.access-control.groups.head": "Grupy/role", - "admin.access-control.groups.button.add": "Dodaj grupę", - "admin.access-control.groups.search.head": "Szukaj grup", - "admin.access-control.groups.button.see-all": "Przeszukaj wszystko", - "admin.access-control.groups.search.button": "Wyszukaj", - "admin.access-control.groups.search.placeholder": "Wyszukaj grupy...", - "admin.access-control.groups.table.id": "ID", - "admin.access-control.groups.table.name": "Nazwa", - "admin.access-control.groups.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.groups.table.members": "Członkowie", - "admin.access-control.groups.table.edit": "Edytuj", - "admin.access-control.groups.table.edit.buttons.edit": "Edytuj \"{{name}}\"", - "admin.access-control.groups.no-items": "Nie znaleziono grup z podaną frazą lub podanym UUID", - "admin.access-control.groups.notification.deleted.success": "Udało się usunąć grupę \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.content": "Powód: \"{{cause}}\"", - "admin.access-control.groups.form.alert.permanent": "Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", - "admin.access-control.groups.form.alert.workflowGroup": "Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", - "admin.access-control.groups.form.head.create": "Utwórz grupę", - "admin.access-control.groups.form.head.edit": "Edytuj grupę", - "admin.access-control.groups.form.groupName": "Nazwa grupy", - "admin.access-control.groups.form.groupCommunity": "Zbiór lub kolekcja", - "admin.access-control.groups.form.groupDescription": "Opis", - "admin.access-control.groups.form.notification.created.success": "Udało się utworzyć grupę \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure": "Nie udało się utworzyć grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", - "admin.access-control.groups.form.notification.edited.failure": "Nie udało się edytować grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Nazwa \"{{name}}\" już w użyciu!", - "admin.access-control.groups.form.notification.edited.success": "Udało się edytować grupę \"{{name}}\"", - "admin.access-control.groups.form.actions.delete": "Usuń grupę", - "admin.access-control.groups.form.delete-group.modal.header": "Usuń grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.info": "Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.cancel": "Anuluj", - "admin.access-control.groups.form.delete-group.modal.confirm": "Usuń", - "admin.access-control.groups.form.notification.deleted.success": "Udało się usunąć grupę \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.content": "Powód: \"{{ cause }}\"", - "admin.access-control.groups.form.members-list.head": "Użytkownik", - "admin.access-control.groups.form.members-list.search.head": "Dodaj użytkownika", - "admin.access-control.groups.form.members-list.button.see-all": "Pokaż wszystkich", - "admin.access-control.groups.form.members-list.headMembers": "Aktualni członkowie", - "admin.access-control.groups.form.members-list.search.scope.metadata": "Metadane", - "admin.access-control.groups.form.members-list.search.scope.email": "E-mail", - "admin.access-control.groups.form.members-list.search.button": "Wyszukaj", - "admin.access-control.groups.form.members-list.table.id": "ID", - "admin.access-control.groups.form.members-list.table.name": "Nazwa", - "admin.access-control.groups.form.members-list.table.identity": "Tożsamość", - "admin.access-control.groups.form.members-list.table.email": "E-mail", - "admin.access-control.groups.form.members-list.table.netid": "NetID", - "admin.access-control.groups.form.members-list.table.edit": "Usuń / Dodaj", - "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Usuń użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.addMember": "Udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.addMember": "Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Dodaj użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.members-list.no-members-yet": "Brak użytkowników w grupie, wyszukaj ich i dodaj.", - "admin.access-control.groups.form.members-list.no-items": "Nie znaleziono użytkowników podczas wyszukiwania", - "admin.access-control.groups.form.subgroups-list.notification.failure": "Coś poszło nie tak: \"{{cause}}\"", - "admin.access-control.groups.form.subgroups-list.head": "Grupy", - "admin.access-control.groups.form.subgroups-list.search.head": "Dodaj podgrupę", - "admin.access-control.groups.form.subgroups-list.button.see-all": "Przeglądaj wszystkie", - "admin.access-control.groups.form.subgroups-list.headSubgroups": "Aktualne podgrupy", - "admin.access-control.groups.form.subgroups-list.search.button": "Wyszukaj", - "admin.access-control.groups.form.subgroups-list.table.id": "ID", - "admin.access-control.groups.form.subgroups-list.table.name": "Nazwa", - "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.groups.form.subgroups-list.table.edit": "Usuń / Dodaj", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Usuń podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Dodaj podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Aktualna grupa", - "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Udało się dodać podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Nie udało się dodać podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Udało się usunąć podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Nie udało się usunąć podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ta grupa jest już stworzona i nie może zostać dodana pononwie.", - "admin.access-control.groups.form.subgroups-list.no-items": "Nie znaleziono grup z tą nazwą lub UUID", - "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Brak podgrup w grupie.", - "admin.access-control.groups.form.return": "Powrót", - "admin.search.breadcrumbs": "Wyszukiwanie administracyjne", - "admin.search.collection.edit": "Edytuj", - "admin.search.community.edit": "Edytuj", - "admin.search.item.delete": "Usuń", - "admin.search.item.edit": "Edytuj", - "admin.search.item.make-private": "Ukryj", - "admin.search.item.make-public": "Upublicznij", - "admin.search.item.move": "Przenieś", - "admin.search.item.reinstate": "Zmień instancję", - "admin.search.item.withdraw": "Wycofane", - "admin.search.title": "Wyszukiwanie administracyjne", - "administrativeView.search.results.head": "Wyszukiwanie administracyjne", - "admin.workflow.breadcrumbs": "Zarządzaj procesem", - "admin.workflow.title": "Zarządzaj procesem", - "admin.workflow.item.workflow": "Proces", - "admin.workflow.item.delete": "Usuń", - "admin.workflow.item.send-back": "Odeślij z powrotem", - "admin.metadata-import.breadcrumbs": "Importuj metadane", - "admin.metadata-import.title": "Importuj metadane", - "admin.metadata-import.page.header": "Importuj metadane", - "admin.metadata-import.page.help": "Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", - "admin.metadata-import.page.dropMsg": "Upuść plik w formacie CSV", - "admin.metadata-import.page.dropMsgReplace": "Upuść, aby zastąpić metadane w formacie CSV do importu", - "admin.metadata-import.page.button.return": "Powrót", - "admin.metadata-import.page.button.proceed": "Zastosuj", - "admin.metadata-import.page.error.addFile": "Najpierw wybierz plik!", - "auth.errors.invalid-user": "Niewłaściwy adres e-mail lub hasło.", - "auth.messages.expired": "Twoja sesja wygasła. Zaloguj się ponownie.", - "auth.messages.token-refresh-failed": "Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", - "bitstream.download.page": "Pobieranie {{bitstream}}...", - "bitstream.download.page.back": "Powrót", - "bitstream.edit.authorizations.link": "Edytuj polityki plików", - "bitstream.edit.authorizations.title": "Edytuj polityki plików", - "bitstream.edit.return": "Powrót", - "bitstream.edit.bitstream": "Pliki: ", - "bitstream.edit.form.description.hint": "Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", - "bitstream.edit.form.description.label": "Opis", - "bitstream.edit.form.embargo.hint": "Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", - "bitstream.edit.form.embargo.label": "Embargo do wybranej daty", - "bitstream.edit.form.fileName.hint": "Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", - "bitstream.edit.form.fileName.label": "Nazwa pliku", - "bitstream.edit.form.newFormat.label": "Opisz nowy format", - "bitstream.edit.form.newFormat.hint": "Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", - "bitstream.edit.form.primaryBitstream.label": "Pierwotny plik", - "bitstream.edit.form.selectedFormat.hint": "Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", - "bitstream.edit.form.selectedFormat.label": "Wybrany format", - "bitstream.edit.form.selectedFormat.unknown": "Tego formatu nie ma na liście", - "bitstream.edit.notifications.error.format.title": "Wystąpił błąd podczas zapisu formatu pliku", - "bitstream.edit.notifications.saved.content": "Zmiany w pliku zostały zapisane.", - "bitstream.edit.notifications.saved.title": "Plik został zapisany", - "bitstream.edit.title": "Edytuj plik", - "bitstream-request-a-copy.alert.canDownload1": "Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", - "bitstream-request-a-copy.alert.canDownload2": "tutaj", - "bitstream-request-a-copy.header": "Wystąp o kopię wybranego pliku", - "bitstream-request-a-copy.intro": "Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", - "bitstream-request-a-copy.intro.bitstream.one": "Wystąpienie o dostęp do następujących plików: ", - "bitstream-request-a-copy.intro.bitstream.all": "Wystąpienie o dostęp do wszystkich plików. ", - "bitstream-request-a-copy.name.label": "Imię *", - "bitstream-request-a-copy.name.error": "Imię jest wymagane", - "bitstream-request-a-copy.email.label": "Adres e-mail *", - "bitstream-request-a-copy.email.hint": "Plik zostanie przesłany na podany adres e-mail", - "bitstream-request-a-copy.email.error": "Proszę wprowadzić prawidłowy adres e-mail", - "bitstream-request-a-copy.allfiles.label": "Pliki", - "bitstream-request-a-copy.files-all-false.label": "Tylko plik, dla którego wystąpiono o dostęp", - "bitstream-request-a-copy.files-all-true.label": "Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", - "bitstream-request-a-copy.message.label": "Wiadomość", - "bitstream-request-a-copy.return": "Powrót", - "bitstream-request-a-copy.submit": "Wystąp o kopię", - "bitstream-request-a-copy.submit.success": "Wystąpienie o dostęp do pliku zostało przesłane.", - "bitstream-request-a-copy.submit.error": "Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", - "browse.comcol.by.author": "wg autorów", - "browse.comcol.by.dateissued": "wg daty wydania", - "browse.comcol.by.subject": "wg tematu", - "browse.comcol.by.title": "wg tytułu", - "browse.comcol.head": "Przeglądaj", - "browse.empty": "Brak rekordów do wyświetlenia.", - "browse.metadata.author": "Autor", - "browse.metadata.dateissued": "Data wydania", - "browse.metadata.subject": "Temat", - "browse.metadata.title": "Tytuł", - "browse.metadata.author.breadcrumbs": "Przeglądaj wg autorów", - "browse.metadata.dateissued.breadcrumbs": "Przeglądaj wg daty wydania", - "browse.metadata.subject.breadcrumbs": "Przeglądaj wg tematów", - "browse.metadata.title.breadcrumbs": "Przeglądaj wg tytułów", - "browse.startsWith.choose_start": "(Wybierz start)", - "browse.startsWith.choose_year": "(Wybierz rok)", - "browse.startsWith.choose_year.label": "Wybierz rok wydania", - "browse.startsWith.jump": "Przejdź do miejsca w indeksie:", - "browse.startsWith.months.april": "kwiecień", - "browse.startsWith.months.august": "sierpień", - "browse.startsWith.months.december": "grudzień", - "browse.startsWith.months.february": "luty", - "browse.startsWith.months.january": "styczeń", - "browse.startsWith.months.july": "lipiec", - "browse.startsWith.months.june": "czerwiec", - "browse.startsWith.months.march": "marzec", - "browse.startsWith.months.may": "maj", - "browse.startsWith.months.none": "(wybierz miesiąc)", - "browse.startsWith.months.none.label": "Wybierz miesiąc wydania", - "browse.startsWith.months.november": "listopad", - "browse.startsWith.months.october": "październik", - "browse.startsWith.months.september": "wrzesień", - "browse.startsWith.submit": "Zastosuj", - "browse.startsWith.type_date": "Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", - "browse.startsWith.type_date.label": "Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", - "browse.startsWith.type_text": "Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", - "browse.title": "Przeglądaj {{ collection }} wg {{ field }} {{ value }}", - "chips.remove": "Usuń chip", - "collection.create.head": "Utwórz kolekcję", - "collection.create.notifications.success": "Udało się utworzyć kolekcję", - "collection.create.sub-head": "Udało się utworzyć kolekcję dla zbioru {{ parent }}", - "collection.curate.header": "Administrator kolekcji: {{collection}}", - "collection.delete.cancel": "Anuluj", - "collection.delete.confirm": "Zatwierdź", - "collection.delete.processing": "Usuwanie", - "collection.delete.head": "Usuń kolekcję", - "collection.delete.notification.fail": "Kolekcja nie może być usunięt", - "collection.delete.notification.success": "Udało się usunąć kolekcję", - "collection.delete.text": "Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", - "collection.edit.delete": "Usuń kolekcję", - "collection.edit.head": "Edytuj kolekcję", - "collection.edit.breadcrumbs": "Edytuj kolekcję", - "collection.edit.tabs.mapper.head": "Item Mapper", - "collection.edit.tabs.item-mapper.title": "Edytuj kolekcję - Item Mapper", - "collection.edit.item-mapper.cancel": "Anuluj", - "collection.edit.item-mapper.collection": "Kolekcja: \"<b>{{name}}</b>\"", - "collection.edit.item-mapper.confirm": "Mapuj wybrane elementy", - "collection.edit.item-mapper.description": "To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", - "collection.edit.item-mapper.head": "Item Mapper - Mapuj pozycje z innych kolekcji", - "collection.edit.item-mapper.no-search": "Wpisz co chcesz wyszukać", - "collection.edit.item-mapper.notifications.map.error.content": "Wystąpiły błędy podczas mapowania {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.error.head": "Mapowanie błędów", - "collection.edit.item-mapper.notifications.map.success.content": "Udało się zmapować {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.success.head": "Mapowanie zakończone", - "collection.edit.item-mapper.notifications.unmap.error.content": "Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.error.head": "Usuń błędy mapowania", - "collection.edit.item-mapper.notifications.unmap.success.content": "Udało się usunąć błędy mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.success.head": "Usuwanie mapowania zakończone", - "collection.edit.item-mapper.remove": "Usuń wybrane mapowanie elementów", - "collection.edit.item-mapper.search-form.placeholder": "Wyszukaj pozycje...", - "collection.edit.item-mapper.tabs.browse": "Wyszukaj mapowane elementy", - "collection.edit.item-mapper.tabs.map": "Mapuj nowe elementy", - "collection.edit.logo.delete.title": "Usuń", - "collection.edit.logo.delete-undo.title": "Cofnij usunięcie", - "collection.edit.logo.label": "Logo kolekcji", - "collection.edit.logo.notifications.add.error": "Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", - "collection.edit.logo.notifications.add.success": "Udało się przesłać logo kolekcji.", - "collection.edit.logo.notifications.delete.success.title": "Logo usunięte", - "collection.edit.logo.notifications.delete.success.content": "Udało się usunąć logo kolekcji", - "collection.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", - "collection.edit.logo.upload": "Upuść logo kolekcji, aby je wgrać", - "collection.edit.notifications.success": "Udało się edytować kolekcję", - "collection.edit.return": "Powrót", - "collection.edit.tabs.curate.head": "Kurator", - "collection.edit.tabs.curate.title": "Edytowanie kolekcji - kurator", - "collection.edit.tabs.authorizations.head": "Autoryzacje", - "collection.edit.tabs.authorizations.title": "Edytowanie kolekcji - autoryzacje", - "collection.edit.tabs.metadata.head": "Edytuj metadane", - "collection.edit.tabs.metadata.title": "Edytowanie kolekcji - metadane", - "collection.edit.tabs.roles.head": "Przypisz role", - "collection.edit.tabs.roles.title": "Edytowanie kolekcji - role", - "collection.edit.tabs.source.external": "Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", - "collection.edit.tabs.source.form.errors.oaiSource.required": "Musisz wskazać id docelowej kolekcji.", - "collection.edit.tabs.source.form.harvestType": "Odczytywanie zawartości", - "collection.edit.tabs.source.form.head": "Skonfiguruj zewnętrzne źródło", - "collection.edit.tabs.source.form.metadataConfigId": "Format metadanych", - "collection.edit.tabs.source.form.oaiSetId": "Określony zestaw ID OAI", - "collection.edit.tabs.source.form.oaiSource": "Dostawca OAI", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Odczytaj metadane i pliki (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Odczytaj tylko metadane", - "collection.edit.tabs.source.head": "Źródło treści", - "collection.edit.tabs.source.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", - "collection.edit.tabs.source.notifications.discarded.title": "Zmiany odrzucone", - "collection.edit.tabs.source.notifications.invalid.content": "Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", - "collection.edit.tabs.source.notifications.invalid.title": "Nieprawidłowe metadane", - "collection.edit.tabs.source.notifications.saved.content": "Zmiany wprowadzone w kolekcji zostały zapisane.", - "collection.edit.tabs.source.notifications.saved.title": "Źródło treści zapisane", - "collection.edit.tabs.source.title": "Collection Edit - Źródło treści", - "collection.edit.template.add-button": "Dodaj", - "collection.edit.template.breadcrumbs": "Szablon pozycji", - "collection.edit.template.cancel": "Anuluj", - "collection.edit.template.delete-button": "Usuń", - "collection.edit.template.edit-button": "Edytuj", - "collection.edit.template.error": "Wystąpił błąd podczas odzyskiwania szablonu pozycji", - "collection.edit.template.head": "Edytuj szablon dla kolekcji \"{{ collection }}\"", - "collection.edit.template.label": "Szablon pozycji", - "collection.edit.template.loading": "ładowanie szablonu pozycji...", - "collection.edit.template.notifications.delete.error": "Nie udało się usunąć szablonu pozycji", - "collection.edit.template.notifications.delete.success": "Udało się usunąć szablon pozycji", - "collection.edit.template.title": "Edytuj szablon pozycji", - "collection.form.abstract": "Opis skrócony", - "collection.form.description": "Tekst powitalny (HTML)", - "collection.form.errors.title.required": "Wpisz nazwę kolekcji", - "collection.form.license": "Licencja", - "collection.form.provenance": "Pochodzenie", - "collection.form.rights": "Tekst praw autorskich (HTML)", - "collection.form.tableofcontents": "Wiadomości (HTML)", - "collection.form.title": "Nazwa", - "collection.form.entityType": "Typ danych", - "collection.page.browse.recent.head": "Ostatnie zgłoszenia", - "collection.page.browse.recent.empty": "Brak pozycji do wyświetlenia", - "collection.page.edit": "Edytuj kolekcję", - "collection.page.handle": "Stały URI dla kolekcji", - "collection.page.license": "Licencja", - "collection.page.news": "Wiadomości", - "collection.select.confirm": "Zaakceptuj zaznaczone", - "collection.select.empty": "Brak kolekcji do wyświetlenia", - "collection.select.table.title": "Tytuł", - "collection.source.controls.head": "Kontrolki odczytywania", - "collection.source.controls.test.submit.error": "Coś poszło nie tak podczas rozpoczynania testów ustawień", - "collection.source.controls.test.failed": "Scenariusz testowy ustawień nie zadziałał", - "collection.source.controls.test.completed": "Scenariusz testowy ustawień został zakończony", - "collection.source.controls.test.submit": "Konfiguracja testowa", - "collection.source.controls.test.running": "Testowanie konfiguracji...", - "collection.source.controls.import.submit.success": "Import został rozpoczęty", - "collection.source.controls.import.submit.error": "Coś poszło nie tak podczas rozpoczynania importu", - "collection.source.controls.import.submit": "Importuj teraz", - "collection.source.controls.import.running": "Importowanie...", - "collection.source.controls.import.failed": "Wystąpił błąd podczas importu", - "collection.source.controls.import.completed": "Import zakończony", - "collection.source.controls.reset.submit.success": "Reset ustawień i powtórny import zostały rozpoczęte poprawnie", - "collection.source.controls.reset.submit.error": "Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", - "collection.source.controls.reset.failed": "Wystąpił błąd podczas resetowania ustawień i ponownego importu", - "collection.source.controls.reset.completed": "Reset ustawień i powtórny import zostały zakończone", - "collection.source.controls.reset.submit": "Resetowanie i powtórny import", - "collection.source.controls.reset.running": "Resetowanie i powtórny import...", - "collection.source.controls.harvest.status": "Status odczytywania:", - "collection.source.controls.harvest.start": "Czas rozpoczęcia odczytywania:", - "collection.source.controls.harvest.last": "Czas ostatniego odczytywania:", - "collection.source.controls.harvest.message": "Informacje nt. odczytywania:", - "collection.source.controls.harvest.no-information": "bd.", - "collection.source.update.notifications.error.content": "Te ustawienia zostały przetestowane i nie działają.", - "collection.source.update.notifications.error.title": "Błąd serwera", - "communityList.breadcrumbs": "Lista zbiorów", - "communityList.tabTitle": "Lista zbiorów", - "communityList.title": "Lista zbiorów", - "communityList.showMore": "Pokaż więcej", - "community.create.head": "Utwórz zbiór", - "community.create.notifications.success": "Udało się utworzyć zbiór", - "community.create.sub-head": "Utwórz podzbiór dla zbioru {{ parent }}", - "community.curate.header": "Zarządzaj zbiorem: {{community}}", - "community.delete.cancel": "Anuluj", - "community.delete.confirm": "Potwierdź", - "community.delete.processing": "Usuwanie...", - "community.delete.head": "Usuń zbiór", - "community.delete.notification.fail": "Zbiór nie może być usunięty", - "community.delete.notification.success": "Udało się usunąć zbiór", - "community.delete.text": "Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", - "community.edit.delete": "Usuń ten zbiór", - "community.edit.head": "Edytuj zbiór", - "community.edit.breadcrumbs": "Edytuj zbiór", - "community.edit.logo.delete.title": "Usuń logo", - "community.edit.logo.delete-undo.title": "Cofnij usunięcie", - "community.edit.logo.label": "Logo zbioru", - "community.edit.logo.notifications.add.error": "Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", - "community.edit.logo.notifications.add.success": "Przesłanie loga powiodło się.", - "community.edit.logo.notifications.delete.success.title": "Logo usunięte", - "community.edit.logo.notifications.delete.success.content": "Usunięcie loga zbioru powiodło się", - "community.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", - "community.edit.logo.upload": "Upuść logo zbioru, aby je przesłać", - "community.edit.notifications.success": "Udało się edytować zbiór", - "community.edit.notifications.unauthorized": "Nie masz uprawnień, aby wykonać te zmiany", - "community.edit.notifications.error": "Wystąpił błąd podczas edycji zbioru", - "community.edit.return": "Cofnij", - "community.edit.tabs.curate.head": "Administruj", - "community.edit.tabs.curate.title": "Edycja zbioru - administrator", - "community.edit.tabs.metadata.head": "Edytuj metadane", - "community.edit.tabs.metadata.title": "Edycja zbioru - metadane", - "community.edit.tabs.roles.head": "Przypisz role", - "community.edit.tabs.roles.title": "Edycja zbioru - role", - "community.edit.tabs.authorizations.head": "Uprawnienia", - "community.edit.tabs.authorizations.title": "Edycja zbioru - uprawnienia", - "community.listelement.badge": "Zbiór", - "comcol-role.edit.no-group": "Brak", - "comcol-role.edit.create": "Utwórz", - "comcol-role.edit.restrict": "Ogranicz", - "comcol-role.edit.delete": "Usuń", - "comcol-role.edit.community-admin.name": "Administratorzy", - "comcol-role.edit.collection-admin.name": "Administratorzy", - "comcol-role.edit.community-admin.description": "Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", - "comcol-role.edit.collection-admin.description": "Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", - "comcol-role.edit.submitters.name": "Zgłaszający", - "comcol-role.edit.submitters.description": "Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", - "comcol-role.edit.item_read.name": "Domyślny dostęp do odczytu pozycji", - "comcol-role.edit.item_read.description": "Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", - "comcol-role.edit.item_read.anonymous-group": "Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", - "comcol-role.edit.bitstream_read.name": "Domyślny dostęp do oczytu plików", - "comcol-role.edit.bitstream_read.description": "Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", - "comcol-role.edit.bitstream_read.anonymous-group": "Domyślny status odczytu dla nowych plików to Anonimowy.", - "comcol-role.edit.editor.name": "Redaktorzy", - "comcol-role.edit.editor.description": "Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", - "comcol-role.edit.finaleditor.name": "Redaktorzy końcowi", - "comcol-role.edit.finaleditor.description": "Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", - "comcol-role.edit.reviewer.name": "Recenzenci", - "comcol-role.edit.reviewer.description": "Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", - "community.form.abstract": "Opis skrócony", - "community.form.description": "Wstęp (HTML)", - "community.form.errors.title.required": "Wprowadź nazwę zbioru", - "community.form.rights": "Prawa autoskie (HTML)", - "community.form.tableofcontents": "Wiadomości (HTML)", - "community.form.title": "Nazwa", - "community.page.edit": "Edytuj ten zbiór", - "community.page.handle": "Stały URI zbioru", - "community.page.license": "Licencja", - "community.page.news": "Wiadomości", - "community.all-lists.head": "Podzbiory i kolekcje", - "community.sub-collection-list.head": "Kolekcje w tym zbiorze", - "community.sub-community-list.head": "Kolekcje w tym zbiorze", - "cookies.consent.accept-all": "Zaakceptuj wszystko", - "cookies.consent.accept-selected": "Zaakceptuj wybrane", - "cookies.consent.app.opt-out.description": "Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", - "cookies.consent.app.opt-out.title": "(możesz ją wyłaczyć)", - "cookies.consent.app.purpose": "cel", - "cookies.consent.app.required.description": "Ta aplikacja jest zawsze wymagana", - "cookies.consent.app.required.title": "(zawsze wymagana)", - "cookies.consent.update": "Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", - "cookies.consent.close": "Zamknij", - "cookies.consent.decline": "Odrzuć", - "cookies.consent.content-notice.description": "Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", - "cookies.consent.content-notice.learnMore": "Dostosuj", - "cookies.consent.content-modal.description": "Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", - "cookies.consent.content-modal.privacy-policy.name": "polityka prywatności", - "cookies.consent.content-modal.privacy-policy.text": "Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", - "cookies.consent.content-modal.title": "Informacje, które zbieramy", - "cookies.consent.app.title.authentication": "Logowanie", - "cookies.consent.app.description.authentication": "Musisz się zalogować", - "cookies.consent.app.title.preferences": "Preferencje", - "cookies.consent.app.description.preferences": "Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.acknowledgement": "Zgody", - "cookies.consent.app.description.acknowledgement": "Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.google-analytics": "Google Analytics", - "cookies.consent.app.description.google-analytics": "Pozwól na śledzenie do celów statystycznych", - "cookies.consent.purpose.functional": "Funkcjonalne", - "cookies.consent.purpose.statistical": "Statystyczne", - "curation-task.task.checklinks.label": "Sprawdź odnośniki w metadanych", - "curation-task.task.noop.label": "NOOP", - "curation-task.task.profileformats.label": "Profil formatów plików", - "curation-task.task.requiredmetadata.label": "Sprawdź poprawność wymaganych metadanych", - "curation-task.task.translate.label": "Microsoft Translator", - "curation-task.task.vscan.label": "Skan antywirusowy", - "curation.form.task-select.label": "Zadanie:", - "curation.form.submit": "Start", - "curation.form.submit.success.head": "Udało się rozpocząć zadanie administratora", - "curation.form.submit.success.content": "Zostaniesz przeniesiony na stronę procesu.", - "curation.form.submit.error.head": "Nie udało się się zakończyć zadania administratora", - "curation.form.submit.error.content": "Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", - "curation.form.handle.label": "Automatyzacja:", - "curation.form.handle.hint": "Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", - "deny-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "deny-request-copy.email.subject": "Wystąp o kopię dokumentu", - "deny-request-copy.error": "Wystąpił błąd", - "deny-request-copy.header": "Odrzuć prośbę o przesłanie kopii dokumentu", - "deny-request-copy.intro": "Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", - "deny-request-copy.success": "Z powodzeniem odrzucono prośbę o udostępnienie pozycji", - "dso.name.untitled": "Brak tytułu", - "dso-selector.claim.item.head": "Wskazówki profilu", - "dso-selector.claim.item.body": "Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", - "dso-selector.claim.item.create-from-scratch": "Utwórz nowy", - "dso-selector.claim.item.not-mine-label": "Żaden nie jest mój", - "dso-selector.create.collection.head": "Nowa kolekcja", - "dso-selector.create.collection.sub-level": "Utwórz nową kolekcję w", - "dso-selector.create.community.head": "Nowy zbiór", - "dso-selector.create.community.sub-level": "Utwórz nowy zbiór", - "dso-selector.create.community.top-level": "Utwórz nowy nadrzędny zbiór", - "dso-selector.create.item.head": "Nowa pozycja", - "dso-selector.create.item.sub-level": "Utwórz nową pozycję w", - "dso-selector.create.submission.head": "Nowe zgłoszenie", - "dso-selector.edit.collection.head": "Edytuj kolekcję", - "dso-selector.edit.community.head": "Edytuj zbiór", - "dso-selector.edit.item.head": "Edytuj pozycję", - "dso-selector.error.title": "Wystąpił błąd podczas wyszukiwania typu {{ type }}", - "dso-selector.export-metadata.dspaceobject.head": "Eksportuj metadane z", - "dso-selector.no-results": "Nie znaleziono {{ type }}", - "dso-selector.placeholder": "Wyszukaj {{ type }}", - "dso-selector.select.collection.head": "Wybierz kolekcję", - "dso-selector.set-scope.community.head": "Wybierz wyszukiwanie zakresu", - "dso-selector.set-scope.community.button": "Wyszukaj w całym DSpace", - "dso-selector.set-scope.community.input-header": "Wyszukaj zbiór lub kolekcję", - "confirmation-modal.export-metadata.header": "Eksportuj metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.info": "Czy na pewno chcesz eksportować metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.cancel": "Anuluj", - "confirmation-modal.export-metadata.confirm": "Eksportuj", - "confirmation-modal.delete-eperson.header": "Usuń użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.info": "Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.cancel": "Anuluj", - "confirmation-modal.delete-eperson.confirm": "Usuń", - "error.bitstream": "Wystąpił błąd podczas tworzenia plików", - "error.browse-by": "Wystąpił błąd podczas tworzenia pozycji", - "error.collection": "Wystąpił błąd podczas tworzenia kolekcji", - "error.collections": "Wystąpił błąd podczas tworzenia kolekcji", - "error.community": "Wystąpił błąd podczas tworzenia ziboru", - "error.identifier": "Nie znaleziono pozycji z podanym identyfikatorem", - "error.default": "Błąd", - "error.item": "Wystąpił błąd podczas tworzenia pozycji", - "error.items": "Wystąpił błąd podczas tworzenia pozycji", - "error.objects": "Wystąpił błąd podczas tworzenia obiektów", - "error.recent-submissions": "Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", - "error.search-results": "Wystąpił błąd podczas tworzenia wyników wyszukiwania", - "error.sub-collections": "Wystąpił błąd podczas tworzenia podkolekcji", - "error.sub-communities": "Wystąpił błąd podczas tworzenia podzbiorów", - "error.submission.sections.init-form-error": "Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", - "error.top-level-communities": "Błąd podczas pobierania nadrzędnego zbioru", - "error.validation.license.notgranted": "Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", - "error.validation.pattern": "Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", - "error.validation.filerequired": "Przesłanie pliku jest obowiązkowe", - "error.validation.required": "Pole jest wymagane", - "error.validation.NotValidEmail": "E-mail nie jest poprawny", - "error.validation.emailTaken": "E-mail jest już zarejestrowany", - "error.validation.groupExists": "Ta grupa już istnieje", - "file-section.error.header": "Błąd podczas uzyskiwania plików dla tej pozycji", - "footer.copyright": "copyright © 2002-{{ year }}", - "footer.link.dspace": "oprogramowanie DSpace", - "footer.link.lyrasis": "LYRASIS", - "footer.link.cookies": "Ustawienia plików cookies", - "footer.link.privacy-policy": "Polityka prywatności", - "footer.link.end-user-agreement": "Umowa użytkownika", - "forgot-email.form.header": "Nie pamiętam hasła", - "forgot-email.form.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "forgot-email.form.email": "Adres e-mail *", - "forgot-email.form.email.error.required": "Uzupełnij adres e-mail", - "forgot-email.form.email.error.pattern": "Uzupełnij prawidłowy adres e-mail", - "forgot-email.form.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "forgot-email.form.submit": "Wyślij", - "forgot-email.form.success.head": "Wysłano wiadomość weryfikacyjną", - "forgot-email.form.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "forgot-email.form.error.head": "Błąd podczas rejestracji adresu e-mail", - "forgot-email.form.error.content": "Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", - "forgot-password.title": "Nie pamiętam hasła", - "forgot-password.form.head": "Nie pamiętam hasła", - "forgot-password.form.info": "Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", - "forgot-password.form.card.security": "Bezpieczeństwo", - "forgot-password.form.identification.header": "Identifikacja", - "forgot-password.form.identification.email": "Adres e-mail: ", - "forgot-password.form.label.password": "Hasło", - "forgot-password.form.label.passwordrepeat": "Potwierdź hasło", - "forgot-password.form.error.empty-password": "Wpisz hasło poniżej.", - "forgot-password.form.error.matching-passwords": "Hasła nie są identyczne.", - "forgot-password.form.notification.error.title": "Błąd podczas próby ustawienia nowego hasła", - "forgot-password.form.notification.success.content": "Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", - "forgot-password.form.notification.success.title": "Resetowanie hasła udane", - "forgot-password.form.submit": "Wpisz hasło", - "form.add": "Dodaj", - "form.add-help": "Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", - "form.cancel": "Anuluj", - "form.clear": "Wyczyść", - "form.clear-help": "Kliknij tutaj, aby usunąć wybraną wartość", - "form.discard": "Odrzuć", - "form.drag": "Przeciągnij", - "form.edit": "Edytuj", - "form.edit-help": "Kliknij tutaj, aby edytować wybraną wartość", - "form.first-name": "Imię", - "form.last-name": "Nazwisko", - "form.loading": "Ładowanie...", - "form.lookup": "Przeglądaj", - "form.lookup-help": "Kliknij tutaj, aby zobaczyć istniejące powiązania", - "form.no-results": "Nie znaleziono rezultatów", - "form.no-value": "Nie wprowadzono wartości", - "form.remove": "Usuń", - "form.save": "Zapisz", - "form.save-help": "Zapisz zmiany", - "form.search": "Wyszukaj", - "form.search-help": "Kliknij tutaj, aby wyszukać w istniejących komentarzach", - "form.submit": "Zapisz", - "form.repeatable.sort.tip": "Upuść nową pozycję w nowym miejscu", - "grant-deny-request-copy.deny": "Nie przesyłaj kopii", - "grant-deny-request-copy.email.back": "Cofnij", - "grant-deny-request-copy.email.message": "Wiadomości", - "grant-deny-request-copy.email.message.empty": "Proszę wprowadzić wiadomość", - "grant-deny-request-copy.email.permissions.info": "W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", - "grant-deny-request-copy.email.permissions.label": "Ustaw jako otwarty dostęp", - "grant-deny-request-copy.email.send": "Wyślij", - "grant-deny-request-copy.email.subject": "Temat", - "grant-deny-request-copy.email.subject.empty": "Wpisz temat", - "grant-deny-request-copy.grant": "Wyślij kopię", - "grant-deny-request-copy.header": "Prośba o przesłanie kopii dokumentu", - "grant-deny-request-copy.home-page": "Zabierz mnie na stronę główną", - "grant-deny-request-copy.intro1": "Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", - "grant-deny-request-copy.intro2": "Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", - "grant-deny-request-copy.processed": "Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "grant-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "grant-request-copy.email.subject": "Prośba o kopię dokumentu", - "grant-request-copy.error": "Wystąpił błąd", - "grant-request-copy.header": "Zezwól na wysłanie kopii dokumentu", - "grant-request-copy.intro": "To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", - "grant-request-copy.success": "Prośba o dostęp do dokumentu została przyjęta", - "home.description": "", - "home.breadcrumbs": "Strona główna", - "home.search-form.placeholder": "Przeszukaj repozytorium...", - "home.title": "Strona główna", - "home.top-level-communities.head": "Zbiory w DSpace", - "home.top-level-communities.help": "Przeszukaj kolekcje", - "info.end-user-agreement.accept": "Przeczytałem/am i akceptuję umowę użytkownika", - "info.end-user-agreement.accept.error": "Błąd wystąpił podczas akceptowania umowy użytkownika", - "info.end-user-agreement.accept.success": "Udało się zaktualizować umowę użytkownika", - "info.end-user-agreement.breadcrumbs": "Umowa użytkownika", - "info.end-user-agreement.buttons.cancel": "Anuluj", - "info.end-user-agreement.buttons.save": "Zapisz", - "info.end-user-agreement.head": "Umowa użytkownika", - "info.end-user-agreement.title": "Umowa użytkownika", - "info.privacy.breadcrumbs": "Oświadczenie polityki prywatności", - "info.privacy.head": "Oświadczenie polityki prywatności", - "info.privacy.title": "Oświadczenie polityki prywatności", - "item.alerts.private": "Ta pozycja jest prywatna", - "item.alerts.withdrawn": "Ta pozycja została wycofana", - "item.edit.authorizations.heading": "Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", - "item.edit.authorizations.title": "Edytuj politykę tej pozycji", - "item.badge.private": "Prywatny status publikacji", - "item.badge.withdrawn": "Wycofane publikacje", - "item.bitstreams.upload.bundle": "Pakiet", - "item.bitstreams.upload.bundle.placeholder": "Wybierz pakiet", - "item.bitstreams.upload.bundle.new": "Utworz pakiet", - "item.bitstreams.upload.bundles.empty": "Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", - "item.bitstreams.upload.cancel": "Anuluj", - "item.bitstreams.upload.drop-message": "Upuść plik, aby przesłać", - "item.bitstreams.upload.item": "Pozycja: ", - "item.bitstreams.upload.notifications.bundle.created.content": "Udało się utworzyć nowy pakiet.", - "item.bitstreams.upload.notifications.bundle.created.title": "Utwórz pakiet", - "item.bitstreams.upload.notifications.upload.failed": "Zweryfikuj pliki przed spróbowaniem ponownie.", - "item.bitstreams.upload.title": "Prześlij strumień bitów", - "item.edit.bitstreams.bundle.edit.buttons.upload": "Prześlij", - "item.edit.bitstreams.bundle.displaying": "Obecnie wyświetlono {{ amount }} plików z {{ total }}.", - "item.edit.bitstreams.bundle.load.all": "Załaduj wszystkie ({{ total }})", - "item.edit.bitstreams.bundle.load.more": "Załaduj więcej", - "item.edit.bitstreams.bundle.name": "PACZKA: {{ name }}", - "item.edit.bitstreams.discard-button": "Odrzuć", - "item.edit.bitstreams.edit.buttons.download": "Pobierz", - "item.edit.bitstreams.edit.buttons.drag": "Przeciągnij", - "item.edit.bitstreams.edit.buttons.edit": "Edytuj", - "item.edit.bitstreams.edit.buttons.remove": "Usuń", - "item.edit.bitstreams.edit.buttons.undo": "Cofnij zmiany", - "item.edit.bitstreams.empty": "Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", - "item.edit.bitstreams.headers.actions": "Akcje", - "item.edit.bitstreams.headers.bundle": "Paczka", - "item.edit.bitstreams.headers.description": "Opis", - "item.edit.bitstreams.headers.format": "Format", - "item.edit.bitstreams.headers.name": "Nazwa", - "item.edit.bitstreams.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", - "item.edit.bitstreams.notifications.discarded.title": "Zmiany odrzucone", - "item.edit.bitstreams.notifications.move.failed.title": "Błąd podczas przenoszenia plików", - "item.edit.bitstreams.notifications.move.saved.content": "Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", - "item.edit.bitstreams.notifications.move.saved.title": "Zmiana pozycji została zapisana", - "item.edit.bitstreams.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", - "item.edit.bitstreams.notifications.outdated.title": "Zmiany nieaktualne", - "item.edit.bitstreams.notifications.remove.failed.title": "Błąd podczas usuwania pliku", - "item.edit.bitstreams.notifications.remove.saved.content": "Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", - "item.edit.bitstreams.notifications.remove.saved.title": "Zmiany dotyczące usunięcia zapisane", - "item.edit.bitstreams.reinstate-button": "Cofnij", - "item.edit.bitstreams.save-button": "Zapisz", - "item.edit.bitstreams.upload-button": "Prześlij", - "item.edit.delete.cancel": "Anuluj", - "item.edit.delete.confirm": "Usuń", - "item.edit.delete.description": "Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", - "item.edit.delete.error": "Błąd wystąpił podczas usuwania pozycji", - "item.edit.delete.header": "Usuń pozycję: {{ id }}", - "item.edit.delete.success": "Ta pozycja została usunięta", - "item.edit.head": "Edytuj pozycję", - "item.edit.breadcrumbs": "Edytuj pozycję", - "item.edit.tabs.disabled.tooltip": "Nie masz dostępu do tej strony", - "item.edit.tabs.mapper.head": "Mapper kolekcji", - "item.edit.tabs.item-mapper.title": "Edytowanie pozycji - Mapper kolekcji", - "item.edit.item-mapper.buttons.add": "Mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.buttons.remove": "Usuń mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.cancel": "Anuluj", - "item.edit.item-mapper.description": "To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", - "item.edit.item-mapper.head": "Mapper pozycji - Mapowanie pozycji do kolekcji", - "item.edit.item-mapper.item": "Pozycja: \"<b>{{name}}</b>\"", - "item.edit.item-mapper.no-search": "Wpisz zapytanie, które chcesz wyszukać", - "item.edit.item-mapper.notifications.add.error.content": "Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.add.error.head": "Błędy mapowania", - "item.edit.item-mapper.notifications.add.success.content": "Udało się zmapować elementy dla {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.add.success.head": "Mapowanie zakończone", - "item.edit.item-mapper.notifications.remove.error.content": "Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.remove.error.head": "Usunięcie mapowania błędów", - "item.edit.item-mapper.notifications.remove.success.content": "Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.remove.success.head": "Usuwanie mapowania zakończone", - "item.edit.item-mapper.search-form.placeholder": "Przeszukaj kolekcje...", - "item.edit.item-mapper.tabs.browse": "Przeglądaj zmapowane kolekcje", - "item.edit.item-mapper.tabs.map": "Mapuj nowe kolekcje", - "item.edit.metadata.add-button": "Dodaj", - "item.edit.metadata.discard-button": "Odrzuć", - "item.edit.metadata.edit.buttons.edit": "Edytuj", - "item.edit.metadata.edit.buttons.remove": "Usuń", - "item.edit.metadata.edit.buttons.undo": "Cofnij zmiany", - "item.edit.metadata.edit.buttons.unedit": "Zatrzymaj edycję", - "item.edit.metadata.empty": "Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", - "item.edit.metadata.headers.edit": "Edytuj", - "item.edit.metadata.headers.field": "Pole", - "item.edit.metadata.headers.language": "Język", - "item.edit.metadata.headers.value": "Wartość", - "item.edit.metadata.metadatafield.invalid": "Wybierz aktualne pole metadanych", - "item.edit.metadata.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", - "item.edit.metadata.notifications.discarded.title": "Zmiany odrzucone", - "item.edit.metadata.notifications.error.title": "Wystąpił błąd", - "item.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", - "item.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadane", - "item.edit.metadata.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", - "item.edit.metadata.notifications.outdated.title": "Zmiany nieaktualne", - "item.edit.metadata.notifications.saved.content": "Twoje zmiany metadanych tej pozycji zostały zapisane.", - "item.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", - "item.edit.metadata.reinstate-button": "Cofnij", - "item.edit.metadata.save-button": "Zapisz", - "item.edit.modify.overview.field": "Pole", - "item.edit.modify.overview.language": "Język", - "item.edit.modify.overview.value": "Wartość", - "item.edit.move.cancel": "Anuluj", - "item.edit.move.save-button": "Zapisz", - "item.edit.move.discard-button": "Odrzuć", - "item.edit.move.description": "Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", - "item.edit.move.error": "Wystąpił błąd podczas przenoszenia pozycji", - "item.edit.move.head": "Przenieś pozycję: {{id}}", - "item.edit.move.inheritpolicies.checkbox": "Dziedziczenie polityk", - "item.edit.move.inheritpolicies.description": "Dziedzczenie domyślnych polityk z kolekcji docelowej", - "item.edit.move.move": "Przenieś", - "item.edit.move.processing": "Przenoszenie...", - "item.edit.move.search.placeholder": "Wpisz zapytanie, aby wyszukać w kolekcjach", - "item.edit.move.success": "Pozycja została przeniesiona", - "item.edit.move.title": "Przenieś pozycję", - "item.edit.private.cancel": "Anuluj", - "item.edit.private.confirm": "Ukryj", - "item.edit.private.description": "Czy chcesz ukryć tę pozycję?", - "item.edit.private.error": "Wystąpił błąd podczas ukrywania pozycji", - "item.edit.private.header": "Ukryj pozycję: {{ id }}", - "item.edit.private.success": "Pozycja jest teraz ukryta", - "item.edit.public.cancel": "Anuluj", - "item.edit.public.confirm": "Upublicznij", - "item.edit.public.description": "Czy chcesz upublicznić tę pozycję?", - "item.edit.public.error": "Wystąpił błąd podczas upubliczniania pozycji", - "item.edit.public.header": "Upublicznij pozycję: {{ id }}", - "item.edit.public.success": "Pozycja jest teraz publiczna", - "item.edit.reinstate.cancel": "Anuluj", - "item.edit.reinstate.confirm": "Przywróć", - "item.edit.reinstate.description": "Czy chcesz przywrócić tę pozycję?", - "item.edit.reinstate.error": "Wystąpił błąd podczas przywracania pozycji", - "item.edit.reinstate.header": "Przywróć pozycję: {{ id }}", - "item.edit.reinstate.success": "Pozycja została przywrócona", - "item.edit.relationships.discard-button": "Odrzuć", - "item.edit.relationships.edit.buttons.add": "Dodaj", - "item.edit.relationships.edit.buttons.remove": "Usuń", - "item.edit.relationships.edit.buttons.undo": "Cofnij zmiany", - "item.edit.relationships.no-relationships": "Brak relacji", - "item.edit.relationships.notifications.discarded.content": "Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", - "item.edit.relationships.notifications.discarded.title": "Zmiany zostały cofnięte", - "item.edit.relationships.notifications.failed.title": "Wystąpił błąd podczas edytowania relacji", - "item.edit.relationships.notifications.outdated.content": "Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", - "item.edit.relationships.notifications.outdated.title": "Zmiany są nieaktualne", - "item.edit.relationships.notifications.saved.content": "Twoje zmiany w relacjach tej pozycji zostały zapisane.", - "item.edit.relationships.notifications.saved.title": "Relacje zostały zapisane", - "item.edit.relationships.reinstate-button": "Cofnij", - "item.edit.relationships.save-button": "Zapisz", - "item.edit.relationships.no-entity-type": "Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", - "item.edit.return": "Cofnij", - "item.edit.tabs.bitstreams.head": "Pliki", - "item.edit.tabs.bitstreams.title": "Edycja pozycji - pliki", - "item.edit.tabs.curate.head": "Administruj", - "item.edit.tabs.curate.title": "Edytowanie pozycji - administruj", - "item.edit.tabs.metadata.head": "Metadane", - "item.edit.tabs.metadata.title": "Edycja pozycji - metadane", - "item.edit.tabs.relationships.head": "Relacje", - "item.edit.tabs.relationships.title": "Edycja pozycja - relacje", - "item.edit.tabs.status.buttons.authorizations.button": "Dostępy...", - "item.edit.tabs.status.buttons.authorizations.label": "Określu dostęp do pozycji", - "item.edit.tabs.status.buttons.delete.button": "Usuń permanentnie", - "item.edit.tabs.status.buttons.delete.label": "Usuń pozycję permanentnie", - "item.edit.tabs.status.buttons.mappedCollections.button": "Zmapowane kolekcje", - "item.edit.tabs.status.buttons.mappedCollections.label": "Zarządzaj mapowanymi kolekcjami", - "item.edit.tabs.status.buttons.move.button": "Przenieś...", - "item.edit.tabs.status.buttons.move.label": "Przenieś pozycję do innej kolekcji", - "item.edit.tabs.status.buttons.private.button": "Ukryj...", - "item.edit.tabs.status.buttons.private.label": "Ukry pozycję", - "item.edit.tabs.status.buttons.public.button": "Upublicznij...", - "item.edit.tabs.status.buttons.public.label": "Upublicznij pozycję", - "item.edit.tabs.status.buttons.reinstate.button": "Przywróć...", - "item.edit.tabs.status.buttons.reinstate.label": "Przywróć pozycję", - "item.edit.tabs.status.buttons.unauthorized": "You're not authorized to perform this action", - "item.edit.tabs.status.buttons.withdraw.button": "Wycofaj...", - "item.edit.tabs.status.buttons.withdraw.label": "Wycofaj z repozytorium", - "item.edit.tabs.status.description": "Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", - "item.edit.tabs.status.head": "Status", - "item.edit.tabs.status.labels.handle": "Identyfikator", - "item.edit.tabs.status.labels.id": "ID pozycji", - "item.edit.tabs.status.labels.itemPage": "Strona pozycji", - "item.edit.tabs.status.labels.lastModified": "Ostatnia modyfikacja", - "item.edit.tabs.status.title": "Edycja pozycji - Status", - "item.edit.tabs.versionhistory.head": "Historia wersji", - "item.edit.tabs.versionhistory.title": "Edycja pozycji - historia wersji", - "item.edit.tabs.versionhistory.under-construction": "Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", - "item.edit.tabs.view.head": "Widok pozycji", - "item.edit.tabs.view.title": "Edycja pozycji - widok", - "item.edit.withdraw.cancel": "Anuluj", - "item.edit.withdraw.confirm": "Wycofaj", - "item.edit.withdraw.description": "Czy na pewno chcesz wycofać pozycję?", - "item.edit.withdraw.error": "Wystąpił błąd podczas wycofywania pozycji", - "item.edit.withdraw.header": "Wycofaj pozycję: {{ id }}", - "item.edit.withdraw.success": "Pozycja została wycofana", - "item.listelement.badge": "Pozycja", - "item.page.description": "Opis", - "item.page.journal-issn": "ISSN czasopisma", - "item.page.journal-title": "Tytuł czasopisma", - "item.page.publisher": "Wydawca", - "item.page.titleprefix": "Pozycja: ", - "item.page.volume-title": "Tytuł tomu", - "item.search.results.head": "Wyniki wyszukiwania pozycji", - "item.search.title": "Wyszukiwanie pozycji", - "item.page.abstract": "Abstrakt", - "item.page.author": "Autorzy", - "item.page.citation": "Cytowanie", - "item.page.collections": "Kolekcje", - "item.page.collections.loading": "Ładowanie...", - "item.page.collections.load-more": "Załaduj więcej", - "item.page.date": "Data", - "item.page.edit": "Edytuj pozycję", - "item.page.files": "Pliki", - "item.page.filesection.description": "Opis:", - "item.page.filesection.download": "Pobierz", - "item.page.filesection.format": "Format:", - "item.page.filesection.name": "Nazwa:", - "item.page.filesection.size": "Rozmiar:", - "item.page.journal.search.title": "Artykuły w czasopiśmie", - "item.page.link.full": "Zobacz szczegóły", - "item.page.link.simple": "Uproszczony widok", - "item.page.person.search.title": "Artykuły tego autora", - "item.page.related-items.view-more": "Pokaż o {{ amount }} więcej", - "item.page.related-items.view-less": "Ukryj {{ amount }}", - "item.page.relationships.isAuthorOfPublication": "Publikacje", - "item.page.relationships.isJournalOfPublication": "Publikacje", - "item.page.relationships.isOrgUnitOfPerson": "Autorzy", - "item.page.relationships.isOrgUnitOfProject": "Projekty naukowe", - "item.page.subject": "Słowa kluczowe", - "item.page.uri": "URI", - "item.page.bitstreams.view-more": "Pokaż więcej", - "item.page.bitstreams.collapse": "Pokaż mniej", - "item.page.filesection.original.bundle": "Oryginalne pliki", - "item.page.filesection.license.bundle": "Licencja", - "item.page.return": "Powrót", - "item.page.version.create": "Utwórz nową wersję", - "item.page.version.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.preview.dc.identifier.doi": "DOI", - "item.preview.dc.relation.ispartof": "Czasopismo lub seria", - "item.preview.dc.identifier.isbn": "ISBN", - "item.preview.dc.identifier.uri": "Identyfikator:", - "item.preview.dc.contributor.author": "Autorzy:", - "item.preview.dc.date.issued": "Data publikacji:", - "item.preview.dc.description.abstract": "Abstrakt:", - "item.preview.dc.identifier.other": "Inny identyfikator:", - "item.preview.dc.language.iso": "Język:", - "item.preview.dc.title": "Tytuł:", - "item.preview.dc.title.alternative": "Tytuł alternatywny", - "item.preview.dc.type": "Typ:", - "item.preview.dc.identifier": "Identyfikator:", - "item.preview.dc.relation.issn": "ISSN", - "item.preview.oaire.citation.issue": "Numer wydania", - "item.preview.oaire.citation.volume": "Numer tomu", - "item.preview.person.familyName": "Nazwisko:", - "item.preview.person.givenName": "Nazwa:", - "item.preview.person.identifier.orcid": "ORCID:", - "item.preview.project.funder.name": "Fundator:", - "item.preview.project.funder.identifier": "Identyfikator fundatora:", - "item.preview.oaire.awardNumber": "ID finansowania:", - "item.preview.dc.coverage.spatial": "Jurysdykcja:", - "item.preview.oaire.fundingStream": "Źródło finansowania:", - "item.select.confirm": "Potwierdź zaznaczone", - "item.select.empty": "Brak pozycji do wyświetlenia", - "item.select.table.author": "Autor", - "item.select.table.collection": "Kolekcja", - "item.select.table.title": "Tytuł", - "item.version.history.empty": "Jeszcze nie ma innych wersji tej pozycji.", - "item.version.history.head": "Poprzednie wersje", - "item.version.history.return": "Powrót", - "item.version.history.selected": "Wybrane wersje", - "item.version.history.selected.alert": "W tym momencie wyświetlono wersję {{version}} pozycji.", - "item.version.history.table.version": "Wersja", - "item.version.history.table.item": "Pozycja", - "item.version.history.table.editor": "Redaktor", - "item.version.history.table.date": "Data", - "item.version.history.table.summary": "Podsumowanie", - "item.version.history.table.workspaceItem": "Wersja robocza", - "item.version.history.table.workflowItem": "Pozycja workflow", - "item.version.history.table.actions": "Akcja", - "item.version.history.table.action.editWorkspaceItem": "Edytuj wersję roboczą pozycji", - "item.version.history.table.action.editSummary": "Edytuj podsumowanie", - "item.version.history.table.action.saveSummary": "Zapisz edycje podsumowania", - "item.version.history.table.action.discardSummary": "Odrzuć edycje podsumowania", - "item.version.history.table.action.newVersion": "Utwórz nową wersję z tej wersji", - "item.version.history.table.action.deleteVersion": "Wersja usunięta", - "item.version.history.table.action.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.version.notice": "To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", - "item.version.create.modal.header": "Nowa wersja", - "item.version.create.modal.text": "Utwórz nową wersję tej pozycji", - "item.version.create.modal.text.startingFrom": "zaczynając od wersji {{version}}", - "item.version.create.modal.button.confirm": "Utwórz", - "item.version.create.modal.button.confirm.tooltip": "Utwórz nową wersję", - "item.version.create.modal.button.cancel": "Anuluj", - "item.version.create.modal.button.cancel.tooltip": "Nie stwarzaj nowej wersji", - "item.version.create.modal.form.summary.label": "Podsumowanie", - "item.version.create.modal.form.summary.placeholder": "Wprowadź podsumowanie nowej wersji", - "item.version.create.notification.success": "Nowa wersja została utworzona z numerem {{version}}", - "item.version.create.notification.failure": "Nowa wersja nie została utworzona", - "item.version.create.notification.inProgress": "Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", - "item.version.delete.modal.header": "Usuń wersję", - "item.version.delete.modal.text": "Czy chcesz usunąć wersję {{version}}?", - "item.version.delete.modal.button.confirm": "Usuń", - "item.version.delete.modal.button.confirm.tooltip": "Usuń wersję", - "item.version.delete.modal.button.cancel": "Anuluj", - "item.version.delete.modal.button.cancel.tooltip": "Nie usuwaj tej wersji", - "item.version.delete.notification.success": "Wersja {{version}} została usunięta", - "item.version.delete.notification.failure": "Wersja {{version}} nie została usunięta", - "item.version.edit.notification.success": "Podsumowanie wersji {{version}} zostało zmienione", - "item.version.edit.notification.failure": "Podsumowanie wersji {{version}} nie zostało zmienione", - "journal.listelement.badge": "Czasopismo", - "journal.page.description": "Opis", - "journal.page.edit": "Edytuj tę pozycję", - "journal.page.editor": "Redaktor naczelny", - "journal.page.issn": "ISSN", - "journal.page.publisher": "Wydawca", - "journal.page.titleprefix": "Czasopismo: ", - "journal.search.results.head": "Wyniki wyszukiwania czasopism", - "journal.search.title": "Wyszukiwanie czasopism", - "journalissue.listelement.badge": "Numer czasopisma", - "journalissue.page.description": "Opis", - "journalissue.page.edit": "Edytuj pozycję", - "journalissue.page.issuedate": "Data wydania", - "journalissue.page.journal-issn": "ISSN czasopisma", - "journalissue.page.journal-title": "Tytuł czasopisma", - "journalissue.page.keyword": "Słowa kluczowe", - "journalissue.page.number": "Numer", - "journalissue.page.titleprefix": "Wydanie czasopisma: ", - "journalvolume.listelement.badge": "Numer tomu czasopisma", - "journalvolume.page.description": "Opis", - "journalvolume.page.edit": "Edytuj pozycję", - "journalvolume.page.issuedate": "Data wydania", - "journalvolume.page.titleprefix": "Numer tomu czasopisma: ", - "journalvolume.page.volume": "Numer wydania", - "iiifsearchable.listelement.badge": "Multimedia dokumentu", - "iiifsearchable.page.titleprefix": "Dokument: ", - "iiifsearchable.page.doi": "Stały link: ", - "iiifsearchable.page.issue": "Wydanie: ", - "iiifsearchable.page.description": "Opis: ", - "iiifviewer.fullscreen.notice": "Wyświetl na pełnym ekranie dla lepszego widoku.", - "iiif.listelement.badge": "Multimedia obrazu", - "iiif.page.titleprefix": "Obraz: ", - "iiif.page.doi": "Stały link: ", - "iiif.page.issue": "Numer wydania: ", - "iiif.page.description": "Opis: ", - "loading.bitstream": "Ładowanie pliku...", - "loading.bitstreams": "Ładowanie plików...", - "loading.browse-by": "Ładowanie pozycji...", - "loading.browse-by-page": "Ładowanie strony...", - "loading.collection": "Ładowanie kolekcji...", - "loading.collections": "Ładowanie kolekcji...", - "loading.content-source": "Ładowanie źródła treści...", - "loading.community": "Ładowanie zbioru...", - "loading.default": "Ładowanie...", - "loading.item": "Ładowanie pozycji...", - "loading.items": "Ładowanie pozycji...", - "loading.mydspace-results": "Ładowanie pozycji...", - "loading.objects": "Ładowanie...", - "loading.recent-submissions": "Ładowanie ostatnich zgłoszeń...", - "loading.search-results": "Ładowanie wyników wyszukiwania...", - "loading.sub-collections": "Ładowanie podkolekcji...", - "loading.sub-communities": "Ładowanie podzbioru...", - "loading.top-level-communities": "Ładowanie zbioru wyszego szczebla...", - "login.form.email": "Adres e-mail", - "login.form.forgot-password": "Nie pamiętasz hasła?", - "login.form.header": "Zaloguj się do DSpace", - "login.form.new-user": "Nie masz konta? Zarejestruj się.", - "login.form.or-divider": "lub", - "login.form.orcid": "Zaloguj za pomocą ORCID", - "login.form.oidc": "Zaloguj za pomocą OIDC", - "login.form.password": "Hasło", - "login.form.shibboleth": "Zaloguj za pomocą Shibboleth", - "login.form.submit": "Zaloguj się", - "login.title": "Zaloguj", - "login.breadcrumbs": "Zaloguj", - "logout.form.header": "Wyloguj się z DSpace", - "logout.form.submit": "Wyloguj się", - "logout.title": "Wylogowywanie", - "menu.header.admin": "Panel administracyjny", - "menu.header.image.logo": "Logo repozytorium", - "menu.header.admin.description": "Menu administratora", - "menu.section.access_control": "Uprawnienia", - "menu.section.access_control_authorizations": "Dostępy", - "menu.section.access_control_groups": "Grupy", - "menu.section.access_control_people": "Użytkownicy", - "menu.section.admin_search": "Wyszukiwanie administracyjne", - "menu.section.browse_community": "Ten zbiór", - "menu.section.browse_community_by_author": "Wg autorów", - "menu.section.browse_community_by_issue_date": "Wg daty wydania", - "menu.section.browse_community_by_title": "Wg tytułów", - "menu.section.browse_global": "Wszystko na DSpace", - "menu.section.browse_global_by_author": "Wg autorów", - "menu.section.browse_global_by_dateissued": "Wg daty wydania", - "menu.section.browse_global_by_subject": "Wg tematu", - "menu.section.browse_global_by_title": "Wg tytułu", - "menu.section.browse_global_communities_and_collections": "Zbiory i kolekcje", - "menu.section.control_panel": "Panel sterowania", - "menu.section.curation_task": "Zadanie administracyjne", - "menu.section.edit": "Edytuj", - "menu.section.edit_collection": "Kolekcja", - "menu.section.edit_community": "Zbiór", - "menu.section.edit_item": "Pozycja", - "menu.section.export": "Eksport", - "menu.section.export_collection": "Kolekcja", - "menu.section.export_community": "Zbiór", - "menu.section.export_item": "Pozycja", - "menu.section.export_metadata": "Metadane", - "menu.section.icon.access_control": "Sekcja menu Uprawnienia", - "menu.section.icon.admin_search": "Sekcja menu Wyszukiwanie administracyjne", - "menu.section.icon.control_panel": "Sekcja menu Panel sterowania", - "menu.section.icon.curation_tasks": "Sekcja menu Zadanie administracyjne", - "menu.section.icon.edit": "Sekcja menu Edycja", - "menu.section.icon.export": "Sekcja menu Eksport", - "menu.section.icon.find": "Sekcja menu Wyszukiwanie", - "menu.section.icon.import": "Sekcja menu Import", - "menu.section.icon.new": "Sekcja menu Dodaj", - "menu.section.icon.pin": "Przypnij boczny pasek", - "menu.section.icon.processes": "Sekcja menu Procesy", - "menu.section.icon.registries": "Sekcja menu Rejestry", - "menu.section.icon.statistics_task": "Sekcja menu Zadanie statystyczne", - "menu.section.icon.workflow": "Sekcja menu Zarządzanie workflow", - "menu.section.icon.unpin": "Odepnij boczny pasek", - "menu.section.import": "Import", - "menu.section.import_batch": "Import masowy (ZIP)", - "menu.section.import_metadata": "Metadane", - "menu.section.new": "Dodaj", - "menu.section.new_collection": "Kolekcja", - "menu.section.new_community": "Zbiór", - "menu.section.new_item": "Pozycja", - "menu.section.new_item_version": "Wersja pozycji", - "menu.section.new_process": "Proces", - "menu.section.pin": "Przypnij pasek boczny", - "menu.section.unpin": "Odepnij pasek boczny", - "menu.section.processes": "Procesy", - "menu.section.registries": "Rejestry", - "menu.section.registries_format": "Formaty", - "menu.section.registries_metadata": "Metadane", - "menu.section.statistics": "Statystyki", - "menu.section.statistics_task": "Zadanie statystyczne", - "menu.section.toggle.access_control": "Przełącz sekcję Uprawnienia", - "menu.section.toggle.control_panel": "Przełącz sekcję Panel sterowania", - "menu.section.toggle.curation_task": "Przełącz sekcję Zadanie kuratora", - "menu.section.toggle.edit": "Przełącz sekcję Edytuj", - "menu.section.toggle.export": "Przełącz sekcję Eksport", - "menu.section.toggle.find": "Przełącz sekcję Wyszukiwanie", - "menu.section.toggle.import": "Przełącz sekcję Import", - "menu.section.toggle.new": "Przełącz nową sekcję", - "menu.section.toggle.registries": "Przełącz sekcję Rejestry", - "menu.section.toggle.statistics_task": "Przełącz sekcję Zadanie statystyczne", - "menu.section.workflow": "Zarządzaj Workflow", - "mydspace.breadcrumbs": "Mój DSpace", - "mydspace.description": "", - "mydspace.messages.controller-help": "Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", - "mydspace.messages.description-placeholder": "Wpisz swoją wiadomość tutaj...", - "mydspace.messages.hide-msg": "Ukryj wiadomość", - "mydspace.messages.mark-as-read": "Oznacz jako przeczytane", - "mydspace.messages.mark-as-unread": "Oznacz jako nieprzeczytane", - "mydspace.messages.no-content": "Brak treści.", - "mydspace.messages.no-messages": "Brak wiadomości.", - "mydspace.messages.send-btn": "Wysłano", - "mydspace.messages.show-msg": "Pokaż wiadomość", - "mydspace.messages.subject-placeholder": "Temat...", - "mydspace.messages.submitter-help": "Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", - "mydspace.messages.title": "Wiadomości", - "mydspace.messages.to": "Do", - "mydspace.new-submission": "Nowe zgłoszenie", - "mydspace.new-submission-external": "Import medatanych z zewnętrznego źródła", - "mydspace.new-submission-external-short": "Import metadanych", - "mydspace.results.head": "Twoje zadania", - "mydspace.results.no-abstract": "Brak abstraktu", - "mydspace.results.no-authors": "Brak autorów", - "mydspace.results.no-collections": "Brak kolekcji", - "mydspace.results.no-date": "Brak daty", - "mydspace.results.no-files": "Brak plików", - "mydspace.results.no-results": "Brak pozycji do wyświetlenia", - "mydspace.results.no-title": "Brak tytułu", - "mydspace.results.no-uri": "Brak Uri", - "mydspace.search-form.placeholder": "Wyszukaj w mydspace...", - "mydspace.show.workflow": "Wszystkie zadania", - "mydspace.show.workspace": "Twoje zadania", - "mydspace.status.mydspaceArchived": "Zarchiwizowano", - "mydspace.status.mydspaceValidation": "Walidacja", - "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redaktora", - "mydspace.status.mydspaceWorkflow": "Workflow", - "mydspace.status.mydspaceWorkspace": "Wersja robocza", - "mydspace.title": "Mój DSpace", - "mydspace.upload.upload-failed": "Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", - "mydspace.upload.upload-failed-manyentries": "Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", - "mydspace.upload.upload-failed-moreonefile": "Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", - "mydspace.upload.upload-multiple-successful": "Utworzono {{qty}} przestrzeni roboczych.", - "mydspace.view-btn": "Widok", - "nav.browse.header": "Cały DSpace", - "nav.community-browse.header": "Wg zbiorów", - "nav.language": "Zmień język", - "nav.login": "Zaloguj", - "nav.logout": "Menu profilu użytkownika i wylogowywanie", - "nav.main.description": "Główny pasek nawigacji", - "nav.mydspace": "Mój DSpace", - "nav.profile": "Profil", - "nav.search": "Wyszukiwanie", - "nav.statistics.header": "Statystyki", - "nav.stop-impersonating": "Przestań impersonifikować użytkownika", - "nav.toggle": "Przełącz nawigację", - "nav.user.description": "Pasek profilu użytkownika", - "none.listelement.badge": "Pozycja", - "person.listelement.badge": "Osoba", - "person.listelement.no-title": "Nie znaleziono imienia", - "person.page.birthdate": "Data urodzenia", - "person.page.edit": "Edytuj pozycję", - "person.page.email": "Adres e-mail", - "person.page.firstname": "Imię", - "person.page.jobtitle": "Stanowisko", - "person.page.lastname": "Nazwisko", - "person.page.link.full": "Pokaż wszystkie metadane", - "person.page.orcid": "ORCID", - "person.page.orcid.create": "Utwórz ORCID ID", - "person.page.orcid.granted-authorizations": "Udzielone dostępy", - "person.page.orcid.grant-authorizations": "Udziel dostępu", - "person.page.orcid.link": "Połącz z ORCID ID", - "person.page.orcid.orcid-not-linked-message": "ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", - "person.page.orcid.unlink": "Odepnij z ORCID", - "person.page.orcid.unlink.processing": "Procesowanie...", - "person.page.orcid.missing-authorizations": "Brak dostępów", - "person.page.orcid.missing-authorizations-message": "Brakuj następujących dostępów:", - "person.page.orcid.no-missing-authorizations-message": "Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", - "person.page.orcid.no-orcid-message": "Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", - "person.page.orcid.profile-preferences": "Preferencje profilu", - "person.page.orcid.funding-preferences": "Preferencje finansowania", - "person.page.orcid.publications-preferences": "Preferencje publikacji", - "person.page.orcid.remove-orcid-message": "Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", - "person.page.orcid.save.preference.changes": "Aktualizuj ustawienia", - "person.page.orcid.sync-profile.affiliation": "Afiliacja", - "person.page.orcid.sync-profile.biographical": "Biografia", - "person.page.orcid.sync-profile.education": "Edukacja", - "person.page.orcid.sync-profile.identifiers": "Identyfikatory", - "person.page.orcid.sync-fundings.all": "Wszystkie źrodła finansowania", - "person.page.orcid.sync-fundings.mine": "Moje źrodła finansowania", - "person.page.orcid.sync-fundings.my_selected": "Wybrane źródła finansowania", - "person.page.orcid.sync-fundings.disabled": "Nieaktywne", - "person.page.orcid.sync-publications.all": "Wszystkie publikacje", - "person.page.orcid.sync-publications.mine": "Moje publikacje", - "person.page.orcid.sync-publications.my_selected": "Wybrane publikacje", - "person.page.orcid.sync-publications.disabled": "Nieaktywne", - "person.page.orcid.sync-queue.discard": "Odrzuć zmianę i nie synchronizuj z ORCID", - "person.page.orcid.sync-queue.discard.error": "Rekord kolejki ORCID nie został odrzucony", - "person.page.orcid.sync-queue.discard.success": "Rekord kolejki ORCID został odrzucony", - "person.page.orcid.sync-queue.empty-message": "Rejestr kolejki w ORCID jest pusty", - "person.page.orcid.sync-queue.description.affiliation": "Afiliacje", - "person.page.orcid.sync-queue.description.country": "Kraj", - "person.page.orcid.sync-queue.description.education": "Edukacja", - "person.page.orcid.sync-queue.description.external_ids": "Zewnętrzne identyfikatory", - "person.page.orcid.sync-queue.description.other_names": "Inne imiona", - "person.page.orcid.sync-queue.description.qualification": "Kwalifikacje", - "person.page.orcid.sync-queue.description.researcher_urls": "URL naukowca", - "person.page.orcid.sync-queue.description.keywords": "Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.insert": "Dodaj nowy wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.update": "Aktualizuj ten wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.delete": "Usuń ten wpis z rejestru ORCID", - "person.page.orcid.sync-queue.tooltip.publication": "Publikacja", - "person.page.orcid.sync-queue.tooltip.affiliation": "Afiliacja", - "person.page.orcid.sync-queue.tooltip.education": "Edukacja", - "person.page.orcid.sync-queue.tooltip.qualification": "Kwalifikacje", - "person.page.orcid.sync-queue.tooltip.other_names": "Inna nazwa", - "person.page.orcid.sync-queue.tooltip.country": "Kraj", - "person.page.orcid.sync-queue.tooltip.keywords": "Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.external_ids": "Zewnętrzny identyfikator", - "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL naukowca", - "person.page.orcid.sync-queue.send": "Synchronizuj z rejestrem ORCID", - "person.page.orcid.sync-queue.send.unauthorized-error.title": "Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", - "person.page.orcid.sync-queue.send.unauthorized-error.content": "Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", - "person.page.orcid.sync-queue.send.bad-request-error": "Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", - "person.page.orcid.sync-queue.send.error": "Wysłanie zgłoszenia do ORCID nie powiodło się", - "person.page.orcid.sync-queue.send.conflict-error": "Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", - "person.page.orcid.sync-queue.send.not-found-warning": "Pozycja nie istnieje już w rejestrze ORCID.", - "person.page.orcid.sync-queue.send.success": "Zgłoszenie do ORCID zostało zakończone pomyślnie", - "person.page.orcid.sync-queue.send.validation-error": "Dane, które chcesz zsynchronizować z ORCID nie są poprawne", - "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Waluta jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", - "person.page.orcid.sync-queue.send.validation-error.title.required": "Tytuł jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.type.required": "Typ jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Data początkowa jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.funder.required": "Instytucja finansująca jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.required": "Instytucja jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Nazwa instytucji jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Aby wysłać instytucję, należy podać adres", - "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Aby wysłać adres, należy podać miasto", - "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Aby wysłać adres, należy podać kraj", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Należy uzupełnić wartość w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Należy uzupełnić źródło w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", - "person.page.orcid.synchronization-mode": "Tryb synchronizacji", - "person.page.orcid.synchronization-mode.batch": "Wsad", - "person.page.orcid.synchronization-mode.label": "Tryb synchronizacji", - "person.page.orcid.synchronization-mode-message": "Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", - "person.page.orcid.synchronization-settings-update.success": "Opcje synchronizacji zostały zaktualizowane", - "person.page.orcid.synchronization-settings-update.error": "Opcje synchronizacji nie zostały zaktualizowane", - "person.page.orcid.synchronization-mode.manual": "Ręczna", - "person.page.orcid.scope.authenticate": "Uzyskaj swój ORCID iD", - "person.page.orcid.scope.read-limited": "Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", - "person.page.orcid.scope.activities-update": "Dodaj/aktualizuj swoje aktywności naukowe", - "person.page.orcid.scope.person-update": "Dodaj/aktualizuj inne informacje o Tobie", - "person.page.orcid.unlink.success": "Odłączenie Twojego profilu od rejestru ORCID powiodło się", - "person.page.orcid.unlink.error": "Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", - "person.page.staffid": "ID pracownika", - "person.page.titleprefix": "Osoba: ", - "person.search.results.head": "Wyniki wyszukiwania użytkowników", - "person.search.title": "Wyniki wyszukiwania użytkowników", - "process.new.select-parameters": "Parametry", - "process.new.cancel": "Anuluj", - "process.new.submit": "Zapisz", - "process.new.select-script": "Skrypt", - "process.new.select-script.placeholder": "Wybierz skrypt...", - "process.new.select-script.required": "Skrypt jest wymagany", - "process.new.parameter.file.upload-button": "Wybierz plik...", - "process.new.parameter.file.required": "Proszę wybrać plik", - "process.new.parameter.string.required": "Wartość parametru jest wymagana", - "process.new.parameter.type.value": "wartość", - "process.new.parameter.type.file": "plik", - "process.new.parameter.required.missing": "Te parametry są wymagane, ale nie zostały uzupełnione:", - "process.new.notification.success.title": "Udało się", - "process.new.notification.success.content": "Udało się stworzyć proces", - "process.new.notification.error.title": "Błąd", - "process.new.notification.error.content": "Wystąpił błąd podczas tworzenia procesu", - "process.new.header": "Utwórz nowy proces", - "process.new.title": "Utwórz nowy proces", - "process.new.breadcrumbs": "Utwórz nowy proces", - "process.detail.arguments": "Argumenty", - "process.detail.arguments.empty": "Do tego procesu nie zostały przypisane żadne argumenty", - "process.detail.back": "Cofnij", - "process.detail.output": "Dane wyjściowe procesu", - "process.detail.logs.button": "Odzyskaj dane wyjściowe procesu", - "process.detail.logs.loading": "Odzyskiwanie", - "process.detail.logs.none": "Ten proces nie ma danych wyjściowych", - "process.detail.output-files": "Pliki", - "process.detail.output-files.empty": "Ten proces nie ma żadnych plików danych wyjściowych", - "process.detail.script": "Skrypt", - "process.detail.title": "Proces: {{ id }} - {{ name }}", - "process.detail.start-time": "Czas rozpoczęcia procesu", - "process.detail.end-time": "Czas zakończenia procesu", - "process.detail.status": "Status", - "process.detail.create": "Stwórz podobny proces", - "process.overview.table.finish": "Czas zakończenia (UTC)", - "process.overview.table.id": "Identyfikator procesu", - "process.overview.table.name": "Nazwa", - "process.overview.table.start": "Czas rozpoczęcia (UTC)", - "process.overview.table.status": "Status", - "process.overview.table.user": "Użytkownik", - "process.overview.title": "Przegląd procesów", - "process.overview.breadcrumbs": "Przegląd procesów", - "process.overview.new": "Nowy", - "profile.breadcrumbs": "Zaktualizuj profil", - "profile.card.identify": "Dane", - "profile.card.security": "Bezpieczeństwo", - "profile.form.submit": "Zaktualizuj profil", - "profile.groups.head": "Posiadane uprawnienia do kolekcji", - "profile.head": "Zaktualizuj profil", - "profile.metadata.form.error.firstname.required": "Imię jest wymagane", - "profile.metadata.form.error.lastname.required": "Nazwisko jest wymagane", - "profile.metadata.form.label.email": "Adres e-mail", - "profile.metadata.form.label.firstname": "Imię", - "profile.metadata.form.label.language": "Język", - "profile.metadata.form.label.lastname": "Nazwisko", - "profile.metadata.form.label.phone": "Telefon kontaktowy", - "profile.metadata.form.notifications.success.content": "Zmiany w profilu zostały zapisane.", - "profile.metadata.form.notifications.success.title": "Profil zapisany", - "profile.notifications.warning.no-changes.content": "Nie dokonano żadnych zmian w profilu.", - "profile.notifications.warning.no-changes.title": "Brak zmian", - "profile.security.form.error.matching-passwords": "Hasła nie są identyczne.", - "profile.security.form.info": "Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", - "profile.security.form.label.password": "Hasło", - "profile.security.form.label.passwordrepeat": "Potwierdź hasło", - "profile.security.form.notifications.success.content": "Twoje zmiany w haśle zostały zapisane.", - "profile.security.form.notifications.success.title": "Hasło zapisane", - "profile.security.form.notifications.error.title": "Błąd podczas próby zmiany hasła", - "profile.security.form.notifications.error.not-same": "Hasła nie są identyczne.", - "profile.title": "Zaktualizuj profil", - "profile.card.researcher": "Profil naukowca", - "project.listelement.badge": "Projekt badawczy", - "project.page.contributor": "Autorzy", - "project.page.description": "Opis", - "project.page.edit": "Edytuj pozycję", - "project.page.expectedcompletion": "Spodziewany termin zakończenia", - "project.page.funder": "Instytucje finansujące", - "project.page.id": "ID", - "project.page.keyword": "Słowa kluczowe", - "project.page.status": "Status", - "project.page.titleprefix": "Projekt badawczy: ", - "project.search.results.head": "Wyniki wyszukiwania projektów", - "publication.listelement.badge": "Publikacja", - "publication.page.description": "Opis", - "publication.page.edit": "Edytuj pozycję", - "publication.page.journal-issn": "ISSN czasopisma", - "publication.page.journal-title": "Tytuł czasopisma", - "publication.page.publisher": "Wydawca", - "publication.page.titleprefix": "Publikacja: ", - "publication.page.volume-title": "Tytuł tomu", - "publication.search.results.head": "Wyniki wyszukiwania publikacji", - "publication.search.title": "Wyszukiwanie publikacji", - "media-viewer.next": "Nowy", - "media-viewer.previous": "Poprzedni", - "media-viewer.playlist": "Playlista", - "register-email.title": "Rejestracja nowego użytkownika", - "register-page.create-profile.header": "Stwórz profil", - "register-page.create-profile.identification.header": "Dane", - "register-page.create-profile.identification.email": "Adres e-mail", - "register-page.create-profile.identification.first-name": "Imię *", - "register-page.create-profile.identification.first-name.error": "Wpisz imię", - "register-page.create-profile.identification.last-name": "Nazwisko *", - "register-page.create-profile.identification.last-name.error": "Wpisz nazwisko", - "register-page.create-profile.identification.contact": "Telefon kontaktowy", - "register-page.create-profile.identification.language": "Język", - "register-page.create-profile.security.header": "Bezpieczeństwo", - "register-page.create-profile.security.info": "Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", - "register-page.create-profile.security.label.password": "Hasło *", - "register-page.create-profile.security.label.passwordrepeat": "Potwierdź hasło *", - "register-page.create-profile.security.error.empty-password": "Wprowadź hasło w polu poniżej.", - "register-page.create-profile.security.error.matching-passwords": "Hasła nie są identyczne.", - "register-page.create-profile.submit": "Rejestracja zakończona", - "register-page.create-profile.submit.error.content": "Coś się nie udało podczas rejestracji nowego użytkownika.", - "register-page.create-profile.submit.error.head": "Rejestracja nie powiodła się", - "register-page.create-profile.submit.success.content": "Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", - "register-page.create-profile.submit.success.head": "Rejestracja zakończona", - "register-page.registration.header": "Rejestracja nowego użytkownika", - "register-page.registration.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "register-page.registration.email": "Adres e-mail *", - "register-page.registration.email.error.required": "Wypełnij adres e-mail", - "register-page.registration.email.error.pattern": "Wypełnij poprawny adres e-mail", - "register-page.registration.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "register-page.registration.submit": "Zarejestruj się", - "register-page.registration.success.head": "Wiadomość weryfikacyjna zostałą wysłana", - "register-page.registration.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "register-page.registration.error.head": "Błąd podczas próby rejestracji adresu e-mail", - "register-page.registration.error.content": "Błąd podczas próby rejestracji adresu e-mail: {{ email }}", - "relationships.add.error.relationship-type.content": "Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", - "relationships.add.error.server.content": "Błąd serwera", - "relationships.add.error.title": "Nie można dodać relacji", - "relationships.isAuthorOf": "Autorzy", - "relationships.isAuthorOf.Person": "Autorzy (osoby)", - "relationships.isAuthorOf.OrgUnit": "Autorzy (jednostki organizacyjne)", - "relationships.isIssueOf": "Numery czasopisma", - "relationships.isJournalIssueOf": "Numer czasopisma", - "relationships.isJournalOf": "Czasopisma", - "relationships.isOrgUnitOf": "Jednostki organizacyjne", - "relationships.isPersonOf": "Autorzy", - "relationships.isProjectOf": "Projekty badawcze", - "relationships.isPublicationOf": "Publikacje", - "relationships.isPublicationOfJournalIssue": "Artykuły", - "relationships.isSingleJournalOf": "Czasopismo", - "relationships.isSingleVolumeOf": "Tom czasopisma", - "relationships.isVolumeOf": "Tomy czasopisma", - "relationships.isContributorOf": "Autorzy", - "relationships.isContributorOf.OrgUnit": "Autor (Jednostka organizacyjna)", - "relationships.isContributorOf.Person": "Autor", - "relationships.isFundingAgencyOf.OrgUnit": "Instytucja finansująca", - "repository.image.logo": "Logo repozytorium", - "repository.title.prefix": "DSpace Angular :: ", - "researcher.profile.action.processing": "Procesowanie...", - "researcher.profile.associated": "Przypisanie profilu badacza", - "researcher.profile.create.new": "Utwórz nowy", - "researcher.profile.create.success": "Profil badacza został utworzony", - "researcher.profile.create.fail": "Wystąpił błąd poczas tworzenia profilu badacza.", - "researcher.profile.delete": "Usuń", - "researcher.profile.expose": "Ujawnij", - "researcher.profile.hide": "Ukryj", - "researcher.profile.not.associated": "Profil badacza nie został jeszcze przypisany", - "researcher.profile.view": "Widok", - "researcher.profile.private.visibility": "PRYWATNY", - "researcher.profile.public.visibility": "PUBLICZNY", - "researcher.profile.status": "Status:", - "researcherprofile.claim.not-authorized": "Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", - "researcherprofile.error.claim.body": "Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", - "researcherprofile.error.claim.title": "Błąd", - "researcherprofile.success.claim.body": "Wystąpienie z prośbą o przypisanie profilu udane", - "researcherprofile.success.claim.title": "Sukces", - "repository.title.prefixDSpace": "DSpace Angular ::", - "resource-policies.add.button": "Dodaj", - "resource-policies.add.for.": "Dodaj nową politykę", - "resource-policies.add.for.bitstream": "Dodaj nową politykę dla plików", - "resource-policies.add.for.bundle": "Dodaj nową politykę paczek", - "resource-policies.add.for.item": "Dodaj nową politykę pozycji", - "resource-policies.add.for.community": "Dodaj nową politykę zbioru", - "resource-policies.add.for.collection": "Dodaj nową politykę kolekcji", - "resource-policies.create.page.heading": "Utwórz nową politykę zasobu dla ", - "resource-policies.create.page.failure.content": "Wystąpił błąd podczas dodawania polityki zasobów.", - "resource-policies.create.page.success.content": "Działanie powiodło się", - "resource-policies.create.page.title": "Utwórz nową politykę zasobu", - "resource-policies.delete.btn": "Usuń zaznaczone", - "resource-policies.delete.btn.title": "Usuń zaznaczone polityki zasobów", - "resource-policies.delete.failure.content": "Wystąpił błąd podczas usuwania wybranych polityk zasobów.", - "resource-policies.delete.success.content": "Działanie powiodło się", - "resource-policies.edit.page.heading": "Edytuj politykę zasobu ", - "resource-policies.edit.page.failure.content": "Wystąpił błąd poczas edytowania polityki zasobu.", - "resource-policies.edit.page.success.content": "Działanie udało się", - "resource-policies.edit.page.title": "Edytuj politykę zasobu", - "resource-policies.form.action-type.label": "Wybierz ten typ akcji", - "resource-policies.form.action-type.required": "Musisz wybrać akcję polityki zasobu.", - "resource-policies.form.eperson-group-list.label": "Użytkownik lub grupa, która otrzyma uprawnienia.", - "resource-policies.form.eperson-group-list.select.btn": "Wybierz", - "resource-policies.form.eperson-group-list.tab.eperson": "Wyszukaj użytkownika", - "resource-policies.form.eperson-group-list.tab.group": "Wyszukaj grupę", - "resource-policies.form.eperson-group-list.table.headers.action": "Akcja", - "resource-policies.form.eperson-group-list.table.headers.id": "ID", - "resource-policies.form.eperson-group-list.table.headers.name": "Nazwa", - "resource-policies.form.date.end.label": "Data zakończenia", - "resource-policies.form.date.start.label": "Data rozpoczęcia", - "resource-policies.form.description.label": "Opis", - "resource-policies.form.name.label": "Nazwa", - "resource-policies.form.policy-type.label": "Wybierz typ polityki", - "resource-policies.form.policy-type.required": "Musisz wybrać typ polityki zasobu.", - "resource-policies.table.headers.action": "Akcja", - "resource-policies.table.headers.date.end": "Data zakończenia", - "resource-policies.table.headers.date.start": "Data rozpoczęcia", - "resource-policies.table.headers.edit": "Edytuj", - "resource-policies.table.headers.edit.group": "Edytuj grupę", - "resource-policies.table.headers.edit.policy": "Edytuj politykę", - "resource-policies.table.headers.eperson": "Użytkownik", - "resource-policies.table.headers.group": "Grupa", - "resource-policies.table.headers.id": "ID", - "resource-policies.table.headers.name": "Nazwa", - "resource-policies.table.headers.policyType": "typ", - "resource-policies.table.headers.title.for.bitstream": "Polityki dla plików", - "resource-policies.table.headers.title.for.bundle": "Polityki dla paczek", - "resource-policies.table.headers.title.for.item": "Polityki dla pozycji", - "resource-policies.table.headers.title.for.community": "Polityki dla zbioru", - "resource-policies.table.headers.title.for.collection": "Polityki dla kolekcji", - "search.description": "", - "search.switch-configuration.title": "Pokaż", - "search.title": "Szukaj", - "search.breadcrumbs": "Szukaj", - "search.search-form.placeholder": "Szukaj w repozytorium...", - "search.filters.applied.f.author": "Autor", - "search.filters.applied.f.dateIssued.max": "Data zakończenia", - "search.filters.applied.f.dateIssued.min": "Data rozpoczęcia", - "search.filters.applied.f.dateSubmitted": "Data zgłoszenia", - "search.filters.applied.f.discoverable": "Ukryty", - "search.filters.applied.f.entityType": "Typ pozycji", - "search.filters.applied.f.has_content_in_original_bundle": "Ma przypisane pliki", - "search.filters.applied.f.itemtype": "Typ", - "search.filters.applied.f.namedresourcetype": "Status", - "search.filters.applied.f.subject": "Temat", - "search.filters.applied.f.submitter": "Zgłaszający", - "search.filters.applied.f.jobTitle": "Stanowisko", - "search.filters.applied.f.birthDate.max": "Data zakończenia tworzenia", - "search.filters.applied.f.birthDate.min": "Data rozpoczęcia tworzenia", - "search.filters.applied.f.withdrawn": "Wycofane", - "search.filters.filter.author.head": "Autor", - "search.filters.filter.author.placeholder": "Autor", - "search.filters.filter.author.label": "Wyszukaj autora", - "search.filters.filter.birthDate.head": "Data urodzenia", - "search.filters.filter.birthDate.placeholder": "Data urodzenia", - "search.filters.filter.birthDate.label": "Wyszukaj datę urodzenia", - "search.filters.filter.collapse": "Ukryj filtr", - "search.filters.filter.creativeDatePublished.head": "Data opublikowania", - "search.filters.filter.creativeDatePublished.placeholder": "Data opublikowania", - "search.filters.filter.creativeDatePublished.label": "Wyszukaj datę opublikowania", - "search.filters.filter.creativeWorkEditor.head": "Redaktor", - "search.filters.filter.creativeWorkEditor.placeholder": "Redaktor", - "search.filters.filter.creativeWorkEditor.label": "Wyszukaj redaktora", - "search.filters.filter.creativeWorkKeywords.head": "Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.placeholder": "Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.label": "Wyszukaj temat", - "search.filters.filter.creativeWorkPublisher.head": "Wydawca", - "search.filters.filter.creativeWorkPublisher.placeholder": "Wydawca", - "search.filters.filter.creativeWorkPublisher.label": "Wyszukaj wydawcę", - "search.filters.filter.dateIssued.head": "Data", - "search.filters.filter.dateIssued.max.placeholder": "Data maksymalna", - "search.filters.filter.dateIssued.max.label": "Koniec", - "search.filters.filter.dateIssued.min.placeholder": "Data minimalna", - "search.filters.filter.dateIssued.min.label": "Start", - "search.filters.filter.dateSubmitted.head": "Data zgłoszenia", - "search.filters.filter.dateSubmitted.placeholder": "Data zgłoszenia", - "search.filters.filter.dateSubmitted.label": "Wyszukaj datę zgłoszenia", - "search.filters.filter.discoverable.head": "Ukryty", - "search.filters.filter.withdrawn.head": "Wycofane", - "search.filters.filter.entityType.head": "Typ pozycji", - "search.filters.filter.entityType.placeholder": "Typ pozycji", - "search.filters.filter.entityType.label": "Wyszukaj typ pozycji", - "search.filters.filter.expand": "Rozwiń filtr", - "search.filters.filter.has_content_in_original_bundle.head": "Ma przypisane pliki", - "search.filters.filter.itemtype.head": "Typ", - "search.filters.filter.itemtype.placeholder": "Typ", - "search.filters.filter.itemtype.label": "Wyszukaj typ", - "search.filters.filter.jobTitle.head": "Stanowisko", - "search.filters.filter.jobTitle.placeholder": "Stanowisko", - "search.filters.filter.jobTitle.label": "Wyszukaj stanowisko", - "search.filters.filter.knowsLanguage.head": "Znajomość języka", - "search.filters.filter.knowsLanguage.placeholder": "Znajomość języka", - "search.filters.filter.knowsLanguage.label": "Wyszukaj wg znajomości języka", - "search.filters.filter.namedresourcetype.head": "Status", - "search.filters.filter.namedresourcetype.placeholder": "Status", - "search.filters.filter.namedresourcetype.label": "Wyszukaj status", - "search.filters.filter.objectpeople.head": "Osoby", - "search.filters.filter.objectpeople.placeholder": "Osoby", - "search.filters.filter.objectpeople.label": "Wyszukaj użytkowników", - "search.filters.filter.organizationAddressCountry.head": "Kraj", - "search.filters.filter.organizationAddressCountry.placeholder": "Kraj", - "search.filters.filter.organizationAddressCountry.label": "Wyszukaj kraj", - "search.filters.filter.organizationAddressLocality.head": "Miasto", - "search.filters.filter.organizationAddressLocality.placeholder": "Miasto", - "search.filters.filter.organizationAddressLocality.label": "Wyszukaj miasto", - "search.filters.filter.organizationFoundingDate.head": "Data założenia", - "search.filters.filter.organizationFoundingDate.placeholder": "Data założenia", - "search.filters.filter.organizationFoundingDate.label": "Wyszukaj datę założenia", - "search.filters.filter.scope.head": "Zakres", - "search.filters.filter.scope.placeholder": "Filtr zakresu", - "search.filters.filter.scope.label": "Wyszukaj filtr zakresu", - "search.filters.filter.show-less": "Pokaż mniej", - "search.filters.filter.show-more": "Pokaż więcej", - "search.filters.filter.subject.head": "Temat", - "search.filters.filter.subject.placeholder": "Temat", - "search.filters.filter.subject.label": "Wyszukaj temat", - "search.filters.filter.submitter.head": "Zgłaszający", - "search.filters.filter.submitter.placeholder": "Zgłaszający", - "search.filters.filter.submitter.label": "Wyszukaj zgłaszającego", - "search.filters.entityType.JournalIssue": "Numer czasopisma", - "search.filters.entityType.JournalVolume": "Tom czasopisma", - "search.filters.entityType.OrgUnit": "Jednostka organizacyjna", - "search.filters.has_content_in_original_bundle.true": "Tak", - "search.filters.has_content_in_original_bundle.false": "Nie", - "search.filters.discoverable.true": "Nie", - "search.filters.discoverable.false": "Tak", - "search.filters.withdrawn.true": "Tak", - "search.filters.withdrawn.false": "Nie", - "search.filters.head": "Filtry", - "search.filters.reset": "Resetuj filtry", - "search.filters.search.submit": "Zastosuj", - "search.form.search": "Wyszukaj", - "search.form.search_dspace": "W repozytorium", - "search.form.scope.all": "W całym DSpace", - "search.results.head": "Wyniki wyszukiwania", - "default.search.results.head": "Wyniki wyszukiwania", - "search.results.no-results": "Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", - "search.results.no-results-link": "fraz podobnych do Twojego wyszukiwania", - "search.results.empty": "Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", - "search.sidebar.close": "Wróć do wyników wyszukiwania", - "search.sidebar.filters.title": "Filtry", - "search.sidebar.open": "Narzędzia wyszukiwania", - "search.sidebar.results": "wyniki", - "search.sidebar.settings.rpp": "Wyników na stronie", - "search.sidebar.settings.sort-by": "Sortuj według", - "search.sidebar.settings.title": "Ustawienia", - "search.view-switch.show-detail": "Wyświetl widok szczegółowy", - "search.view-switch.show-grid": "Wyświetl jako siatkę", - "search.view-switch.show-list": "Wyświetl jako listę", - "sorting.ASC": "Rosnąco", - "sorting.DESC": "Malejąco", - "sorting.dc.title.ASC": "Tytułami rosnąco", - "sorting.dc.title.DESC": "Tytułami malejąco", - "sorting.score.ASC": "Najmniej trafne", - "sorting.score.DESC": "Najbardziej trafne", - "sorting.dc.date.issued.ASC": "Data wydania rosnąco", - "sorting.dc.date.issued.DESC": "Data wydania malejąco", - "sorting.dc.date.accessioned.ASC": "Data dostępu rosnąco", - "sorting.dc.date.accessioned.DESC": "Data dostępu malejąco", - "sorting.lastModified.ASC": "Ostatnia modyfikacja rosnąco", - "sorting.lastModified.DESC": "Ostatnia modyfikacja malejąco", - "statistics.title": "Statystyki", - "statistics.header": "Statystyki dla {{ scope }}", - "statistics.breadcrumbs": "Statystyki", - "statistics.page.no-data": "Brak dostępnych danych", - "statistics.table.no-data": "Brak dostępnych danych", - "statistics.table.header.views": "Wyświetlenia", - "submission.edit.breadcrumbs": "Edytuj zgłoszenie", - "submission.edit.title": "Edytuj zgłoszenie", - "submission.general.cancel": "Anuluj", - "submission.general.cannot_submit": "Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", - "submission.general.deposit": "Deponuj", - "submission.general.discard.confirm.cancel": "Anuluj", - "submission.general.discard.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.general.discard.confirm.submit": "Tak, na pewno", - "submission.general.discard.confirm.title": "Odrzuć zgłoszenie", - "submission.general.discard.submit": "Odrzuć", - "submission.general.info.saved": "Zapisane", - "submission.general.info.pending-changes": "Niezapisane zmiany", - "submission.general.save": "Zapisz", - "submission.general.save-later": "Zapisz wersję roboczą", - "submission.import-external.page.title": "Importuj metdane z zewnętrznego źródła", - "submission.import-external.title": "Importuj metadane z zewnętrznego źródła", - "submission.import-external.title.Journal": "Importuj czasopismo z zewnętrznego źródła", - "submission.import-external.title.JournalIssue": "Importuj numer czasopisma z zewnętrznego źródła", - "submission.import-external.title.JournalVolume": "Importuj tom czasopisma z zewnętrznego źródła", - "submission.import-external.title.OrgUnit": "Importuj wydawcę z zewnętrznego źródła", - "submission.import-external.title.Person": "Importuj osobę z zewnętrznego źródła", - "submission.import-external.title.Project": "Importuj projekt z zewnętrznego źródła", - "submission.import-external.title.Publication": "Importuj publikację z zewnętrznego źródła", - "submission.import-external.title.none": "Importuj metadane z zewnętrznego źródła", - "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", - "submission.import-external.back-to-my-dspace": "Powrót do MyDSpace", - "submission.import-external.search.placeholder": "Wyszukaj zewnętrzne źródła danych", - "submission.import-external.search.button": "Szukaj", - "submission.import-external.search.button.hint": "Zacznij wpisywać frazę, aby wyszukać", - "submission.import-external.search.source.hint": "Wybierz zewnętrzne źródło", - "submission.import-external.source.ads": "NASA/ADS", - "submission.import-external.source.arxiv": "arXiv", - "submission.import-external.source.cinii": "CiNii", - "submission.import-external.source.crossref": "CrossRef", - "submission.import-external.source.loading": "ładowanie...", - "submission.import-external.source.sherpaJournal": "Czasopisma w SHERPA", - "submission.import-external.source.sherpaJournalIssn": "Czasopisma w SHERPA wg ISSN", - "submission.import-external.source.sherpaPublisher": "Wydawcy w SHERPA", - "submission.import-external.source.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.import-external.source.orcid": "ORCID", - "submission.import-external.source.orcidWorks": "ORCID", - "submission.import-external.source.pubmed": "Pubmed", - "submission.import-external.source.pubmedeu": "Pubmed Europe", - "submission.import-external.source.lcname": "Nazwy Biblioteki Kongresu", - "submission.import-external.source.scielo": "SciELO", - "submission.import-external.source.scopus": "Scopus", - "submission.import-external.source.vufind": "VuFind", - "submission.import-external.source.wos": "Web Of Science", - "submission.import-external.source.epo": "Europejski Urząd Patentowy (EPO)", - "submission.import-external.preview.title.Journal": "Podgląd czasopisma", - "submission.import-external.preview.title.OrgUnit": "Podgląd organizacji", - "submission.import-external.preview.title.Person": "Podgląd osoby", - "submission.import-external.preview.title.Project": "Podgląd projektu", - "submission.import-external.preview.title.Publication": "Podgląd publikacji", - "submission.import-external.preview.subtitle": "Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", - "submission.import-external.preview.button.import": "Rozpocznij zgłoszenie", - "submission.import-external.preview.error.import.title": "Błąd zgłoszenia", - "submission.import-external.preview.error.import.body": "Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", - "submission.sections.describe.relationship-lookup.close": "Zamknij", - "submission.sections.describe.relationship-lookup.external-source.added": "Udało się dodać wpis do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importuj zdalny tom czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Nowy typ danych dodany!", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Importuj zdalną osobę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Importuj zdalny produkt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importuj zdalną aparaturę badawczą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Importuj zdalne wydarzenie", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Importuj zdalną instytucję finansującą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importuj zdalnego wydawcę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Importuj zdalnie patent", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Importuj zdalnie projekt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Importuj zdalnie publikację", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Udało się dodać autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Udało się zaimportować i dodać zewnętrznego autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Nadrzędność", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Importuj jako nową, lokalną, nadrzędną pozycję", - "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Anuluj", - "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Wybierz kolekcję do zaimportowania nowych pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Importuj jako nowy lokalny typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Importuj z LC Name", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Importuj z ORCID", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Importuj z Sherpa Journal", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Importuj z Sherpa Publisher", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Importuj z PubMed", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Importuj z arXiv", - "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Import", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Successfully added local journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Successfully imported and added external journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Udało się dodać lokalne czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Udało się dodać lokalny numer czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Wybierz lokalne powiązanie:", - "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Odznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Odznacz stronę", - "submission.sections.describe.relationship-lookup.search-tab.loading": "Ładowanie...", - "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Wyszukaj zapytanie", - "submission.sections.describe.relationship-lookup.search-tab.search": "Zastosuj", - "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Wyszukaj...", - "submission.sections.describe.relationship-lookup.search-tab.select-all": "Zaznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.select-page": "Zaznacz stronę", - "submission.sections.describe.relationship-lookup.selected": "Zaznacz {{ size }} pozycji", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Czasopisma lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Projekty lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Publikacje lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Lokalne jednostki organizacyjne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Lokalne paczki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Lokalne pliki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Lokalne czasopisma ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa Publishers ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC Names ({{ 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": "Wyszukaj instytucje finansujące", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Wyszukaj finansowanie", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Wyszukaj jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projekty", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekt", - "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projekty", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Wyszukaj...", - "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Aktualne zaznaczenie ({{ count }})", - "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalIssue": "Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalVolume": "Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Czasopisma", - "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Autorzy", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.Project": "Projekty", - "submission.sections.describe.relationship-lookup.title.Publication": "Publikacje", - "submission.sections.describe.relationship-lookup.title.Person": "Autorzy", - "submission.sections.describe.relationship-lookup.title.OrgUnit": "Jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.title.DataPackage": "Paczki danych", - "submission.sections.describe.relationship-lookup.title.DataFile": "Pliki danych", - "submission.sections.describe.relationship-lookup.title.Funding Agency": "Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Finansowanie", - "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Nadrzędna jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Przełącz na listę rozwijaną", - "submission.sections.describe.relationship-lookup.selection-tab.settings": "Ustawienia", - "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Twoje zaznaczenie jest puste.", - "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Wybrane tomy czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Wybrane projekty", - "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Wybrane publikacje", - "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Wybrane jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Wybrane pakiety danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Wybrane pliki danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Wybrany tom czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Wybrane instytucje finansujące", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Wybrane finansowanie", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Wybrana jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", - "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Zapisz nowy wariant imienia", - "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Użyj tylko w tym zgłoszeniu", - "submission.sections.ccLicense.type": "Typ licencji", - "submission.sections.ccLicense.select": "Wybierz typ licencji…", - "submission.sections.ccLicense.change": "Zmień typ licencji…", - "submission.sections.ccLicense.none": "Brak dostępnych licencji", - "submission.sections.ccLicense.option.select": "Wybierz opcję…", - "submission.sections.ccLicense.link": "Wybrano licencję:", - "submission.sections.ccLicense.confirmation": "Udzielam powyższej licencji", - "submission.sections.general.add-more": "Dodaj więcej", - "submission.sections.general.collection": "Kolekcja", - "submission.sections.general.deposit_error_notice": "Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", - "submission.sections.general.deposit_success_notice": "Udało się wprowadzić pozycję.", - "submission.sections.general.discard_error_notice": "Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", - "submission.sections.general.discard_success_notice": "Udało się odrzucić pozycję.", - "submission.sections.general.metadata-extracted": "Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", - "submission.sections.general.metadata-extracted-new-section": "Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", - "submission.sections.general.no-collection": "Nie znaleziono kolekcji", - "submission.sections.general.no-sections": "Opcje niedostępne", - "submission.sections.general.save_error_notice": "Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", - "submission.sections.general.save_success_notice": "Udało się zapisać zgłoszenie.", - "submission.sections.general.search-collection": "Szukaj kolekcji", - "submission.sections.general.sections_not_valid": "Niektóre sekcje są niekompletne.", - "submission.sections.submit.progressbar.CClicense": "Licencja Creative Commons", - "submission.sections.submit.progressbar.describe.recycle": "Odzyskaj", - "submission.sections.submit.progressbar.describe.stepcustom": "Opisz", - "submission.sections.submit.progressbar.describe.stepone": "Opisz", - "submission.sections.submit.progressbar.describe.steptwo": "Opisz", - "submission.sections.submit.progressbar.detect-duplicate": "Potencjalne duplikaty", - "submission.sections.submit.progressbar.license": "Zdeponuj licencję", - "submission.sections.submit.progressbar.upload": "Prześlij pliki", - "submission.sections.status.errors.title": "Błędy", - "submission.sections.status.valid.title": "Poprawność", - "submission.sections.status.warnings.title": "Ostrzeżenia", - "submission.sections.status.errors.aria": "ma błędy", - "submission.sections.status.valid.aria": "jest poprawne", - "submission.sections.status.warnings.aria": "ma ostrzeżenia", - "submission.sections.toggle.open": "Otwórz sekcję", - "submission.sections.toggle.close": "Zamknij sekcję", - "submission.sections.toggle.aria.open": "Rozwiń sekcję {{sectionHeader}}", - "submission.sections.toggle.aria.close": "Zwiń sekcję {{sectionHeader}}", - "submission.sections.upload.delete.confirm.cancel": "Anuluj", - "submission.sections.upload.delete.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.sections.upload.delete.confirm.submit": "Tak, na pewno", - "submission.sections.upload.delete.confirm.title": "Usuń plik", - "submission.sections.upload.delete.submit": "Usuń", - "submission.sections.upload.download.title": "Pobierz plik", - "submission.sections.upload.drop-message": "Upuść pliki, aby załączyć je do tej pozycji", - "submission.sections.upload.edit.title": "Edytuj plik", - "submission.sections.upload.form.access-condition-label": "Typ dostępu", - "submission.sections.upload.form.date-required": "Data jest wymagana.", - "submission.sections.upload.form.date-required-from": "Data przyznania dostępu od jest wymagana.", - "submission.sections.upload.form.date-required-until": "Data przyznania dostępu do jest wymagana.", - "submission.sections.upload.form.from-label": "Pozwól na dostęp od", - "submission.sections.upload.form.from-placeholder": "Od", - "submission.sections.upload.form.group-label": "Grupa", - "submission.sections.upload.form.group-required": "Grupa jest wymagana", - "submission.sections.upload.form.until-label": "Pozwól na dostęp do", - "submission.sections.upload.form.until-placeholder": "Do", - "submission.sections.upload.header.policy.default.nolist": "Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", - "submission.sections.upload.header.policy.default.withlist": "Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", - "submission.sections.upload.info": "Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", - "submission.sections.upload.no-entry": "Nie", - "submission.sections.upload.no-file-uploaded": "Pliki nie zostały jeszcze wgrane.", - "submission.sections.upload.save-metadata": "Zapisz metadane", - "submission.sections.upload.undo": "Anuluj", - "submission.sections.upload.upload-failed": "Przesyłanie nieudane", - "submission.sections.upload.upload-successful": "Przesyłanie udane", - "submission.submit.breadcrumbs": "Nowe zgłoszenie", - "submission.submit.title": "Nowe zgłoszenie", - "submission.workflow.generic.delete": "Usuń", - "submission.workflow.generic.delete-help": "Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", - "submission.workflow.generic.edit": "Edytuj", - "submission.workflow.generic.edit-help": "Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.generic.view": "Podgląd", - "submission.workflow.generic.view-help": "Wybierz tę opcję, aby wyświetlić metadane pozycji.", - "submission.workflow.tasks.claimed.approve": "Zatwierdź", - "submission.workflow.tasks.claimed.approve_help": "Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", - "submission.workflow.tasks.claimed.edit": "Edytuj", - "submission.workflow.tasks.claimed.edit_help": "Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.tasks.claimed.reject.reason.info": "Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", - "submission.workflow.tasks.claimed.reject.reason.placeholder": "Opisz powód odrzucenia zgłoszenia", - "submission.workflow.tasks.claimed.reject.reason.submit": "Odrzuć pozycję", - "submission.workflow.tasks.claimed.reject.reason.title": "Powód", - "submission.workflow.tasks.claimed.reject.submit": "Odrzuć", - "submission.workflow.tasks.claimed.reject_help": "Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", - "submission.workflow.tasks.claimed.return": "Cofnij do puli zadań", - "submission.workflow.tasks.claimed.return_help": "Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", - "submission.workflow.tasks.generic.error": "Podczas działania wystąpił błąd...", - "submission.workflow.tasks.generic.processing": "Procesowanie...", - "submission.workflow.tasks.generic.submitter": "Zgłaszający", - "submission.workflow.tasks.generic.success": "Udało się", - "submission.workflow.tasks.pool.claim": "Podejmij pracę", - "submission.workflow.tasks.pool.claim_help": "Przypisz to zadanie do siebie.", - "submission.workflow.tasks.pool.hide-detail": "Ukryj szczegóły", - "submission.workflow.tasks.pool.show-detail": "Pokaż szczegóły", - "thumbnail.default.alt": "Miniatura", - "thumbnail.default.placeholder": "Brak miniatury", - "thumbnail.project.alt": "Logo projektu", - "thumbnail.project.placeholder": "Obraz zastępczy projketu", - "thumbnail.orgunit.alt": "Logo jednostki organizacyjnej", - "thumbnail.orgunit.placeholder": "Obraz zastępczy jednostki organizacyjnej", - "thumbnail.person.alt": "Zdjęcie profilowe", - "thumbnail.person.placeholder": "Brak zdjęcia profilowego", - "title": "DSpace", - "vocabulary-treeview.header": "Widok drzewka", - "vocabulary-treeview.load-more": "Pokaż więcej", - "vocabulary-treeview.search.form.reset": "Resetuj", - "vocabulary-treeview.search.form.search": "Szukaj", - "vocabulary-treeview.search.no-result": "Brak pozycji do wyświetlenia", - "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", - "vocabulary-treeview.tree.description.srsc": "Kategorie tematów badań", - "uploader.browse": "wyszukaj na swoim urządzeniu", - "uploader.drag-message": "Przeciągnij i upuść pliki tutaj", - "uploader.delete.btn-title": "Usuń", - "uploader.or": ", lub ", - "uploader.processing": "Procesowanie", - "uploader.queue-length": "Długość kolejki", - "virtual-metadata.delete-item.info": "Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "virtual-metadata.delete-item.modal-head": "Wirtualne metadane tego powiązania", - "virtual-metadata.delete-relationship.modal-head": "Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "workflowAdmin.search.results.head": "Zarządzaj procesami", - "workflow-item.edit.breadcrumbs": "Edytuj pozycję procesu", - "workflow-item.edit.title": "Edytuj pozycję procesu", - "workflow-item.delete.notification.success.title": "Usunięte", - "workflow-item.delete.notification.success.content": "Ten element procesu został usunięty", - "workflow-item.delete.notification.error.title": "Coś poszło nie tak", - "workflow-item.delete.notification.error.content": "Ten element procesu nie mógł zostać usunięty", - "workflow-item.delete.title": "Usuń element procesu", - "workflow-item.delete.header": "Usuń element procesu", - "workflow-item.delete.button.cancel": "Anuluj", - "workflow-item.delete.button.confirm": "Usuń", - "workflow-item.send-back.notification.success.title": "SOdeślij do zgłaszającego", - "workflow-item.send-back.notification.success.content": "Ten element procesu został odesłany do zgłaszającego", - "workflow-item.send-back.notification.error.title": "Coś poszło nie tak", - "workflow-item.send-back.notification.error.content": "Ten element procesu nie mógł zostać odesłany do zgłaszającego", - "workflow-item.send-back.title": "Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.header": "Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.button.cancel": "Anuluj", - "workflow-item.send-back.button.confirm": "Odeślij", - "workflow-item.view.breadcrumbs": "Widok procesu", - "idle-modal.header": "Sesja wkrótce wygaśnie", - "idle-modal.info": "Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", - "idle-modal.log-out": "Wyloguj", - "idle-modal.extend-session": "Wydłuż sesję", - "workspace.search.results.head": "Twoje zadania", - "orgunit.listelement.badge": "Jednostka organizacyjna", - "orgunit.page.city": "Miasto", - "orgunit.page.country": "Kraj", - "orgunit.page.dateestablished": "Data założenia", - "orgunit.page.description": "Opis", - "orgunit.page.edit": "Edytuj pozycję", - "orgunit.page.id": "ID", - "orgunit.page.titleprefix": "Jednostka organizacyjna: ", - "pagination.options.description": "Opcje strony", - "pagination.results-per-page": "Wyników na stronę", - "pagination.showing.detail": "{{ range }} z {{ total }}", - "pagination.showing.label": "Teraz wyświetlane ", - "pagination.sort-direction": "Opcje sortowania", - "cookies.consent.purpose.sharing": "Udostępnianie", - "item.preview.dc.identifier.issn": "ISSN", - "500.page-internal-server-error": "Usługa niedostępna", - "500.help": "Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", - "500.link.home-page": "Zabierz mnie na stronę główną", - "error-page.description.401": "brak autoryzacji", - "error-page.description.403": "brak dostępu", - "error-page.description.500": "usługa niedostępna", - "error-page.description.404": "nie znaleziono strony", - "error-page.orcid.generic-error": "Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", - "access-status.embargo.listelement.badge": "Embargo", - "access-status.metadata.only.listelement.badge": "Tylko metadane", - "access-status.open.access.listelement.badge": "Open Access", - "access-status.restricted.listelement.badge": "Brak dostępu", - "access-status.unknown.listelement.badge": "Nieznane", - "admin.access-control.groups.table.edit.buttons.remove": "Usuń \"{{name}}\"", - "admin.metadata-import.page.validateOnly": "Tylko waliduj", - "admin.metadata-import.page.validateOnly.hint": "Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", - "bitstream.edit.form.iiifLabel.label": "Etykieta canvyIIIF", - "bitstream.edit.form.iiifLabel.hint": "Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", - "bitstream.edit.form.iiifToc.label": "Spis treści IIIF", - "bitstream.edit.form.iiifToc.hint": "Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", - "bitstream.edit.form.iiifWidth.label": "Szerokość canvy IIIF", - "bitstream.edit.form.iiifWidth.hint": "Szerokość canvy jest zwykle równa szerokości obrazu.", - "bitstream.edit.form.iiifHeight.label": "Wysokość canvy IIIF", - "bitstream.edit.form.iiifHeight.hint": "Wysokość canvy jest zwykle równa szerokości obrazu.", - "browse.back.all-results": "Wszystkie wyniki wyszukiwania", - "pagination.next.button": "Następny", - "pagination.previous.button": "Poprzedni", - "pagination.next.button.disabled.tooltip": "Brak więcej stron z wynikami wyszukiwania", - "browse.startsWith": ", zaczyna się od {{ startsWith }}", - "browse.title.page": "Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", - "collection.edit.item.authorizations.load-bundle-button": "Załaduj więcej paczek", - "collection.edit.item.authorizations.load-more-button": "Załaduj więcej", - "collection.edit.item.authorizations.show-bitstreams-button": "Pokaż polityki plików dla paczek", - "comcol-role.edit.create.error.title": "Nie udało się utworzyć grupy dla roli '{{ role }}'", - "curation.form.submit.error.invalid-handle": "Nie ustalono identyfikatora dla tego obiektu", - "confirmation-modal.delete-profile.header": "Usuń profil", - "confirmation-modal.delete-profile.info": "Czy na pewno chcesz usunąć profil", - "confirmation-modal.delete-profile.cancel": "Anuluj", - "confirmation-modal.delete-profile.confirm": "Usuń", - "error.invalid-search-query": "Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", - "feed.description": "Aktualności", - "footer.link.feedback": "Prześlij uwagi", - "form.group-collapse": "Zwiń", - "form.group-collapse-help": "Kliknij tutaj, aby zwinąć", - "form.group-expand": "Rozwiń", - "form.group-expand-help": "Kliknij tutaj, aby rozwinąć", - "health.breadcrumbs": "Stan systemu", - "health-page.heading": "Stan systemu", - "health-page.info-tab": "Informacje", - "health-page.status-tab": "Status", - "health-page.error.msg": "Serwis stanu systemu jest tymczasowo niedostępny", - "health-page.property.status": "Kod statusu", - "health-page.section.db.title": "Baza danych", - "health-page.section.geoIp.title": "GeoIp", - "health-page.section.solrAuthorityCore.title": "Autentykacja", - "health-page.section.solrOaiCore.title": "OAI", - "health-page.section.solrSearchCore.title": "Wyszukiwarka", - "health-page.section.solrStatisticsCore.title": "Statystyki", - "health-page.section-info.app.title": "Backend aplikacji", - "health-page.section-info.java.title": "Java", - "health-page.status": "Status", - "health-page.status.ok.info": "operacyjny", - "health-page.status.error.info": "Wykryte problemy", - "health-page.status.warning.info": "Wykryte potencjalne problemy", - "health-page.title": "Stan systemu", - "health-page.section.no-issues": "Nie wykryto żadnych problemów", - "info.feedback.breadcrumbs": "Uwagi", - "info.feedback.head": "Uwagi", - "info.feedback.title": "Uwagi", - "info.feedback.info": "Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", - "info.feedback.email_help": "Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", - "info.feedback.send": "Prześlij uwagi", - "info.feedback.comments": "Komentarz", - "info.feedback.email-label": "Twoj adres e-mail", - "info.feedback.create.success": "Uwagi przesłane!", - "info.feedback.error.email.required": "Poprawny adres e-mail jest wymagany", - "info.feedback.error.message.required": "Treść komentarza jest wymagana", - "info.feedback.page-label": "Strona", - "info.feedback.page_help": "Ta strona odnosi się do uwag.", - "item.orcid.return": "Powrót", - "item.truncatable-part.show-more": "Pokaż więcej", - "item.truncatable-part.show-less": "Pokaż mniej", - "item.page.orcid.title": "ORCID", - "item.page.orcid.tooltip": "Otwórz ustawienia ORCID", - "item.page.claim.button": "Podejmij pracę", - "item.page.claim.tooltip": "Podejmij pracę jako profil", - "item.version.create.modal.submitted.header": "Tworzenie nowej wersji...", - "item.version.create.modal.submitted.text": "Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", - "journal-relationships.search.results.head": "Wyniki wyszukiwania czasopism", - "menu.section.icon.health": "Sekcja menu Stan systemu", - "menu.section.health": "Stan systemu", - "metadata-export-search.tooltip": "Eksportuj wyniki wyszukiwania w formacie CSV", - "metadata-export-search.submit.success": "Eksport rozpoczął się", - "metadata-export-search.submit.error": "Eksport nie rozpoczął się", - "person.page.name": "Nazwa", - "person-relationships.search.results.head": "Wyniki wyszukiwania osób", - "profile.special.groups.head": "Autoryzacja do specjalnych grup, do których należysz", - "project-relationships.search.results.head": "Wyniki wyszukiwania projektów", - "publication-relationships.search.results.head": "Wyniki wyszukiwania publikacji", - "resource-policies.edit.page.target-failure.content": "Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", - "resource-policies.edit.page.other-failure.content": "Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", - "resource-policies.form.eperson-group-list.modal.header": "Nie można zmienić typu", - "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Nie można zastąpić użytkownika grupą.", - "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Nie można zastąpić grupy użytkownikiem.", - "resource-policies.form.eperson-group-list.modal.text2": "Usuń obecną polityke zasobu i stwórz nową o określonym typie.", - "resource-policies.form.eperson-group-list.modal.close": "Ok", - "search.results.view-result": "Widok", - "default-relationships.search.results.head": "Wyniki wyszukiwania", - "statistics.table.title.TotalVisits": "Wyświetlnia ogółem", - "statistics.table.title.TotalVisitsPerMonth": "Wyświetlenia w miesiącu", - "statistics.table.title.TotalDownloads": "Pobrania", - "statistics.table.title.TopCountries": "Wyświetlenia wg krajów", - "statistics.table.title.TopCities": "Wyświetlenia wg miast", - "submission.import-external.preview.title": "Podgląd pozycji", - "submission.import-external.preview.title.none": "Podgląd pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import pozycji zdalnie", - "submission.sections.general.cannot_deposit": "Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", - "submission.sections.submit.progressbar.accessCondition": "Warunki dostępu do pozycji", - "submission.sections.submit.progressbar.sherpapolicy": "Polityki Sherpa", - "submission.sections.submit.progressbar.sherpaPolicies": "Informacje o polityce open access wydawcy.", - "submission.sections.status.info.title": "Dodatkowe informacje", - "submission.sections.status.info.aria": "Dodatkowe informacje", - "submission.sections.upload.form.access-condition-hint": "Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", - "submission.sections.upload.form.from-hint": "Wybierz datę, od której ma zostać zastosowany warunek dostępu", - "submission.sections.upload.form.until-hint": "Wybierz datę, do której ma zostać zastosowany warunek dostępu", - "submission.sections.accesses.form.discoverable-description": "Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", - "submission.sections.accesses.form.discoverable-label": "Niemożliwe do wyszukania", - "submission.sections.accesses.form.access-condition-label": "Typ warunku dostępu", - "submission.sections.accesses.form.access-condition-hint": "Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", - "submission.sections.accesses.form.date-required": "Data jest wymagana.", - "submission.sections.accesses.form.date-required-from": "Początkowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.date-required-until": "Końcowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.from-label": "Udziel dostępu od", - "submission.sections.accesses.form.from-hint": "Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.from-placeholder": "Od", - "submission.sections.accesses.form.group-label": "Grupa", - "submission.sections.accesses.form.group-required": "Grupa jest wymagana.", - "submission.sections.accesses.form.until-label": "Udziel dostępu do", - "submission.sections.accesses.form.until-hint": "Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.until-placeholder": "Do", - "submission.sections.sherpa.publication.information": "Informacje o publikacji", - "submission.sections.sherpa.publication.information.title": "Tytuł", - "submission.sections.sherpa.publication.information.issns": "Numery ISSN", - "submission.sections.sherpa.publication.information.url": "URL", - "submission.sections.sherpa.publication.information.publishers": "Wydawca", - "submission.sections.sherpa.publication.information.romeoPub": "Wydawca Romeo", - "submission.sections.sherpa.publication.information.zetoPub": "Wydawca Zeto", - "submission.sections.sherpa.publisher.policy": "Polityka wydawnicza", - "submission.sections.sherpa.publisher.policy.description": "Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", - "submission.sections.sherpa.publisher.policy.openaccess": "Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", - "submission.sections.sherpa.publisher.policy.more.information": "Aby uzuyskać więcej informacji, kliknij tutaj:", - "submission.sections.sherpa.publisher.policy.version": "Wersja", - "submission.sections.sherpa.publisher.policy.embargo": "Embargo", - "submission.sections.sherpa.publisher.policy.noembargo": "Brak embargo", - "submission.sections.sherpa.publisher.policy.nolocation": "Brak", - "submission.sections.sherpa.publisher.policy.license": "Licencja", - "submission.sections.sherpa.publisher.policy.prerequisites": "Wymagania wstępne", - "submission.sections.sherpa.publisher.policy.location": "Lokalizacja", - "submission.sections.sherpa.publisher.policy.conditions": "Wymagania", - "submission.sections.sherpa.publisher.policy.refresh": "Odśwież", - "submission.sections.sherpa.record.information": "Informacje o rekordzie", - "submission.sections.sherpa.record.information.id": "ID", - "submission.sections.sherpa.record.information.date.created": "Data utworzenia", - "submission.sections.sherpa.record.information.date.modified": "Ostatnia modyfikacja", - "submission.sections.sherpa.record.information.uri": "URI", - "submission.sections.sherpa.error.message": "Wystąpił błąd podczas pobierania informacji z Sherpa", - "submission.workspace.generic.view": "Podgląd", - "submission.workspace.generic.view-help": "Wybierz tę opcje, aby zobaczyć metadane.", - "workflow.search.results.head": "Zadania na workflow", - "workspace-item.view.breadcrumbs": "Widok wersji roboczej", - "workspace-item.view.title": "Widok wersji roboczej", - "researcher.profile.change-visibility.fail": "Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", - "person.page.orcid.link.processing": "Łączenie profilu z ORCID...", - "person.page.orcid.link.error.message": "Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", - "person.page.orcid.sync-queue.table.header.type": "Typ", - "person.page.orcid.sync-queue.table.header.description": "Opis", - "person.page.orcid.sync-queue.table.header.action": "Akcja", - "person.page.orcid.sync-queue.tooltip.project": "Projekt", - "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Niewłaściwy dwuznakowy kod kraju ISO 3166", - "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Wymagana data publikacji to co najmniej rok po 1900", - "person.page.orcid.synchronization-mode-funding-message": "Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", - "person.page.orcid.synchronization-mode-publication-message": "Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", - "person.page.orcid.synchronization-mode-profile-message": "Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", - "person.orcid.sync.setting": "Ustawienia synchronizacji z ORCID", - "person.orcid.registry.queue": "Kolejka rejestru z ORCID", - "person.orcid.registry.auth": "Autoryzacje z ORCID", - "home.recent-submissions.head": "Najnowsze publikacje", - "submission.sections.sherpa-policy.title-empty": "Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", - "admin.batch-import.breadcrumbs": "Import zbiorczy", - "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", - "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", - "admin.batch-import.page.error.addFile": "Najpierw wybierz plik (ZIP)", - "admin.batch-import.page.header": "Import masowy", - "admin.batch-import.page.help": "Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", - "admin.batch-import.page.remove": "usuń", - "admin.batch-import.page.validateOnly.hint": "Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", - "collection.form.correctionSubmissionDefinition": "Wzór zgłoszenia do prośby o korektę", - "comcol-role.edit.delete.error.title": "Nie udało się usunąć roli '{{ role }}' dla grup", - "confirmation-modal.export-batch.header": "Eksport maasowy (ZIP) {{ dsoName }}", - "confirmation-modal.export-batch.info": "Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", - "dso-selector.export-batch.dspaceobject.head": "Eksport masowy (ZIP) z", - "menu.section.export_batch": "Eksport masowy (ZIP)", - "nav.user-profile-menu-and-logout": "Profil użytkownika i wylogowywanie", - "process.detail.actions": "Akcje", - "process.detail.delete.body": "Czy na pewno chcesz usunąć bieżący proces?", - "process.detail.delete.button": "Usuń proces", - "process.detail.delete.cancel": "Anuluj", - "process.detail.delete.confirm": "Usuń proces", - "process.detail.delete.error": "Nie udało się usunąć procesu", - "process.detail.delete.header": "Usuń proces", - "process.detail.delete.success": "Proces został usunięty.", - "admin.batch-import.title": "Masowy import", - "admin.metadata-import.page.button.select-collection": "Wybierz kolekcję", - "admin.registries.bitstream-formats.table.id": "ID", - "admin.registries.schema.fields.table.id": "ID", - "cookies.consent.app.description.google-recaptcha": "Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", - "cookies.consent.app.disable-all.description": "Przełącz, aby zaakceptować lub odrzucić wszystkie", - "cookies.consent.app.disable-all.title": "Akceptowacja lub odrzucenie wszystkich", - "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", - "cookies.consent.content-modal.service": "usługa", - "cookies.consent.content-modal.services": "usługi", - "cookies.consent.content-notice.description.no-privacy": "Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", - "cookies.consent.content-notice.title": "Zgoda na ciasteczka", - "cookies.consent.ok": "Zgadzam się", - "cookies.consent.purpose.registration-password-recovery": "Rejestracja i odzyskiwanie hasła", - "cookies.consent.save": "Zapisz", - "curation-task.task.citationpage.label": "Generuj stronę z cytowaniem", - "dso-selector.import-batch.dspaceobject.head": "Import masowy z", - "orgunit.listelement.no-title": "Brak tytyłu", - "process.bulk.delete.error.body": "Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", - "process.bulk.delete.error.head": "Błąd podczas usuwania procesu", - "process.bulk.delete.success": "{{count}} proces/y został/y usunięte", - "process.overview.delete": "Usuń {{count}} proces/y", - "process.overview.delete.body": "Czy na pewno usunąć {{count}} proces/y?", - "process.overview.delete.clear": "Wyczyść selekcję procesów do usunięcia", - "process.overview.delete.header": "Usuń procesy", - "process.overview.delete.processing": "{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", - "process.overview.table.actions": "Akcje", - "profile.security.form.label.current-password": "Aktualne hasło", - "profile.security.form.notifications.error.change-failed": "Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", - "profile.security.form.notifications.error.general": "Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", - "register-page.registration.error.recaptcha": "Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", - "register-page.registration.google-recaptcha.must-accept-cookies": "Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", - "register-page.registration.google-recaptcha.notification.message.error": "Wystąpił błąd podczas weryfikacji reCaptcha", - "register-page.registration.google-recaptcha.notification.message.expired": "Weryfikacja wygasła. Zweryfikuj ponownie.", - "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", - "register-page.registration.google-recaptcha.open-cookie-settings": "Otwórz ustawienia plików cookies", - "search.results.response.500": "Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", - "submission.sections.license.granted-label": "Potwierdzam akceptację powyższej licencji", - "submission.sections.license.notgranted": "Najpierw musisz zaakceptować licencję", - "submission.sections.license.required": "Najpierw musisz zaakceptować licencję", - "confirmation-modal.export-batch.confirm": "Eksportuj", - "confirmation-modal.export-batch.cancel": "Anuluj", + "401.help":"Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", + "401.link.home-page":"Zabierz mnie na stronę główną", + "401.unauthorized":"nieautoryzowany", + "403.help":"Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "403.link.home-page":"Zabierz mnie na stronę główną", + "403.forbidden":"zabroniony", + "404.help":"Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", + "404.link.home-page":"Zabierz mnie na stronę główną", + "404.page-not-found":"strona nie została znaleziona", + "admin.curation-tasks.breadcrumbs":"Systemowe zadania administracyjne", + "admin.curation-tasks.title":"Systemowe zadania administracyjne", + "admin.curation-tasks.header":"Systemowe zadania administracyjne", + "admin.registries.bitstream-formats.breadcrumbs":"Rejestr formatów", + "admin.registries.bitstream-formats.create.breadcrumbs":"Format strumienia bitów", + "admin.registries.bitstream-formats.create.failure.content":"Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", + "admin.registries.bitstream-formats.create.failure.head":"Nie udało się", + "admin.registries.bitstream-formats.create.head":"Utwórz nowy format", + "admin.registries.bitstream-formats.create.new":"Dodaj nowy format", + "admin.registries.bitstream-formats.create.success.content":"Nowy format strumienia bitów został pomyślnie utworzony.", + "admin.registries.bitstream-formats.create.success.head":"Udało się", + "admin.registries.bitstream-formats.delete.failure.amount":"Nie udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.failure.head":"Nie udało się", + "admin.registries.bitstream-formats.delete.success.amount":"Udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.success.head":"Udało się", + "admin.registries.bitstream-formats.description":"Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", + "admin.registries.bitstream-formats.edit.breadcrumbs":"Format strumienia bitów", + "admin.registries.bitstream-formats.edit.description.hint":"", + "admin.registries.bitstream-formats.edit.description.label":"Opis", + "admin.registries.bitstream-formats.edit.extensions.hint":"Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", + "admin.registries.bitstream-formats.edit.extensions.label":"Rozszerzenia plików", + "admin.registries.bitstream-formats.edit.extensions.placeholder":"Wprowadź rozszerzenie pliku bez kropki", + "admin.registries.bitstream-formats.edit.failure.content":"Wystąpił błąd podczas edycji formatu pliku.", + "admin.registries.bitstream-formats.edit.failure.head":"Nie udało się", + "admin.registries.bitstream-formats.edit.head":"Format plików: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint":"Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", + "admin.registries.bitstream-formats.edit.internal.label":"Wewnętrzny", + "admin.registries.bitstream-formats.edit.mimetype.hint":"Typ MIME powiązany z tym formatem, nie musi być unikalny.", + "admin.registries.bitstream-formats.edit.mimetype.label":"Typ MIME", + "admin.registries.bitstream-formats.edit.shortDescription.hint":"Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label":"Nazwa", + "admin.registries.bitstream-formats.edit.success.content":"Format strumienia bitów został pomyślnie edytowany.", + "admin.registries.bitstream-formats.edit.success.head":"Udało się", + "admin.registries.bitstream-formats.edit.supportLevel.hint":"Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", + "admin.registries.bitstream-formats.edit.supportLevel.label":"Obsługiwany format", + "admin.registries.bitstream-formats.head":"Rejestr formatów", + "admin.registries.bitstream-formats.no-items":"Brak formatów plików do wyświetlenia.", + "admin.registries.bitstream-formats.table.delete":"Usuń zaznaczone", + "admin.registries.bitstream-formats.table.deselect-all":"Odznacz wszystkie", + "admin.registries.bitstream-formats.table.internal":"wewnętrzne", + "admin.registries.bitstream-formats.table.mimetype":"Typ MIME", + "admin.registries.bitstream-formats.table.name":"Nazwa", + "admin.registries.bitstream-formats.table.return":"Powrót", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN":"Znane", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED":"Wspierane", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN":"Nieznane", + "admin.registries.bitstream-formats.table.supportLevel.head":"Obsługiwany format", + "admin.registries.bitstream-formats.title":"Rejestr formatów plików", + "admin.registries.metadata.breadcrumbs":"Rejestr metadanych", + "admin.registries.metadata.description":"W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", + "admin.registries.metadata.form.create":"Utwórz schemat metadanych", + "admin.registries.metadata.form.edit":"Edytuj schemat metadanych", + "admin.registries.metadata.form.name":"Nazwa", + "admin.registries.metadata.form.namespace":"Nazwa schematu", + "admin.registries.metadata.head":"Rejestr metadanych", + "admin.registries.metadata.schemas.no-items":"Brak rejestrów metadanych do pokazania.", + "admin.registries.metadata.schemas.table.delete":"Usuń zaznaczone", + "admin.registries.metadata.schemas.table.id":"ID", + "admin.registries.metadata.schemas.table.name":"Nazwa", + "admin.registries.metadata.schemas.table.namespace":"Nazwa schematu", + "admin.registries.metadata.title":"Rejestr metadanych", + "admin.registries.schema.breadcrumbs":"Schemat metadanych", + "admin.registries.schema.description":"Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", + "admin.registries.schema.fields.head":"Pola schematu metadanych", + "admin.registries.schema.fields.no-items":"Brak pól metadanych do pokazania.", + "admin.registries.schema.fields.table.delete":"Usuń zaznaczone", + "admin.registries.schema.fields.table.field":"Pole", + "admin.registries.schema.fields.table.scopenote":"Uwagi", + "admin.registries.schema.form.create":"Stwórz pole metadanych", + "admin.registries.schema.form.edit":"Edytuj pole metadanych", + "admin.registries.schema.form.element":"Element", + "admin.registries.schema.form.qualifier":"Kwalifikator", + "admin.registries.schema.form.scopenote":"Uwagi", + "admin.registries.schema.head":"Schemat metadanych", + "admin.registries.schema.notification.created":"Udało się utworzyć schemat metdanych \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure":"Nie udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.deleted.success":"Udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.edited":"Udało się edytować schemat metadanych \"{{prefix}}\"", + "admin.registries.schema.notification.failure":"Błąd", + "admin.registries.schema.notification.field.created":"Udało się utworzyć pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure":"Nie udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.deleted.success":"Udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.edited":"SUdało się edytować pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.success":"Udało się", + "admin.registries.schema.return":"Powrót", + "admin.registries.schema.title":"Rejestr schematów metadanych", + "admin.access-control.epeople.actions.delete":"Usuń użytkownika", + "admin.access-control.epeople.actions.impersonate":"Personifikuj użytkownika", + "admin.access-control.epeople.actions.reset":"Zresetuj hasło", + "admin.access-control.epeople.actions.stop-impersonating":"Przestań personifikować użytkownika", + "admin.access-control.epeople.breadcrumbs":"Użytkownicy", + "admin.access-control.epeople.title":"Użytkownicy", + "admin.access-control.epeople.head":"Użytkownicy", + "admin.access-control.epeople.search.head":"Wyszukaj", + "admin.access-control.epeople.button.see-all":"Przeglądaj wszystko", + "admin.access-control.epeople.search.scope.metadata":"Metadane", + "admin.access-control.epeople.search.scope.email":"E-mail", + "admin.access-control.epeople.search.button":"Wyszukaj", + "admin.access-control.epeople.search.placeholder":"Wyszukaj użytkownika...", + "admin.access-control.epeople.button.add":"Dodaj użytkownika", + "admin.access-control.epeople.table.id":"ID", + "admin.access-control.epeople.table.name":"Nazwa", + "admin.access-control.epeople.table.email":"E-mail", + "admin.access-control.epeople.table.edit":"Edytuj", + "admin.access-control.epeople.table.edit.buttons.edit":"Edytuj \"{{name}}\"", + "admin.access-control.epeople.table.edit.buttons.edit-disabled":"Brak uprawnień do edycji wybranej grupy", + "admin.access-control.epeople.table.edit.buttons.remove":"Usuń \"{{name}}\"", + "admin.access-control.epeople.no-items":"Brak użytkowników do wyświetlenia.", + "admin.access-control.epeople.form.create":"Utwórz użytkownika", + "admin.access-control.epeople.form.edit":"Edytuj użytkownika", + "admin.access-control.epeople.form.firstName":"Imię", + "admin.access-control.epeople.form.lastName":"Nazwisko", + "admin.access-control.epeople.form.email":"E-mail", + "admin.access-control.epeople.form.emailHint":"Adres e-mail musi być poprawny", + "admin.access-control.epeople.form.canLogIn":"Możliwość zalogowania", + "admin.access-control.epeople.form.requireCertificate":"Wymagany certyfikat", + "admin.access-control.epeople.form.return":"Powrót", + "admin.access-control.epeople.form.notification.created.success":"Udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure":"Nie udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure.emailInUse":"Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.failure.emailInUse":"Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.success":"Udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.edited.failure":"Nie udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.success":"Udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.failure":"Nie udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.groupsEPersonIsMemberOf":"Członek grup:", + "admin.access-control.epeople.form.table.id":"ID", + "admin.access-control.epeople.form.table.name":"Nazwa", + "admin.access-control.epeople.form.table.collectionOrCommunity":"Zbiór/kolekcja", + "admin.access-control.epeople.form.memberOfNoGroups":"Ten użytkownik nie jest członkiem żadnej grupy", + "admin.access-control.epeople.form.goToGroups":"Dodaj do grup", + "admin.access-control.epeople.notification.deleted.failure":"Nie udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.success":"Udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.groups.title":"Grupy", + "admin.access-control.groups.breadcrumbs":"Grupy", + "admin.access-control.groups.singleGroup.breadcrumbs":"Edytuj grupę", + "admin.access-control.groups.title.singleGroup":"Edytuj grupę", + "admin.access-control.groups.title.addGroup":"Nowa grupa", + "admin.access-control.groups.addGroup.breadcrumbs":"Nowa grupa", + "admin.access-control.groups.head":"Grupy/role", + "admin.access-control.groups.button.add":"Dodaj grupę", + "admin.access-control.groups.search.head":"Szukaj grup", + "admin.access-control.groups.button.see-all":"Przeszukaj wszystko", + "admin.access-control.groups.search.button":"Wyszukaj", + "admin.access-control.groups.search.placeholder":"Wyszukaj grupy...", + "admin.access-control.groups.table.id":"ID", + "admin.access-control.groups.table.name":"Nazwa", + "admin.access-control.groups.table.collectionOrCommunity":"Zbiór/kolekcja", + "admin.access-control.groups.table.members":"Członkowie", + "admin.access-control.groups.table.edit":"Edytuj", + "admin.access-control.groups.table.edit.buttons.edit":"Edytuj \"{{name}}\"", + "admin.access-control.groups.no-items":"Nie znaleziono grup z podaną frazą lub podanym UUID", + "admin.access-control.groups.notification.deleted.success":"Udało się usunąć grupę \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title":"Nie udało się usunąć grupy \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content":"Powód: \"{{cause}}\"", + "admin.access-control.groups.form.alert.permanent":"Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", + "admin.access-control.groups.form.alert.workflowGroup":"Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", + "admin.access-control.groups.form.head.create":"Utwórz grupę", + "admin.access-control.groups.form.head.edit":"Edytuj grupę", + "admin.access-control.groups.form.groupName":"Nazwa grupy", + "admin.access-control.groups.form.groupCommunity":"Zbiór lub kolekcja", + "admin.access-control.groups.form.groupDescription":"Opis", + "admin.access-control.groups.form.notification.created.success":"Udało się utworzyć grupę \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure":"Nie udało się utworzyć grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure.groupNameInUse":"Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", + "admin.access-control.groups.form.notification.edited.failure":"Nie udało się edytować grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse":"Nazwa \"{{name}}\" już w użyciu!", + "admin.access-control.groups.form.notification.edited.success":"Udało się edytować grupę \"{{name}}\"", + "admin.access-control.groups.form.actions.delete":"Usuń grupę", + "admin.access-control.groups.form.delete-group.modal.header":"Usuń grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.info":"Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.cancel":"Anuluj", + "admin.access-control.groups.form.delete-group.modal.confirm":"Usuń", + "admin.access-control.groups.form.notification.deleted.success":"Udało się usunąć grupę \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.title":"Nie udało się usunąć grupy \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.content":"Powód: \"{{ cause }}\"", + "admin.access-control.groups.form.members-list.head":"Użytkownik", + "admin.access-control.groups.form.members-list.search.head":"Dodaj użytkownika", + "admin.access-control.groups.form.members-list.button.see-all":"Pokaż wszystkich", + "admin.access-control.groups.form.members-list.headMembers":"Aktualni członkowie", + "admin.access-control.groups.form.members-list.search.scope.metadata":"Metadane", + "admin.access-control.groups.form.members-list.search.scope.email":"E-mail", + "admin.access-control.groups.form.members-list.search.button":"Wyszukaj", + "admin.access-control.groups.form.members-list.table.id":"ID", + "admin.access-control.groups.form.members-list.table.name":"Nazwa", + "admin.access-control.groups.form.members-list.table.identity":"Tożsamość", + "admin.access-control.groups.form.members-list.table.email":"E-mail", + "admin.access-control.groups.form.members-list.table.netid":"NetID", + "admin.access-control.groups.form.members-list.table.edit":"Usuń / Dodaj", + "admin.access-control.groups.form.members-list.table.edit.buttons.remove":"Usuń użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.addMember":"Udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.addMember":"Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.deleteMember":"Udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.deleteMember":"Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.table.edit.buttons.add":"Dodaj użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.members-list.no-members-yet":"Brak użytkowników w grupie, wyszukaj ich i dodaj.", + "admin.access-control.groups.form.members-list.no-items":"Nie znaleziono użytkowników podczas wyszukiwania", + "admin.access-control.groups.form.subgroups-list.notification.failure":"Coś poszło nie tak: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head":"Grupy", + "admin.access-control.groups.form.subgroups-list.search.head":"Dodaj podgrupę", + "admin.access-control.groups.form.subgroups-list.button.see-all":"Przeglądaj wszystkie", + "admin.access-control.groups.form.subgroups-list.headSubgroups":"Aktualne podgrupy", + "admin.access-control.groups.form.subgroups-list.search.button":"Wyszukaj", + "admin.access-control.groups.form.subgroups-list.table.id":"ID", + "admin.access-control.groups.form.subgroups-list.table.name":"Nazwa", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity":"Zbiór/kolekcja", + "admin.access-control.groups.form.subgroups-list.table.edit":"Usuń / Dodaj", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove":"Usuń podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add":"Dodaj podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup":"Aktualna grupa", + "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup":"Udało się dodać podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup":"Nie udało się dodać podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup":"Udało się usunąć podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup":"Nie udało się usunąć podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup":"Ta grupa jest już stworzona i nie może zostać dodana pononwie.", + "admin.access-control.groups.form.subgroups-list.no-items":"Nie znaleziono grup z tą nazwą lub UUID", + "admin.access-control.groups.form.subgroups-list.no-subgroups-yet":"Brak podgrup w grupie.", + "admin.access-control.groups.form.return":"Powrót", + "admin.search.breadcrumbs":"Wyszukiwanie administracyjne", + "admin.search.collection.edit":"Edytuj", + "admin.search.community.edit":"Edytuj", + "admin.search.item.delete":"Usuń", + "admin.search.item.edit":"Edytuj", + "admin.search.item.make-private":"Ukryj", + "admin.search.item.make-public":"Upublicznij", + "admin.search.item.move":"Przenieś", + "admin.search.item.reinstate":"Zmień instancję", + "admin.search.item.withdraw":"Wycofane", + "admin.search.title":"Wyszukiwanie administracyjne", + "administrativeView.search.results.head":"Wyszukiwanie administracyjne", + "admin.workflow.breadcrumbs":"Zarządzaj procesem", + "admin.workflow.title":"Zarządzaj procesem", + "admin.workflow.item.workflow":"Proces", + "admin.workflow.item.delete":"Usuń", + "admin.workflow.item.send-back":"Odeślij z powrotem", + "admin.metadata-import.breadcrumbs":"Importuj metadane", + "admin.metadata-import.title":"Importuj metadane", + "admin.metadata-import.page.header":"Importuj metadane", + "admin.metadata-import.page.help":"Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", + "admin.metadata-import.page.dropMsg":"Upuść plik w formacie CSV", + "admin.metadata-import.page.dropMsgReplace":"Upuść, aby zastąpić metadane w formacie CSV do importu", + "admin.metadata-import.page.button.return":"Powrót", + "admin.metadata-import.page.button.proceed":"Zastosuj", + "admin.metadata-import.page.error.addFile":"Najpierw wybierz plik!", + "auth.errors.invalid-user":"Niewłaściwy adres e-mail lub hasło.", + "auth.messages.expired":"Twoja sesja wygasła. Zaloguj się ponownie.", + "auth.messages.token-refresh-failed":"Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", + "bitstream.download.page":"Pobieranie {{bitstream}}...", + "bitstream.download.page.back":"Powrót", + "bitstream.edit.authorizations.link":"Edytuj polityki plików", + "bitstream.edit.authorizations.title":"Edytuj polityki plików", + "bitstream.edit.return":"Powrót", + "bitstream.edit.bitstream":"Pliki: ", + "bitstream.edit.form.description.hint":"Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", + "bitstream.edit.form.description.label":"Opis", + "bitstream.edit.form.embargo.hint":"Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", + "bitstream.edit.form.embargo.label":"Embargo do wybranej daty", + "bitstream.edit.form.fileName.hint":"Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", + "bitstream.edit.form.fileName.label":"Nazwa pliku", + "bitstream.edit.form.newFormat.label":"Opisz nowy format", + "bitstream.edit.form.newFormat.hint":"Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", + "bitstream.edit.form.primaryBitstream.label":"Pierwotny plik", + "bitstream.edit.form.selectedFormat.hint":"Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", + "bitstream.edit.form.selectedFormat.label":"Wybrany format", + "bitstream.edit.form.selectedFormat.unknown":"Tego formatu nie ma na liście", + "bitstream.edit.notifications.error.format.title":"Wystąpił błąd podczas zapisu formatu pliku", + "bitstream.edit.notifications.saved.content":"Zmiany w pliku zostały zapisane.", + "bitstream.edit.notifications.saved.title":"Plik został zapisany", + "bitstream.edit.title":"Edytuj plik", + "bitstream-request-a-copy.alert.canDownload1":"Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", + "bitstream-request-a-copy.alert.canDownload2":"tutaj", + "bitstream-request-a-copy.header":"Wystąp o kopię wybranego pliku", + "bitstream-request-a-copy.intro":"Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", + "bitstream-request-a-copy.intro.bitstream.one":"Wystąpienie o dostęp do następujących plików: ", + "bitstream-request-a-copy.intro.bitstream.all":"Wystąpienie o dostęp do wszystkich plików. ", + "bitstream-request-a-copy.name.label":"Imię *", + "bitstream-request-a-copy.name.error":"Imię jest wymagane", + "bitstream-request-a-copy.email.label":"Adres e-mail *", + "bitstream-request-a-copy.email.hint":"Plik zostanie przesłany na podany adres e-mail", + "bitstream-request-a-copy.email.error":"Proszę wprowadzić prawidłowy adres e-mail", + "bitstream-request-a-copy.allfiles.label":"Pliki", + "bitstream-request-a-copy.files-all-false.label":"Tylko plik, dla którego wystąpiono o dostęp", + "bitstream-request-a-copy.files-all-true.label":"Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", + "bitstream-request-a-copy.message.label":"Wiadomość", + "bitstream-request-a-copy.return":"Powrót", + "bitstream-request-a-copy.submit":"Wystąp o kopię", + "bitstream-request-a-copy.submit.success":"Wystąpienie o dostęp do pliku zostało przesłane.", + "bitstream-request-a-copy.submit.error":"Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", + "browse.comcol.by.author":"wg autorów", + "browse.comcol.by.dateissued":"wg daty wydania", + "browse.comcol.by.subject":"wg tematu", + "browse.comcol.by.title":"wg tytułu", + "browse.comcol.head":"Przeglądaj", + "browse.empty":"Brak rekordów do wyświetlenia.", + "browse.metadata.author":"Autor", + "browse.metadata.dateissued":"Data wydania", + "browse.metadata.subject":"Temat", + "browse.metadata.title":"Tytuł", + "browse.metadata.author.breadcrumbs":"Przeglądaj wg autorów", + "browse.metadata.dateissued.breadcrumbs":"Przeglądaj wg daty wydania", + "browse.metadata.subject.breadcrumbs":"Przeglądaj wg tematów", + "browse.metadata.title.breadcrumbs":"Przeglądaj wg tytułów", + "browse.startsWith.choose_start":"(Wybierz start)", + "browse.startsWith.choose_year":"(Wybierz rok)", + "browse.startsWith.choose_year.label":"Wybierz rok wydania", + "browse.startsWith.jump":"Przejdź do miejsca w indeksie:", + "browse.startsWith.months.april":"kwiecień", + "browse.startsWith.months.august":"sierpień", + "browse.startsWith.months.december":"grudzień", + "browse.startsWith.months.february":"luty", + "browse.startsWith.months.january":"styczeń", + "browse.startsWith.months.july":"lipiec", + "browse.startsWith.months.june":"czerwiec", + "browse.startsWith.months.march":"marzec", + "browse.startsWith.months.may":"maj", + "browse.startsWith.months.none":"(wybierz miesiąc)", + "browse.startsWith.months.none.label":"Wybierz miesiąc wydania", + "browse.startsWith.months.november":"listopad", + "browse.startsWith.months.october":"październik", + "browse.startsWith.months.september":"wrzesień", + "browse.startsWith.submit":"Zastosuj", + "browse.startsWith.type_date":"Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", + "browse.startsWith.type_date.label":"Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", + "browse.startsWith.type_text":"Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", + "browse.title":"Przeglądaj {{ collection }} wg {{ field }} {{ value }}", + "chips.remove":"Usuń chip", + "collection.create.head":"Utwórz kolekcję", + "collection.create.notifications.success":"Udało się utworzyć kolekcję", + "collection.create.sub-head":"Udało się utworzyć kolekcję dla zbioru {{ parent }}", + "collection.curate.header":"Administrator kolekcji: {{collection}}", + "collection.delete.cancel":"Anuluj", + "collection.delete.confirm":"Zatwierdź", + "collection.delete.processing":"Usuwanie", + "collection.delete.head":"Usuń kolekcję", + "collection.delete.notification.fail":"Kolekcja nie może być usunięt", + "collection.delete.notification.success":"Udało się usunąć kolekcję", + "collection.delete.text":"Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", + "collection.edit.delete":"Usuń kolekcję", + "collection.edit.head":"Edytuj kolekcję", + "collection.edit.breadcrumbs":"Edytuj kolekcję", + "collection.edit.tabs.mapper.head":"Item Mapper", + "collection.edit.tabs.item-mapper.title":"Edytuj kolekcję - Item Mapper", + "collection.edit.item-mapper.cancel":"Anuluj", + "collection.edit.item-mapper.collection":"Kolekcja: \"<b>{{name}}</b>\"", + "collection.edit.item-mapper.confirm":"Mapuj wybrane elementy", + "collection.edit.item-mapper.description":"To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", + "collection.edit.item-mapper.head":"Item Mapper - Mapuj pozycje z innych kolekcji", + "collection.edit.item-mapper.no-search":"Wpisz co chcesz wyszukać", + "collection.edit.item-mapper.notifications.map.error.content":"Wystąpiły błędy podczas mapowania {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.error.head":"Mapowanie błędów", + "collection.edit.item-mapper.notifications.map.success.content":"Udało się zmapować {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.success.head":"Mapowanie zakończone", + "collection.edit.item-mapper.notifications.unmap.error.content":"Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.error.head":"Usuń błędy mapowania", + "collection.edit.item-mapper.notifications.unmap.success.content":"Udało się usunąć błędy mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.success.head":"Usuwanie mapowania zakończone", + "collection.edit.item-mapper.remove":"Usuń wybrane mapowanie elementów", + "collection.edit.item-mapper.search-form.placeholder":"Wyszukaj pozycje...", + "collection.edit.item-mapper.tabs.browse":"Wyszukaj mapowane elementy", + "collection.edit.item-mapper.tabs.map":"Mapuj nowe elementy", + "collection.edit.logo.delete.title":"Usuń", + "collection.edit.logo.delete-undo.title":"Cofnij usunięcie", + "collection.edit.logo.label":"Logo kolekcji", + "collection.edit.logo.notifications.add.error":"Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", + "collection.edit.logo.notifications.add.success":"Udało się przesłać logo kolekcji.", + "collection.edit.logo.notifications.delete.success.title":"Logo usunięte", + "collection.edit.logo.notifications.delete.success.content":"Udało się usunąć logo kolekcji", + "collection.edit.logo.notifications.delete.error.title":"Błąd podczas usuwania loga", + "collection.edit.logo.upload":"Upuść logo kolekcji, aby je wgrać", + "collection.edit.notifications.success":"Udało się edytować kolekcję", + "collection.edit.return":"Powrót", + "collection.edit.tabs.curate.head":"Kurator", + "collection.edit.tabs.curate.title":"Edytowanie kolekcji - kurator", + "collection.edit.tabs.authorizations.head":"Autoryzacje", + "collection.edit.tabs.authorizations.title":"Edytowanie kolekcji - autoryzacje", + "collection.edit.tabs.metadata.head":"Edytuj metadane", + "collection.edit.tabs.metadata.title":"Edytowanie kolekcji - metadane", + "collection.edit.tabs.roles.head":"Przypisz role", + "collection.edit.tabs.roles.title":"Edytowanie kolekcji - role", + "collection.edit.tabs.source.external":"Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", + "collection.edit.tabs.source.form.errors.oaiSource.required":"Musisz wskazać id docelowej kolekcji.", + "collection.edit.tabs.source.form.harvestType":"Odczytywanie zawartości", + "collection.edit.tabs.source.form.head":"Skonfiguruj zewnętrzne źródło", + "collection.edit.tabs.source.form.metadataConfigId":"Format metadanych", + "collection.edit.tabs.source.form.oaiSetId":"Określony zestaw ID OAI", + "collection.edit.tabs.source.form.oaiSource":"Dostawca OAI", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS":"Odczytaj metadane i pliki (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF":"Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY":"Odczytaj tylko metadane", + "collection.edit.tabs.source.head":"Źródło treści", + "collection.edit.tabs.source.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", + "collection.edit.tabs.source.notifications.discarded.title":"Zmiany odrzucone", + "collection.edit.tabs.source.notifications.invalid.content":"Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", + "collection.edit.tabs.source.notifications.invalid.title":"Nieprawidłowe metadane", + "collection.edit.tabs.source.notifications.saved.content":"Zmiany wprowadzone w kolekcji zostały zapisane.", + "collection.edit.tabs.source.notifications.saved.title":"Źródło treści zapisane", + "collection.edit.tabs.source.title":"Collection Edit - Źródło treści", + "collection.edit.template.add-button":"Dodaj", + "collection.edit.template.breadcrumbs":"Szablon pozycji", + "collection.edit.template.cancel":"Anuluj", + "collection.edit.template.delete-button":"Usuń", + "collection.edit.template.edit-button":"Edytuj", + "collection.edit.template.error":"Wystąpił błąd podczas odzyskiwania szablonu pozycji", + "collection.edit.template.head":"Edytuj szablon dla kolekcji \"{{ collection }}\"", + "collection.edit.template.label":"Szablon pozycji", + "collection.edit.template.loading":"ładowanie szablonu pozycji...", + "collection.edit.template.notifications.delete.error":"Nie udało się usunąć szablonu pozycji", + "collection.edit.template.notifications.delete.success":"Udało się usunąć szablon pozycji", + "collection.edit.template.title":"Edytuj szablon pozycji", + "collection.form.abstract":"Opis skrócony", + "collection.form.description":"Tekst powitalny (HTML)", + "collection.form.errors.title.required":"Wpisz nazwę kolekcji", + "collection.form.license":"Licencja", + "collection.form.provenance":"Pochodzenie", + "collection.form.rights":"Tekst praw autorskich (HTML)", + "collection.form.tableofcontents":"Wiadomości (HTML)", + "collection.form.title":"Nazwa", + "collection.form.entityType":"Typ danych", + "collection.page.browse.recent.head":"Ostatnie zgłoszenia", + "collection.page.browse.recent.empty":"Brak pozycji do wyświetlenia", + "collection.page.edit":"Edytuj kolekcję", + "collection.page.handle":"Stały URI dla kolekcji", + "collection.page.license":"Licencja", + "collection.page.news":"Wiadomości", + "collection.select.confirm":"Zaakceptuj zaznaczone", + "collection.select.empty":"Brak kolekcji do wyświetlenia", + "collection.select.table.title":"Tytuł", + "collection.source.controls.head":"Kontrolki odczytywania", + "collection.source.controls.test.submit.error":"Coś poszło nie tak podczas rozpoczynania testów ustawień", + "collection.source.controls.test.failed":"Scenariusz testowy ustawień nie zadziałał", + "collection.source.controls.test.completed":"Scenariusz testowy ustawień został zakończony", + "collection.source.controls.test.submit":"Konfiguracja testowa", + "collection.source.controls.test.running":"Testowanie konfiguracji...", + "collection.source.controls.import.submit.success":"Import został rozpoczęty", + "collection.source.controls.import.submit.error":"Coś poszło nie tak podczas rozpoczynania importu", + "collection.source.controls.import.submit":"Importuj teraz", + "collection.source.controls.import.running":"Importowanie...", + "collection.source.controls.import.failed":"Wystąpił błąd podczas importu", + "collection.source.controls.import.completed":"Import zakończony", + "collection.source.controls.reset.submit.success":"Reset ustawień i powtórny import zostały rozpoczęte poprawnie", + "collection.source.controls.reset.submit.error":"Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", + "collection.source.controls.reset.failed":"Wystąpił błąd podczas resetowania ustawień i ponownego importu", + "collection.source.controls.reset.completed":"Reset ustawień i powtórny import zostały zakończone", + "collection.source.controls.reset.submit":"Resetowanie i powtórny import", + "collection.source.controls.reset.running":"Resetowanie i powtórny import...", + "collection.source.controls.harvest.status":"Status odczytywania:", + "collection.source.controls.harvest.start":"Czas rozpoczęcia odczytywania:", + "collection.source.controls.harvest.last":"Czas ostatniego odczytywania:", + "collection.source.controls.harvest.message":"Informacje nt. odczytywania:", + "collection.source.controls.harvest.no-information":"bd.", + "collection.source.update.notifications.error.content":"Te ustawienia zostały przetestowane i nie działają.", + "collection.source.update.notifications.error.title":"Błąd serwera", + "communityList.breadcrumbs":"Lista zbiorów", + "communityList.tabTitle":"Lista zbiorów", + "communityList.title":"Lista zbiorów", + "communityList.showMore":"Pokaż więcej", + "community.create.head":"Utwórz zbiór", + "community.create.notifications.success":"Udało się utworzyć zbiór", + "community.create.sub-head":"Utwórz podzbiór dla zbioru {{ parent }}", + "community.curate.header":"Zarządzaj zbiorem: {{community}}", + "community.delete.cancel":"Anuluj", + "community.delete.confirm":"Potwierdź", + "community.delete.processing":"Usuwanie...", + "community.delete.head":"Usuń zbiór", + "community.delete.notification.fail":"Zbiór nie może być usunięty", + "community.delete.notification.success":"Udało się usunąć zbiór", + "community.delete.text":"Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", + "community.edit.delete":"Usuń ten zbiór", + "community.edit.head":"Edytuj zbiór", + "community.edit.breadcrumbs":"Edytuj zbiór", + "community.edit.logo.delete.title":"Usuń logo", + "community.edit.logo.delete-undo.title":"Cofnij usunięcie", + "community.edit.logo.label":"Logo zbioru", + "community.edit.logo.notifications.add.error":"Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", + "community.edit.logo.notifications.add.success":"Przesłanie loga powiodło się.", + "community.edit.logo.notifications.delete.success.title":"Logo usunięte", + "community.edit.logo.notifications.delete.success.content":"Usunięcie loga zbioru powiodło się", + "community.edit.logo.notifications.delete.error.title":"Błąd podczas usuwania loga", + "community.edit.logo.upload":"Upuść logo zbioru, aby je przesłać", + "community.edit.notifications.success":"Udało się edytować zbiór", + "community.edit.notifications.unauthorized":"Nie masz uprawnień, aby wykonać te zmiany", + "community.edit.notifications.error":"Wystąpił błąd podczas edycji zbioru", + "community.edit.return":"Cofnij", + "community.edit.tabs.curate.head":"Administruj", + "community.edit.tabs.curate.title":"Edycja zbioru - administrator", + "community.edit.tabs.metadata.head":"Edytuj metadane", + "community.edit.tabs.metadata.title":"Edycja zbioru - metadane", + "community.edit.tabs.roles.head":"Przypisz role", + "community.edit.tabs.roles.title":"Edycja zbioru - role", + "community.edit.tabs.authorizations.head":"Uprawnienia", + "community.edit.tabs.authorizations.title":"Edycja zbioru - uprawnienia", + "community.listelement.badge":"Zbiór", + "comcol-role.edit.no-group":"Brak", + "comcol-role.edit.create":"Utwórz", + "comcol-role.edit.restrict":"Ogranicz", + "comcol-role.edit.delete":"Usuń", + "comcol-role.edit.community-admin.name":"Administratorzy", + "comcol-role.edit.collection-admin.name":"Administratorzy", + "comcol-role.edit.community-admin.description":"Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", + "comcol-role.edit.collection-admin.description":"Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", + "comcol-role.edit.submitters.name":"Zgłaszający", + "comcol-role.edit.submitters.description":"Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", + "comcol-role.edit.item_read.name":"Domyślny dostęp do odczytu pozycji", + "comcol-role.edit.item_read.description":"Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", + "comcol-role.edit.item_read.anonymous-group":"Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", + "comcol-role.edit.bitstream_read.name":"Domyślny dostęp do oczytu plików", + "comcol-role.edit.bitstream_read.description":"Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", + "comcol-role.edit.bitstream_read.anonymous-group":"Domyślny status odczytu dla nowych plików to Anonimowy.", + "comcol-role.edit.editor.name":"Redaktorzy", + "comcol-role.edit.editor.description":"Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", + "comcol-role.edit.finaleditor.name":"Redaktorzy końcowi", + "comcol-role.edit.finaleditor.description":"Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", + "comcol-role.edit.reviewer.name":"Recenzenci", + "comcol-role.edit.reviewer.description":"Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", + "community.form.abstract":"Opis skrócony", + "community.form.description":"Wstęp (HTML)", + "community.form.errors.title.required":"Wprowadź nazwę zbioru", + "community.form.rights":"Prawa autoskie (HTML)", + "community.form.tableofcontents":"Wiadomości (HTML)", + "community.form.title":"Nazwa", + "community.page.edit":"Edytuj ten zbiór", + "community.page.handle":"Stały URI zbioru", + "community.page.license":"Licencja", + "community.page.news":"Wiadomości", + "community.all-lists.head":"Podzbiory i kolekcje", + "community.sub-collection-list.head":"Kolekcje w tym zbiorze", + "community.sub-community-list.head":"Kolekcje w tym zbiorze", + "cookies.consent.accept-all":"Zaakceptuj wszystko", + "cookies.consent.accept-selected":"Zaakceptuj wybrane", + "cookies.consent.app.opt-out.description":"Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", + "cookies.consent.app.opt-out.title":"(możesz ją wyłaczyć)", + "cookies.consent.app.purpose":"cel", + "cookies.consent.app.required.description":"Ta aplikacja jest zawsze wymagana", + "cookies.consent.app.required.title":"(zawsze wymagana)", + "cookies.consent.update":"Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", + "cookies.consent.close":"Zamknij", + "cookies.consent.decline":"Odrzuć", + "cookies.consent.content-notice.description":"Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", + "cookies.consent.content-notice.learnMore":"Dostosuj", + "cookies.consent.content-modal.description":"Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", + "cookies.consent.content-modal.privacy-policy.name":"polityka prywatności", + "cookies.consent.content-modal.privacy-policy.text":"Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", + "cookies.consent.content-modal.title":"Informacje, które zbieramy", + "cookies.consent.app.title.authentication":"Logowanie", + "cookies.consent.app.description.authentication":"Musisz się zalogować", + "cookies.consent.app.title.preferences":"Preferencje", + "cookies.consent.app.description.preferences":"Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.acknowledgement":"Zgody", + "cookies.consent.app.description.acknowledgement":"Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.google-analytics":"Google Analytics", + "cookies.consent.app.description.google-analytics":"Pozwól na śledzenie do celów statystycznych", + "cookies.consent.purpose.functional":"Funkcjonalne", + "cookies.consent.purpose.statistical":"Statystyczne", + "curation-task.task.checklinks.label":"Sprawdź odnośniki w metadanych", + "curation-task.task.noop.label":"NOOP", + "curation-task.task.profileformats.label":"Profil formatów plików", + "curation-task.task.requiredmetadata.label":"Sprawdź poprawność wymaganych metadanych", + "curation-task.task.translate.label":"Microsoft Translator", + "curation-task.task.vscan.label":"Skan antywirusowy", + "curation.form.task-select.label":"Zadanie:", + "curation.form.submit":"Start", + "curation.form.submit.success.head":"Udało się rozpocząć zadanie administratora", + "curation.form.submit.success.content":"Zostaniesz przeniesiony na stronę procesu.", + "curation.form.submit.error.head":"Nie udało się się zakończyć zadania administratora", + "curation.form.submit.error.content":"Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", + "curation.form.handle.label":"Automatyzacja:", + "curation.form.handle.hint":"Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", + "deny-request-copy.email.message":"Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.subject":"Wystąp o kopię dokumentu", + "deny-request-copy.error":"Wystąpił błąd", + "deny-request-copy.header":"Odrzuć prośbę o przesłanie kopii dokumentu", + "deny-request-copy.intro":"Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", + "deny-request-copy.success":"Z powodzeniem odrzucono prośbę o udostępnienie pozycji", + "dso.name.untitled":"Brak tytułu", + "dso-selector.claim.item.head":"Wskazówki profilu", + "dso-selector.claim.item.body":"Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", + "dso-selector.claim.item.create-from-scratch":"Utwórz nowy", + "dso-selector.claim.item.not-mine-label":"Żaden nie jest mój", + "dso-selector.create.collection.head":"Nowa kolekcja", + "dso-selector.create.collection.sub-level":"Utwórz nową kolekcję w", + "dso-selector.create.community.head":"Nowy zbiór", + "dso-selector.create.community.sub-level":"Utwórz nowy zbiór", + "dso-selector.create.community.top-level":"Utwórz nowy nadrzędny zbiór", + "dso-selector.create.item.head":"Nowa pozycja", + "dso-selector.create.item.sub-level":"Utwórz nową pozycję w", + "dso-selector.create.submission.head":"Nowe zgłoszenie", + "dso-selector.edit.collection.head":"Edytuj kolekcję", + "dso-selector.edit.community.head":"Edytuj zbiór", + "dso-selector.edit.item.head":"Edytuj pozycję", + "dso-selector.error.title":"Wystąpił błąd podczas wyszukiwania typu {{ type }}", + "dso-selector.export-metadata.dspaceobject.head":"Eksportuj metadane z", + "dso-selector.no-results":"Nie znaleziono {{ type }}", + "dso-selector.placeholder":"Wyszukaj {{ type }}", + "dso-selector.select.collection.head":"Wybierz kolekcję", + "dso-selector.set-scope.community.head":"Wybierz wyszukiwanie zakresu", + "dso-selector.set-scope.community.button":"Wyszukaj w całym DSpace", + "dso-selector.set-scope.community.input-header":"Wyszukaj zbiór lub kolekcję", + "confirmation-modal.export-metadata.header":"Eksportuj metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.info":"Czy na pewno chcesz eksportować metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.cancel":"Anuluj", + "confirmation-modal.export-metadata.confirm":"Eksportuj", + "confirmation-modal.delete-eperson.header":"Usuń użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info":"Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.cancel":"Anuluj", + "confirmation-modal.delete-eperson.confirm":"Usuń", + "error.bitstream":"Wystąpił błąd podczas tworzenia plików", + "error.browse-by":"Wystąpił błąd podczas tworzenia pozycji", + "error.collection":"Wystąpił błąd podczas tworzenia kolekcji", + "error.collections":"Wystąpił błąd podczas tworzenia kolekcji", + "error.community":"Wystąpił błąd podczas tworzenia ziboru", + "error.identifier":"Nie znaleziono pozycji z podanym identyfikatorem", + "error.default":"Błąd", + "error.item":"Wystąpił błąd podczas tworzenia pozycji", + "error.items":"Wystąpił błąd podczas tworzenia pozycji", + "error.objects":"Wystąpił błąd podczas tworzenia obiektów", + "error.recent-submissions":"Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", + "error.search-results":"Wystąpił błąd podczas tworzenia wyników wyszukiwania", + "error.sub-collections":"Wystąpił błąd podczas tworzenia podkolekcji", + "error.sub-communities":"Wystąpił błąd podczas tworzenia podzbiorów", + "error.submission.sections.init-form-error":"Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", + "error.top-level-communities":"Błąd podczas pobierania nadrzędnego zbioru", + "error.validation.license.notgranted":"Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", + "error.validation.pattern":"Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", + "error.validation.filerequired":"Przesłanie pliku jest obowiązkowe", + "error.validation.required":"Pole jest wymagane", + "error.validation.NotValidEmail":"E-mail nie jest poprawny", + "error.validation.emailTaken":"E-mail jest już zarejestrowany", + "error.validation.groupExists":"Ta grupa już istnieje", + "file-section.error.header":"Błąd podczas uzyskiwania plików dla tej pozycji", + "footer.copyright":"copyright © 2002-{{ year }}", + "footer.link.dspace":"oprogramowanie DSpace", + "footer.link.lyrasis":"LYRASIS", + "footer.link.cookies":"Ustawienia plików cookies", + "footer.link.privacy-policy":"Polityka prywatności", + "footer.link.end-user-agreement":"Umowa użytkownika", + "forgot-email.form.header":"Nie pamiętam hasła", + "forgot-email.form.info":"Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "forgot-email.form.email":"Adres e-mail *", + "forgot-email.form.email.error.required":"Uzupełnij adres e-mail", + "forgot-email.form.email.error.pattern":"Uzupełnij prawidłowy adres e-mail", + "forgot-email.form.email.hint":"Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "forgot-email.form.submit":"Wyślij", + "forgot-email.form.success.head":"Wysłano wiadomość weryfikacyjną", + "forgot-email.form.success.content":"Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "forgot-email.form.error.head":"Błąd podczas rejestracji adresu e-mail", + "forgot-email.form.error.content":"Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", + "forgot-password.title":"Nie pamiętam hasła", + "forgot-password.form.head":"Nie pamiętam hasła", + "forgot-password.form.info":"Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", + "forgot-password.form.card.security":"Bezpieczeństwo", + "forgot-password.form.identification.header":"Identifikacja", + "forgot-password.form.identification.email":"Adres e-mail: ", + "forgot-password.form.label.password":"Hasło", + "forgot-password.form.label.passwordrepeat":"Potwierdź hasło", + "forgot-password.form.error.empty-password":"Wpisz hasło poniżej.", + "forgot-password.form.error.matching-passwords":"Hasła nie są identyczne.", + "forgot-password.form.notification.error.title":"Błąd podczas próby ustawienia nowego hasła", + "forgot-password.form.notification.success.content":"Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", + "forgot-password.form.notification.success.title":"Resetowanie hasła udane", + "forgot-password.form.submit":"Wpisz hasło", + "form.add":"Dodaj", + "form.add-help":"Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", + "form.cancel":"Anuluj", + "form.clear":"Wyczyść", + "form.clear-help":"Kliknij tutaj, aby usunąć wybraną wartość", + "form.discard":"Odrzuć", + "form.drag":"Przeciągnij", + "form.edit":"Edytuj", + "form.edit-help":"Kliknij tutaj, aby edytować wybraną wartość", + "form.first-name":"Imię", + "form.last-name":"Nazwisko", + "form.loading":"Ładowanie...", + "form.lookup":"Przeglądaj", + "form.lookup-help":"Kliknij tutaj, aby zobaczyć istniejące powiązania", + "form.no-results":"Nie znaleziono rezultatów", + "form.no-value":"Nie wprowadzono wartości", + "form.remove":"Usuń", + "form.save":"Zapisz", + "form.save-help":"Zapisz zmiany", + "form.search":"Wyszukaj", + "form.search-help":"Kliknij tutaj, aby wyszukać w istniejących komentarzach", + "form.submit":"Zapisz", + "form.repeatable.sort.tip":"Upuść nową pozycję w nowym miejscu", + "grant-deny-request-copy.deny":"Nie przesyłaj kopii", + "grant-deny-request-copy.email.back":"Cofnij", + "grant-deny-request-copy.email.message":"Wiadomości", + "grant-deny-request-copy.email.message.empty":"Proszę wprowadzić wiadomość", + "grant-deny-request-copy.email.permissions.info":"W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", + "grant-deny-request-copy.email.permissions.label":"Ustaw jako otwarty dostęp", + "grant-deny-request-copy.email.send":"Wyślij", + "grant-deny-request-copy.email.subject":"Temat", + "grant-deny-request-copy.email.subject.empty":"Wpisz temat", + "grant-deny-request-copy.grant":"Wyślij kopię", + "grant-deny-request-copy.header":"Prośba o przesłanie kopii dokumentu", + "grant-deny-request-copy.home-page":"Zabierz mnie na stronę główną", + "grant-deny-request-copy.intro1":"Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", + "grant-deny-request-copy.intro2":"Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", + "grant-deny-request-copy.processed":"Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "grant-request-copy.email.message":"Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "grant-request-copy.email.subject":"Prośba o kopię dokumentu", + "grant-request-copy.error":"Wystąpił błąd", + "grant-request-copy.header":"Zezwól na wysłanie kopii dokumentu", + "grant-request-copy.intro":"To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", + "grant-request-copy.success":"Prośba o dostęp do dokumentu została przyjęta", + "home.description":"", + "home.breadcrumbs":"Strona główna", + "home.search-form.placeholder":"Przeszukaj repozytorium...", + "home.title":"Strona główna", + "home.top-level-communities.head":"Zbiory w DSpace", + "home.top-level-communities.help":"Przeszukaj kolekcje", + "info.end-user-agreement.accept":"Przeczytałem/am i akceptuję umowę użytkownika", + "info.end-user-agreement.accept.error":"Błąd wystąpił podczas akceptowania umowy użytkownika", + "info.end-user-agreement.accept.success":"Udało się zaktualizować umowę użytkownika", + "info.end-user-agreement.breadcrumbs":"Umowa użytkownika", + "info.end-user-agreement.buttons.cancel":"Anuluj", + "info.end-user-agreement.buttons.save":"Zapisz", + "info.end-user-agreement.head":"Umowa użytkownika", + "info.end-user-agreement.title":"Umowa użytkownika", + "info.privacy.breadcrumbs":"Oświadczenie polityki prywatności", + "info.privacy.head":"Oświadczenie polityki prywatności", + "info.privacy.title":"Oświadczenie polityki prywatności", + "item.alerts.private":"Ta pozycja jest prywatna", + "item.alerts.withdrawn":"Ta pozycja została wycofana", + "item.edit.authorizations.heading":"Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", + "item.edit.authorizations.title":"Edytuj politykę tej pozycji", + "item.badge.private":"Prywatny status publikacji", + "item.badge.withdrawn":"Wycofane publikacje", + "item.bitstreams.upload.bundle":"Pakiet", + "item.bitstreams.upload.bundle.placeholder":"Wybierz pakiet", + "item.bitstreams.upload.bundle.new":"Utworz pakiet", + "item.bitstreams.upload.bundles.empty":"Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", + "item.bitstreams.upload.cancel":"Anuluj", + "item.bitstreams.upload.drop-message":"Upuść plik, aby przesłać", + "item.bitstreams.upload.item":"Pozycja: ", + "item.bitstreams.upload.notifications.bundle.created.content":"Udało się utworzyć nowy pakiet.", + "item.bitstreams.upload.notifications.bundle.created.title":"Utwórz pakiet", + "item.bitstreams.upload.notifications.upload.failed":"Zweryfikuj pliki przed spróbowaniem ponownie.", + "item.bitstreams.upload.title":"Prześlij strumień bitów", + "item.edit.bitstreams.bundle.edit.buttons.upload":"Prześlij", + "item.edit.bitstreams.bundle.displaying":"Obecnie wyświetlono {{ amount }} plików z {{ total }}.", + "item.edit.bitstreams.bundle.load.all":"Załaduj wszystkie ({{ total }})", + "item.edit.bitstreams.bundle.load.more":"Załaduj więcej", + "item.edit.bitstreams.bundle.name":"PACZKA: {{ name }}", + "item.edit.bitstreams.discard-button":"Odrzuć", + "item.edit.bitstreams.edit.buttons.download":"Pobierz", + "item.edit.bitstreams.edit.buttons.drag":"Przeciągnij", + "item.edit.bitstreams.edit.buttons.edit":"Edytuj", + "item.edit.bitstreams.edit.buttons.remove":"Usuń", + "item.edit.bitstreams.edit.buttons.undo":"Cofnij zmiany", + "item.edit.bitstreams.empty":"Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", + "item.edit.bitstreams.headers.actions":"Akcje", + "item.edit.bitstreams.headers.bundle":"Paczka", + "item.edit.bitstreams.headers.description":"Opis", + "item.edit.bitstreams.headers.format":"Format", + "item.edit.bitstreams.headers.name":"Nazwa", + "item.edit.bitstreams.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", + "item.edit.bitstreams.notifications.discarded.title":"Zmiany odrzucone", + "item.edit.bitstreams.notifications.move.failed.title":"Błąd podczas przenoszenia plików", + "item.edit.bitstreams.notifications.move.saved.content":"Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", + "item.edit.bitstreams.notifications.move.saved.title":"Zmiana pozycji została zapisana", + "item.edit.bitstreams.notifications.outdated.content":"Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", + "item.edit.bitstreams.notifications.outdated.title":"Zmiany nieaktualne", + "item.edit.bitstreams.notifications.remove.failed.title":"Błąd podczas usuwania pliku", + "item.edit.bitstreams.notifications.remove.saved.content":"Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", + "item.edit.bitstreams.notifications.remove.saved.title":"Zmiany dotyczące usunięcia zapisane", + "item.edit.bitstreams.reinstate-button":"Cofnij", + "item.edit.bitstreams.save-button":"Zapisz", + "item.edit.bitstreams.upload-button":"Prześlij", + "item.edit.delete.cancel":"Anuluj", + "item.edit.delete.confirm":"Usuń", + "item.edit.delete.description":"Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", + "item.edit.delete.error":"Błąd wystąpił podczas usuwania pozycji", + "item.edit.delete.header":"Usuń pozycję: {{ id }}", + "item.edit.delete.success":"Ta pozycja została usunięta", + "item.edit.head":"Edytuj pozycję", + "item.edit.breadcrumbs":"Edytuj pozycję", + "item.edit.tabs.disabled.tooltip":"Nie masz dostępu do tej strony", + "item.edit.tabs.mapper.head":"Mapper kolekcji", + "item.edit.tabs.item-mapper.title":"Edytowanie pozycji - Mapper kolekcji", + "item.edit.item-mapper.buttons.add":"Mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.buttons.remove":"Usuń mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.cancel":"Anuluj", + "item.edit.item-mapper.description":"To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", + "item.edit.item-mapper.head":"Mapper pozycji - Mapowanie pozycji do kolekcji", + "item.edit.item-mapper.item":"Pozycja: \"<b>{{name}}</b>\"", + "item.edit.item-mapper.no-search":"Wpisz zapytanie, które chcesz wyszukać", + "item.edit.item-mapper.notifications.add.error.content":"Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.add.error.head":"Błędy mapowania", + "item.edit.item-mapper.notifications.add.success.content":"Udało się zmapować elementy dla {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.add.success.head":"Mapowanie zakończone", + "item.edit.item-mapper.notifications.remove.error.content":"Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.remove.error.head":"Usunięcie mapowania błędów", + "item.edit.item-mapper.notifications.remove.success.content":"Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.remove.success.head":"Usuwanie mapowania zakończone", + "item.edit.item-mapper.search-form.placeholder":"Przeszukaj kolekcje...", + "item.edit.item-mapper.tabs.browse":"Przeglądaj zmapowane kolekcje", + "item.edit.item-mapper.tabs.map":"Mapuj nowe kolekcje", + "item.edit.metadata.add-button":"Dodaj", + "item.edit.metadata.discard-button":"Odrzuć", + "item.edit.metadata.edit.buttons.edit":"Edytuj", + "item.edit.metadata.edit.buttons.remove":"Usuń", + "item.edit.metadata.edit.buttons.undo":"Cofnij zmiany", + "item.edit.metadata.edit.buttons.unedit":"Zatrzymaj edycję", + "item.edit.metadata.empty":"Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", + "item.edit.metadata.headers.edit":"Edytuj", + "item.edit.metadata.headers.field":"Pole", + "item.edit.metadata.headers.language":"Język", + "item.edit.metadata.headers.value":"Wartość", + "item.edit.metadata.metadatafield.invalid":"Wybierz aktualne pole metadanych", + "item.edit.metadata.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", + "item.edit.metadata.notifications.discarded.title":"Zmiany odrzucone", + "item.edit.metadata.notifications.error.title":"Wystąpił błąd", + "item.edit.metadata.notifications.invalid.content":"Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", + "item.edit.metadata.notifications.invalid.title":"Nieprawidłowe metadane", + "item.edit.metadata.notifications.outdated.content":"Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", + "item.edit.metadata.notifications.outdated.title":"Zmiany nieaktualne", + "item.edit.metadata.notifications.saved.content":"Twoje zmiany metadanych tej pozycji zostały zapisane.", + "item.edit.metadata.notifications.saved.title":"Metadane zostały zapisane", + "item.edit.metadata.reinstate-button":"Cofnij", + "item.edit.metadata.save-button":"Zapisz", + "item.edit.modify.overview.field":"Pole", + "item.edit.modify.overview.language":"Język", + "item.edit.modify.overview.value":"Wartość", + "item.edit.move.cancel":"Anuluj", + "item.edit.move.save-button":"Zapisz", + "item.edit.move.discard-button":"Odrzuć", + "item.edit.move.description":"Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", + "item.edit.move.error":"Wystąpił błąd podczas przenoszenia pozycji", + "item.edit.move.head":"Przenieś pozycję: {{id}}", + "item.edit.move.inheritpolicies.checkbox":"Dziedziczenie polityk", + "item.edit.move.inheritpolicies.description":"Dziedzczenie domyślnych polityk z kolekcji docelowej", + "item.edit.move.move":"Przenieś", + "item.edit.move.processing":"Przenoszenie...", + "item.edit.move.search.placeholder":"Wpisz zapytanie, aby wyszukać w kolekcjach", + "item.edit.move.success":"Pozycja została przeniesiona", + "item.edit.move.title":"Przenieś pozycję", + "item.edit.private.cancel":"Anuluj", + "item.edit.private.confirm":"Ukryj", + "item.edit.private.description":"Czy chcesz ukryć tę pozycję?", + "item.edit.private.error":"Wystąpił błąd podczas ukrywania pozycji", + "item.edit.private.header":"Ukryj pozycję: {{ id }}", + "item.edit.private.success":"Pozycja jest teraz ukryta", + "item.edit.public.cancel":"Anuluj", + "item.edit.public.confirm":"Upublicznij", + "item.edit.public.description":"Czy chcesz upublicznić tę pozycję?", + "item.edit.public.error":"Wystąpił błąd podczas upubliczniania pozycji", + "item.edit.public.header":"Upublicznij pozycję: {{ id }}", + "item.edit.public.success":"Pozycja jest teraz publiczna", + "item.edit.reinstate.cancel":"Anuluj", + "item.edit.reinstate.confirm":"Przywróć", + "item.edit.reinstate.description":"Czy chcesz przywrócić tę pozycję?", + "item.edit.reinstate.error":"Wystąpił błąd podczas przywracania pozycji", + "item.edit.reinstate.header":"Przywróć pozycję: {{ id }}", + "item.edit.reinstate.success":"Pozycja została przywrócona", + "item.edit.relationships.discard-button":"Odrzuć", + "item.edit.relationships.edit.buttons.add":"Dodaj", + "item.edit.relationships.edit.buttons.remove":"Usuń", + "item.edit.relationships.edit.buttons.undo":"Cofnij zmiany", + "item.edit.relationships.no-relationships":"Brak relacji", + "item.edit.relationships.notifications.discarded.content":"Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", + "item.edit.relationships.notifications.discarded.title":"Zmiany zostały cofnięte", + "item.edit.relationships.notifications.failed.title":"Wystąpił błąd podczas edytowania relacji", + "item.edit.relationships.notifications.outdated.content":"Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", + "item.edit.relationships.notifications.outdated.title":"Zmiany są nieaktualne", + "item.edit.relationships.notifications.saved.content":"Twoje zmiany w relacjach tej pozycji zostały zapisane.", + "item.edit.relationships.notifications.saved.title":"Relacje zostały zapisane", + "item.edit.relationships.reinstate-button":"Cofnij", + "item.edit.relationships.save-button":"Zapisz", + "item.edit.relationships.no-entity-type":"Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", + "item.edit.return":"Cofnij", + "item.edit.tabs.bitstreams.head":"Pliki", + "item.edit.tabs.bitstreams.title":"Edycja pozycji - pliki", + "item.edit.tabs.curate.head":"Administruj", + "item.edit.tabs.curate.title":"Edytowanie pozycji - administruj", + "item.edit.tabs.metadata.head":"Metadane", + "item.edit.tabs.metadata.title":"Edycja pozycji - metadane", + "item.edit.tabs.relationships.head":"Relacje", + "item.edit.tabs.relationships.title":"Edycja pozycja - relacje", + "item.edit.tabs.status.buttons.authorizations.button":"Dostępy...", + "item.edit.tabs.status.buttons.authorizations.label":"Określu dostęp do pozycji", + "item.edit.tabs.status.buttons.delete.button":"Usuń permanentnie", + "item.edit.tabs.status.buttons.delete.label":"Usuń pozycję permanentnie", + "item.edit.tabs.status.buttons.mappedCollections.button":"Zmapowane kolekcje", + "item.edit.tabs.status.buttons.mappedCollections.label":"Zarządzaj mapowanymi kolekcjami", + "item.edit.tabs.status.buttons.move.button":"Przenieś...", + "item.edit.tabs.status.buttons.move.label":"Przenieś pozycję do innej kolekcji", + "item.edit.tabs.status.buttons.private.button":"Ukryj...", + "item.edit.tabs.status.buttons.private.label":"Ukry pozycję", + "item.edit.tabs.status.buttons.public.button":"Upublicznij...", + "item.edit.tabs.status.buttons.public.label":"Upublicznij pozycję", + "item.edit.tabs.status.buttons.reinstate.button":"Przywróć...", + "item.edit.tabs.status.buttons.reinstate.label":"Przywróć pozycję", + "item.edit.tabs.status.buttons.unauthorized":"You're not authorized to perform this action", + "item.edit.tabs.status.buttons.withdraw.button":"Wycofaj...", + "item.edit.tabs.status.buttons.withdraw.label":"Wycofaj z repozytorium", + "item.edit.tabs.status.description":"Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", + "item.edit.tabs.status.head":"Status", + "item.edit.tabs.status.labels.handle":"Identyfikator", + "item.edit.tabs.status.labels.id":"ID pozycji", + "item.edit.tabs.status.labels.itemPage":"Strona pozycji", + "item.edit.tabs.status.labels.lastModified":"Ostatnia modyfikacja", + "item.edit.tabs.status.title":"Edycja pozycji - Status", + "item.edit.tabs.versionhistory.head":"Historia wersji", + "item.edit.tabs.versionhistory.title":"Edycja pozycji - historia wersji", + "item.edit.tabs.versionhistory.under-construction":"Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", + "item.edit.tabs.view.head":"Widok pozycji", + "item.edit.tabs.view.title":"Edycja pozycji - widok", + "item.edit.withdraw.cancel":"Anuluj", + "item.edit.withdraw.confirm":"Wycofaj", + "item.edit.withdraw.description":"Czy na pewno chcesz wycofać pozycję?", + "item.edit.withdraw.error":"Wystąpił błąd podczas wycofywania pozycji", + "item.edit.withdraw.header":"Wycofaj pozycję: {{ id }}", + "item.edit.withdraw.success":"Pozycja została wycofana", + "item.listelement.badge":"Pozycja", + "item.page.description":"Opis", + "item.page.journal-issn":"ISSN czasopisma", + "item.page.journal-title":"Tytuł czasopisma", + "item.page.publisher":"Wydawca", + "item.page.titleprefix":"Pozycja: ", + "item.page.volume-title":"Tytuł tomu", + "item.search.results.head":"Wyniki wyszukiwania pozycji", + "item.search.title":"Wyszukiwanie pozycji", + "item.page.abstract":"Abstrakt", + "item.page.author":"Autorzy", + "item.page.citation":"Cytowanie", + "item.page.collections":"Kolekcje", + "item.page.collections.loading":"Ładowanie...", + "item.page.collections.load-more":"Załaduj więcej", + "item.page.date":"Data", + "item.page.edit":"Edytuj pozycję", + "item.page.files":"Pliki", + "item.page.filesection.description":"Opis:", + "item.page.filesection.download":"Pobierz", + "item.page.filesection.format":"Format:", + "item.page.filesection.name":"Nazwa:", + "item.page.filesection.size":"Rozmiar:", + "item.page.journal.search.title":"Artykuły w czasopiśmie", + "item.page.link.full":"Zobacz szczegóły", + "item.page.link.simple":"Uproszczony widok", + "item.page.person.search.title":"Artykuły tego autora", + "item.page.related-items.view-more":"Pokaż o {{ amount }} więcej", + "item.page.related-items.view-less":"Ukryj {{ amount }}", + "item.page.relationships.isAuthorOfPublication":"Publikacje", + "item.page.relationships.isJournalOfPublication":"Publikacje", + "item.page.relationships.isOrgUnitOfPerson":"Autorzy", + "item.page.relationships.isOrgUnitOfProject":"Projekty naukowe", + "item.page.subject":"Słowa kluczowe", + "item.page.uri":"URI", + "item.page.bitstreams.view-more":"Pokaż więcej", + "item.page.bitstreams.collapse":"Pokaż mniej", + "item.page.filesection.original.bundle":"Oryginalne pliki", + "item.page.filesection.license.bundle":"Licencja", + "item.page.return":"Powrót", + "item.page.version.create":"Utwórz nową wersję", + "item.page.version.hasDraft":"Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.preview.dc.identifier.doi":"DOI", + "item.preview.dc.relation.ispartof":"Czasopismo lub seria", + "item.preview.dc.identifier.isbn":"ISBN", + "item.preview.dc.identifier.uri":"Identyfikator:", + "item.preview.dc.contributor.author":"Autorzy:", + "item.preview.dc.date.issued":"Data publikacji:", + "item.preview.dc.description.abstract":"Abstrakt:", + "item.preview.dc.identifier.other":"Inny identyfikator:", + "item.preview.dc.language.iso":"Język:", + "item.preview.dc.title":"Tytuł:", + "item.preview.dc.title.alternative":"Tytuł alternatywny", + "item.preview.dc.type":"Typ:", + "item.preview.dc.identifier":"Identyfikator:", + "item.preview.dc.relation.issn":"ISSN", + "item.preview.oaire.citation.issue":"Numer wydania", + "item.preview.oaire.citation.volume":"Numer tomu", + "item.preview.person.familyName":"Nazwisko:", + "item.preview.person.givenName":"Nazwa:", + "item.preview.person.identifier.orcid":"ORCID:", + "item.preview.project.funder.name":"Fundator:", + "item.preview.project.funder.identifier":"Identyfikator fundatora:", + "item.preview.oaire.awardNumber":"ID finansowania:", + "item.preview.dc.coverage.spatial":"Jurysdykcja:", + "item.preview.oaire.fundingStream":"Źródło finansowania:", + "item.select.confirm":"Potwierdź zaznaczone", + "item.select.empty":"Brak pozycji do wyświetlenia", + "item.select.table.author":"Autor", + "item.select.table.collection":"Kolekcja", + "item.select.table.title":"Tytuł", + "item.version.history.empty":"Jeszcze nie ma innych wersji tej pozycji.", + "item.version.history.head":"Poprzednie wersje", + "item.version.history.return":"Powrót", + "item.version.history.selected":"Wybrane wersje", + "item.version.history.selected.alert":"W tym momencie wyświetlono wersję {{version}} pozycji.", + "item.version.history.table.version":"Wersja", + "item.version.history.table.item":"Pozycja", + "item.version.history.table.editor":"Redaktor", + "item.version.history.table.date":"Data", + "item.version.history.table.summary":"Podsumowanie", + "item.version.history.table.workspaceItem":"Wersja robocza", + "item.version.history.table.workflowItem":"Pozycja workflow", + "item.version.history.table.actions":"Akcja", + "item.version.history.table.action.editWorkspaceItem":"Edytuj wersję roboczą pozycji", + "item.version.history.table.action.editSummary":"Edytuj podsumowanie", + "item.version.history.table.action.saveSummary":"Zapisz edycje podsumowania", + "item.version.history.table.action.discardSummary":"Odrzuć edycje podsumowania", + "item.version.history.table.action.newVersion":"Utwórz nową wersję z tej wersji", + "item.version.history.table.action.deleteVersion":"Wersja usunięta", + "item.version.history.table.action.hasDraft":"Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.version.notice":"To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", + "item.version.create.modal.header":"Nowa wersja", + "item.version.create.modal.text":"Utwórz nową wersję tej pozycji", + "item.version.create.modal.text.startingFrom":"zaczynając od wersji {{version}}", + "item.version.create.modal.button.confirm":"Utwórz", + "item.version.create.modal.button.confirm.tooltip":"Utwórz nową wersję", + "item.version.create.modal.button.cancel":"Anuluj", + "item.version.create.modal.button.cancel.tooltip":"Nie stwarzaj nowej wersji", + "item.version.create.modal.form.summary.label":"Podsumowanie", + "item.version.create.modal.form.summary.placeholder":"Wprowadź podsumowanie nowej wersji", + "item.version.create.notification.success":"Nowa wersja została utworzona z numerem {{version}}", + "item.version.create.notification.failure":"Nowa wersja nie została utworzona", + "item.version.create.notification.inProgress":"Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", + "item.version.delete.modal.header":"Usuń wersję", + "item.version.delete.modal.text":"Czy chcesz usunąć wersję {{version}}?", + "item.version.delete.modal.button.confirm":"Usuń", + "item.version.delete.modal.button.confirm.tooltip":"Usuń wersję", + "item.version.delete.modal.button.cancel":"Anuluj", + "item.version.delete.modal.button.cancel.tooltip":"Nie usuwaj tej wersji", + "item.version.delete.notification.success":"Wersja {{version}} została usunięta", + "item.version.delete.notification.failure":"Wersja {{version}} nie została usunięta", + "item.version.edit.notification.success":"Podsumowanie wersji {{version}} zostało zmienione", + "item.version.edit.notification.failure":"Podsumowanie wersji {{version}} nie zostało zmienione", + "journal.listelement.badge":"Czasopismo", + "journal.page.description":"Opis", + "journal.page.edit":"Edytuj tę pozycję", + "journal.page.editor":"Redaktor naczelny", + "journal.page.issn":"ISSN", + "journal.page.publisher":"Wydawca", + "journal.page.titleprefix":"Czasopismo: ", + "journal.search.results.head":"Wyniki wyszukiwania czasopism", + "journal.search.title":"Wyszukiwanie czasopism", + "journalissue.listelement.badge":"Numer czasopisma", + "journalissue.page.description":"Opis", + "journalissue.page.edit":"Edytuj pozycję", + "journalissue.page.issuedate":"Data wydania", + "journalissue.page.journal-issn":"ISSN czasopisma", + "journalissue.page.journal-title":"Tytuł czasopisma", + "journalissue.page.keyword":"Słowa kluczowe", + "journalissue.page.number":"Numer", + "journalissue.page.titleprefix":"Wydanie czasopisma: ", + "journalvolume.listelement.badge":"Numer tomu czasopisma", + "journalvolume.page.description":"Opis", + "journalvolume.page.edit":"Edytuj pozycję", + "journalvolume.page.issuedate":"Data wydania", + "journalvolume.page.titleprefix":"Numer tomu czasopisma: ", + "journalvolume.page.volume":"Numer wydania", + "iiifsearchable.listelement.badge":"Multimedia dokumentu", + "iiifsearchable.page.titleprefix":"Dokument: ", + "iiifsearchable.page.doi":"Stały link: ", + "iiifsearchable.page.issue":"Wydanie: ", + "iiifsearchable.page.description":"Opis: ", + "iiifviewer.fullscreen.notice":"Wyświetl na pełnym ekranie dla lepszego widoku.", + "iiif.listelement.badge":"Multimedia obrazu", + "iiif.page.titleprefix":"Obraz: ", + "iiif.page.doi":"Stały link: ", + "iiif.page.issue":"Numer wydania: ", + "iiif.page.description":"Opis: ", + "loading.bitstream":"Ładowanie pliku...", + "loading.bitstreams":"Ładowanie plików...", + "loading.browse-by":"Ładowanie pozycji...", + "loading.browse-by-page":"Ładowanie strony...", + "loading.collection":"Ładowanie kolekcji...", + "loading.collections":"Ładowanie kolekcji...", + "loading.content-source":"Ładowanie źródła treści...", + "loading.community":"Ładowanie zbioru...", + "loading.default":"Ładowanie...", + "loading.item":"Ładowanie pozycji...", + "loading.items":"Ładowanie pozycji...", + "loading.mydspace-results":"Ładowanie pozycji...", + "loading.objects":"Ładowanie...", + "loading.recent-submissions":"Ładowanie ostatnich zgłoszeń...", + "loading.search-results":"Ładowanie wyników wyszukiwania...", + "loading.sub-collections":"Ładowanie podkolekcji...", + "loading.sub-communities":"Ładowanie podzbioru...", + "loading.top-level-communities":"Ładowanie zbioru wyszego szczebla...", + "login.form.email":"Adres e-mail", + "login.form.forgot-password":"Nie pamiętasz hasła?", + "login.form.header":"Zaloguj się do DSpace", + "login.form.new-user":"Nie masz konta? Zarejestruj się.", + "login.form.or-divider":"lub", + "login.form.orcid":"Zaloguj za pomocą ORCID", + "login.form.oidc":"Zaloguj za pomocą OIDC", + "login.form.password":"Hasło", + "login.form.shibboleth":"Zaloguj za pomocą Shibboleth", + "login.form.submit":"Zaloguj się", + "login.title":"Zaloguj", + "login.breadcrumbs":"Zaloguj", + "logout.form.header":"Wyloguj się z DSpace", + "logout.form.submit":"Wyloguj się", + "logout.title":"Wylogowywanie", + "menu.header.admin":"Panel administracyjny", + "menu.header.image.logo":"Logo repozytorium", + "menu.header.admin.description":"Menu administratora", + "menu.section.access_control":"Uprawnienia", + "menu.section.access_control_authorizations":"Dostępy", + "menu.section.access_control_groups":"Grupy", + "menu.section.access_control_people":"Użytkownicy", + "menu.section.admin_search":"Wyszukiwanie administracyjne", + "menu.section.browse_community":"Ten zbiór", + "menu.section.browse_community_by_author":"Wg autorów", + "menu.section.browse_community_by_issue_date":"Wg daty wydania", + "menu.section.browse_community_by_title":"Wg tytułów", + "menu.section.browse_global":"Wszystko na DSpace", + "menu.section.browse_global_by_author":"Wg autorów", + "menu.section.browse_global_by_dateissued":"Wg daty wydania", + "menu.section.browse_global_by_subject":"Wg tematu", + "menu.section.browse_global_by_title":"Wg tytułu", + "menu.section.browse_global_communities_and_collections":"Zbiory i kolekcje", + "menu.section.control_panel":"Panel sterowania", + "menu.section.curation_task":"Zadanie administracyjne", + "menu.section.edit":"Edytuj", + "menu.section.edit_collection":"Kolekcja", + "menu.section.edit_community":"Zbiór", + "menu.section.edit_item":"Pozycja", + "menu.section.export":"Eksport", + "menu.section.export_collection":"Kolekcja", + "menu.section.export_community":"Zbiór", + "menu.section.export_item":"Pozycja", + "menu.section.export_metadata":"Metadane", + "menu.section.icon.access_control":"Sekcja menu Uprawnienia", + "menu.section.icon.admin_search":"Sekcja menu Wyszukiwanie administracyjne", + "menu.section.icon.control_panel":"Sekcja menu Panel sterowania", + "menu.section.icon.curation_tasks":"Sekcja menu Zadanie administracyjne", + "menu.section.icon.edit":"Sekcja menu Edycja", + "menu.section.icon.export":"Sekcja menu Eksport", + "menu.section.icon.find":"Sekcja menu Wyszukiwanie", + "menu.section.icon.import":"Sekcja menu Import", + "menu.section.icon.new":"Sekcja menu Dodaj", + "menu.section.icon.pin":"Przypnij boczny pasek", + "menu.section.icon.processes":"Sekcja menu Procesy", + "menu.section.icon.registries":"Sekcja menu Rejestry", + "menu.section.icon.statistics_task":"Sekcja menu Zadanie statystyczne", + "menu.section.icon.workflow":"Sekcja menu Zarządzanie workflow", + "menu.section.icon.unpin":"Odepnij boczny pasek", + "menu.section.import":"Import", + "menu.section.import_batch":"Import masowy (ZIP)", + "menu.section.import_metadata":"Metadane", + "menu.section.new":"Dodaj", + "menu.section.new_collection":"Kolekcja", + "menu.section.new_community":"Zbiór", + "menu.section.new_item":"Pozycja", + "menu.section.new_item_version":"Wersja pozycji", + "menu.section.new_process":"Proces", + "menu.section.pin":"Przypnij pasek boczny", + "menu.section.unpin":"Odepnij pasek boczny", + "menu.section.processes":"Procesy", + "menu.section.registries":"Rejestry", + "menu.section.registries_format":"Formaty", + "menu.section.registries_metadata":"Metadane", + "menu.section.statistics":"Statystyki", + "menu.section.statistics_task":"Zadanie statystyczne", + "menu.section.toggle.access_control":"Przełącz sekcję Uprawnienia", + "menu.section.toggle.control_panel":"Przełącz sekcję Panel sterowania", + "menu.section.toggle.curation_task":"Przełącz sekcję Zadanie kuratora", + "menu.section.toggle.edit":"Przełącz sekcję Edytuj", + "menu.section.toggle.export":"Przełącz sekcję Eksport", + "menu.section.toggle.find":"Przełącz sekcję Wyszukiwanie", + "menu.section.toggle.import":"Przełącz sekcję Import", + "menu.section.toggle.new":"Przełącz nową sekcję", + "menu.section.toggle.registries":"Przełącz sekcję Rejestry", + "menu.section.toggle.statistics_task":"Przełącz sekcję Zadanie statystyczne", + "menu.section.workflow":"Zarządzaj Workflow", + "mydspace.breadcrumbs":"Mój DSpace", + "mydspace.description":"", + "mydspace.messages.controller-help":"Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", + "mydspace.messages.description-placeholder":"Wpisz swoją wiadomość tutaj...", + "mydspace.messages.hide-msg":"Ukryj wiadomość", + "mydspace.messages.mark-as-read":"Oznacz jako przeczytane", + "mydspace.messages.mark-as-unread":"Oznacz jako nieprzeczytane", + "mydspace.messages.no-content":"Brak treści.", + "mydspace.messages.no-messages":"Brak wiadomości.", + "mydspace.messages.send-btn":"Wysłano", + "mydspace.messages.show-msg":"Pokaż wiadomość", + "mydspace.messages.subject-placeholder":"Temat...", + "mydspace.messages.submitter-help":"Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", + "mydspace.messages.title":"Wiadomości", + "mydspace.messages.to":"Do", + "mydspace.new-submission":"Nowe zgłoszenie", + "mydspace.new-submission-external":"Import medatanych z zewnętrznego źródła", + "mydspace.new-submission-external-short":"Import metadanych", + "mydspace.results.head":"Twoje zadania", + "mydspace.results.no-abstract":"Brak abstraktu", + "mydspace.results.no-authors":"Brak autorów", + "mydspace.results.no-collections":"Brak kolekcji", + "mydspace.results.no-date":"Brak daty", + "mydspace.results.no-files":"Brak plików", + "mydspace.results.no-results":"Brak pozycji do wyświetlenia", + "mydspace.results.no-title":"Brak tytułu", + "mydspace.results.no-uri":"Brak Uri", + "mydspace.search-form.placeholder":"Wyszukaj w mydspace...", + "mydspace.show.workflow":"Wszystkie zadania", + "mydspace.show.workspace":"Twoje zadania", + "mydspace.status.mydspaceArchived":"Zarchiwizowano", + "mydspace.status.mydspaceValidation":"Walidacja", + "mydspace.status.mydspaceWaitingController":"Oczekiwanie na redaktora", + "mydspace.status.mydspaceWorkflow":"Workflow", + "mydspace.status.mydspaceWorkspace":"Wersja robocza", + "mydspace.title":"Mój DSpace", + "mydspace.upload.upload-failed":"Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", + "mydspace.upload.upload-failed-manyentries":"Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", + "mydspace.upload.upload-failed-moreonefile":"Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", + "mydspace.upload.upload-multiple-successful":"Utworzono {{qty}} przestrzeni roboczych.", + "mydspace.view-btn":"Widok", + "nav.browse.header":"Cały DSpace", + "nav.community-browse.header":"Wg zbiorów", + "nav.language":"Zmień język", + "nav.login":"Zaloguj", + "nav.logout":"Menu profilu użytkownika i wylogowywanie", + "nav.main.description":"Główny pasek nawigacji", + "nav.mydspace":"Mój DSpace", + "nav.profile":"Profil", + "nav.search":"Wyszukiwanie", + "nav.statistics.header":"Statystyki", + "nav.stop-impersonating":"Przestań impersonifikować użytkownika", + "nav.toggle":"Przełącz nawigację", + "nav.user.description":"Pasek profilu użytkownika", + "none.listelement.badge":"Pozycja", + "person.listelement.badge":"Osoba", + "person.listelement.no-title":"Nie znaleziono imienia", + "person.page.birthdate":"Data urodzenia", + "person.page.edit":"Edytuj pozycję", + "person.page.email":"Adres e-mail", + "person.page.firstname":"Imię", + "person.page.jobtitle":"Stanowisko", + "person.page.lastname":"Nazwisko", + "person.page.link.full":"Pokaż wszystkie metadane", + "person.page.orcid":"ORCID", + "person.page.orcid.create":"Utwórz ORCID ID", + "person.page.orcid.granted-authorizations":"Udzielone dostępy", + "person.page.orcid.grant-authorizations":"Udziel dostępu", + "person.page.orcid.link":"Połącz z ORCID ID", + "person.page.orcid.orcid-not-linked-message":"ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", + "person.page.orcid.unlink":"Odepnij z ORCID", + "person.page.orcid.unlink.processing":"Procesowanie...", + "person.page.orcid.missing-authorizations":"Brak dostępów", + "person.page.orcid.missing-authorizations-message":"Brakuj następujących dostępów:", + "person.page.orcid.no-missing-authorizations-message":"Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", + "person.page.orcid.no-orcid-message":"Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", + "person.page.orcid.profile-preferences":"Preferencje profilu", + "person.page.orcid.funding-preferences":"Preferencje finansowania", + "person.page.orcid.publications-preferences":"Preferencje publikacji", + "person.page.orcid.remove-orcid-message":"Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", + "person.page.orcid.save.preference.changes":"Aktualizuj ustawienia", + "person.page.orcid.sync-profile.affiliation":"Afiliacja", + "person.page.orcid.sync-profile.biographical":"Biografia", + "person.page.orcid.sync-profile.education":"Edukacja", + "person.page.orcid.sync-profile.identifiers":"Identyfikatory", + "person.page.orcid.sync-fundings.all":"Wszystkie źrodła finansowania", + "person.page.orcid.sync-fundings.mine":"Moje źrodła finansowania", + "person.page.orcid.sync-fundings.my_selected":"Wybrane źródła finansowania", + "person.page.orcid.sync-fundings.disabled":"Nieaktywne", + "person.page.orcid.sync-publications.all":"Wszystkie publikacje", + "person.page.orcid.sync-publications.mine":"Moje publikacje", + "person.page.orcid.sync-publications.my_selected":"Wybrane publikacje", + "person.page.orcid.sync-publications.disabled":"Nieaktywne", + "person.page.orcid.sync-queue.discard":"Odrzuć zmianę i nie synchronizuj z ORCID", + "person.page.orcid.sync-queue.discard.error":"Rekord kolejki ORCID nie został odrzucony", + "person.page.orcid.sync-queue.discard.success":"Rekord kolejki ORCID został odrzucony", + "person.page.orcid.sync-queue.empty-message":"Rejestr kolejki w ORCID jest pusty", + "person.page.orcid.sync-queue.description.affiliation":"Afiliacje", + "person.page.orcid.sync-queue.description.country":"Kraj", + "person.page.orcid.sync-queue.description.education":"Edukacja", + "person.page.orcid.sync-queue.description.external_ids":"Zewnętrzne identyfikatory", + "person.page.orcid.sync-queue.description.other_names":"Inne imiona", + "person.page.orcid.sync-queue.description.qualification":"Kwalifikacje", + "person.page.orcid.sync-queue.description.researcher_urls":"URL naukowca", + "person.page.orcid.sync-queue.description.keywords":"Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.insert":"Dodaj nowy wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.update":"Aktualizuj ten wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.delete":"Usuń ten wpis z rejestru ORCID", + "person.page.orcid.sync-queue.tooltip.publication":"Publikacja", + "person.page.orcid.sync-queue.tooltip.affiliation":"Afiliacja", + "person.page.orcid.sync-queue.tooltip.education":"Edukacja", + "person.page.orcid.sync-queue.tooltip.qualification":"Kwalifikacje", + "person.page.orcid.sync-queue.tooltip.other_names":"Inna nazwa", + "person.page.orcid.sync-queue.tooltip.country":"Kraj", + "person.page.orcid.sync-queue.tooltip.keywords":"Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.external_ids":"Zewnętrzny identyfikator", + "person.page.orcid.sync-queue.tooltip.researcher_urls":"URL naukowca", + "person.page.orcid.sync-queue.send":"Synchronizuj z rejestrem ORCID", + "person.page.orcid.sync-queue.send.unauthorized-error.title":"Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", + "person.page.orcid.sync-queue.send.unauthorized-error.content":"Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", + "person.page.orcid.sync-queue.send.bad-request-error":"Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", + "person.page.orcid.sync-queue.send.error":"Wysłanie zgłoszenia do ORCID nie powiodło się", + "person.page.orcid.sync-queue.send.conflict-error":"Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", + "person.page.orcid.sync-queue.send.not-found-warning":"Pozycja nie istnieje już w rejestrze ORCID.", + "person.page.orcid.sync-queue.send.success":"Zgłoszenie do ORCID zostało zakończone pomyślnie", + "person.page.orcid.sync-queue.send.validation-error":"Dane, które chcesz zsynchronizować z ORCID nie są poprawne", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required":"Waluta jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.external-id.required":"Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", + "person.page.orcid.sync-queue.send.validation-error.title.required":"Tytuł jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.type.required":"Typ jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.start-date.required":"Data początkowa jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.funder.required":"Instytucja finansująca jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.required":"Instytucja jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required":"Nazwa instytucji jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required":"Aby wysłać instytucję, należy podać adres", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required":"Aby wysłać adres, należy podać miasto", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required":"Aby wysłać adres, należy podać kraj", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required":"Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required":"Należy uzupełnić wartość w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required":"Należy uzupełnić źródło w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid":"Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", + "person.page.orcid.synchronization-mode":"Tryb synchronizacji", + "person.page.orcid.synchronization-mode.batch":"Wsad", + "person.page.orcid.synchronization-mode.label":"Tryb synchronizacji", + "person.page.orcid.synchronization-mode-message":"Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", + "person.page.orcid.synchronization-settings-update.success":"Opcje synchronizacji zostały zaktualizowane", + "person.page.orcid.synchronization-settings-update.error":"Opcje synchronizacji nie zostały zaktualizowane", + "person.page.orcid.synchronization-mode.manual":"Ręczna", + "person.page.orcid.scope.authenticate":"Uzyskaj swój ORCID iD", + "person.page.orcid.scope.read-limited":"Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", + "person.page.orcid.scope.activities-update":"Dodaj/aktualizuj swoje aktywności naukowe", + "person.page.orcid.scope.person-update":"Dodaj/aktualizuj inne informacje o Tobie", + "person.page.orcid.unlink.success":"Odłączenie Twojego profilu od rejestru ORCID powiodło się", + "person.page.orcid.unlink.error":"Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", + "person.page.staffid":"ID pracownika", + "person.page.titleprefix":"Osoba: ", + "person.search.results.head":"Wyniki wyszukiwania użytkowników", + "person.search.title":"Wyniki wyszukiwania użytkowników", + "process.new.select-parameters":"Parametry", + "process.new.cancel":"Anuluj", + "process.new.submit":"Zapisz", + "process.new.select-script":"Skrypt", + "process.new.select-script.placeholder":"Wybierz skrypt...", + "process.new.select-script.required":"Skrypt jest wymagany", + "process.new.parameter.file.upload-button":"Wybierz plik...", + "process.new.parameter.file.required":"Proszę wybrać plik", + "process.new.parameter.string.required":"Wartość parametru jest wymagana", + "process.new.parameter.type.value":"wartość", + "process.new.parameter.type.file":"plik", + "process.new.parameter.required.missing":"Te parametry są wymagane, ale nie zostały uzupełnione:", + "process.new.notification.success.title":"Udało się", + "process.new.notification.success.content":"Udało się stworzyć proces", + "process.new.notification.error.title":"Błąd", + "process.new.notification.error.content":"Wystąpił błąd podczas tworzenia procesu", + "process.new.header":"Utwórz nowy proces", + "process.new.title":"Utwórz nowy proces", + "process.new.breadcrumbs":"Utwórz nowy proces", + "process.detail.arguments":"Argumenty", + "process.detail.arguments.empty":"Do tego procesu nie zostały przypisane żadne argumenty", + "process.detail.back":"Cofnij", + "process.detail.output":"Dane wyjściowe procesu", + "process.detail.logs.button":"Odzyskaj dane wyjściowe procesu", + "process.detail.logs.loading":"Odzyskiwanie", + "process.detail.logs.none":"Ten proces nie ma danych wyjściowych", + "process.detail.output-files":"Pliki", + "process.detail.output-files.empty":"Ten proces nie ma żadnych plików danych wyjściowych", + "process.detail.script":"Skrypt", + "process.detail.title":"Proces: {{ id }} - {{ name }}", + "process.detail.start-time":"Czas rozpoczęcia procesu", + "process.detail.end-time":"Czas zakończenia procesu", + "process.detail.status":"Status", + "process.detail.create":"Stwórz podobny proces", + "process.overview.table.finish":"Czas zakończenia (UTC)", + "process.overview.table.id":"Identyfikator procesu", + "process.overview.table.name":"Nazwa", + "process.overview.table.start":"Czas rozpoczęcia (UTC)", + "process.overview.table.status":"Status", + "process.overview.table.user":"Użytkownik", + "process.overview.title":"Przegląd procesów", + "process.overview.breadcrumbs":"Przegląd procesów", + "process.overview.new":"Nowy", + "profile.breadcrumbs":"Zaktualizuj profil", + "profile.card.identify":"Dane", + "profile.card.security":"Bezpieczeństwo", + "profile.form.submit":"Zaktualizuj profil", + "profile.groups.head":"Posiadane uprawnienia do kolekcji", + "profile.head":"Zaktualizuj profil", + "profile.metadata.form.error.firstname.required":"Imię jest wymagane", + "profile.metadata.form.error.lastname.required":"Nazwisko jest wymagane", + "profile.metadata.form.label.email":"Adres e-mail", + "profile.metadata.form.label.firstname":"Imię", + "profile.metadata.form.label.language":"Język", + "profile.metadata.form.label.lastname":"Nazwisko", + "profile.metadata.form.label.phone":"Telefon kontaktowy", + "profile.metadata.form.notifications.success.content":"Zmiany w profilu zostały zapisane.", + "profile.metadata.form.notifications.success.title":"Profil zapisany", + "profile.notifications.warning.no-changes.content":"Nie dokonano żadnych zmian w profilu.", + "profile.notifications.warning.no-changes.title":"Brak zmian", + "profile.security.form.error.matching-passwords":"Hasła nie są identyczne.", + "profile.security.form.info":"Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", + "profile.security.form.label.password":"Hasło", + "profile.security.form.label.passwordrepeat":"Potwierdź hasło", + "profile.security.form.notifications.success.content":"Twoje zmiany w haśle zostały zapisane.", + "profile.security.form.notifications.success.title":"Hasło zapisane", + "profile.security.form.notifications.error.title":"Błąd podczas próby zmiany hasła", + "profile.security.form.notifications.error.not-same":"Hasła nie są identyczne.", + "profile.title":"Zaktualizuj profil", + "profile.card.researcher":"Profil naukowca", + "project.listelement.badge":"Projekt badawczy", + "project.page.contributor":"Autorzy", + "project.page.description":"Opis", + "project.page.edit":"Edytuj pozycję", + "project.page.expectedcompletion":"Spodziewany termin zakończenia", + "project.page.funder":"Instytucje finansujące", + "project.page.id":"ID", + "project.page.keyword":"Słowa kluczowe", + "project.page.status":"Status", + "project.page.titleprefix":"Projekt badawczy: ", + "project.search.results.head":"Wyniki wyszukiwania projektów", + "publication.listelement.badge":"Publikacja", + "publication.page.description":"Opis", + "publication.page.edit":"Edytuj pozycję", + "publication.page.journal-issn":"ISSN czasopisma", + "publication.page.journal-title":"Tytuł czasopisma", + "publication.page.publisher":"Wydawca", + "publication.page.titleprefix":"Publikacja: ", + "publication.page.volume-title":"Tytuł tomu", + "publication.search.results.head":"Wyniki wyszukiwania publikacji", + "publication.search.title":"Wyszukiwanie publikacji", + "media-viewer.next":"Nowy", + "media-viewer.previous":"Poprzedni", + "media-viewer.playlist":"Playlista", + "register-email.title":"Rejestracja nowego użytkownika", + "register-page.create-profile.header":"Stwórz profil", + "register-page.create-profile.identification.header":"Dane", + "register-page.create-profile.identification.email":"Adres e-mail", + "register-page.create-profile.identification.first-name":"Imię *", + "register-page.create-profile.identification.first-name.error":"Wpisz imię", + "register-page.create-profile.identification.last-name":"Nazwisko *", + "register-page.create-profile.identification.last-name.error":"Wpisz nazwisko", + "register-page.create-profile.identification.contact":"Telefon kontaktowy", + "register-page.create-profile.identification.language":"Język", + "register-page.create-profile.security.header":"Bezpieczeństwo", + "register-page.create-profile.security.info":"Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", + "register-page.create-profile.security.label.password":"Hasło *", + "register-page.create-profile.security.label.passwordrepeat":"Potwierdź hasło *", + "register-page.create-profile.security.error.empty-password":"Wprowadź hasło w polu poniżej.", + "register-page.create-profile.security.error.matching-passwords":"Hasła nie są identyczne.", + "register-page.create-profile.submit":"Rejestracja zakończona", + "register-page.create-profile.submit.error.content":"Coś się nie udało podczas rejestracji nowego użytkownika.", + "register-page.create-profile.submit.error.head":"Rejestracja nie powiodła się", + "register-page.create-profile.submit.success.content":"Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", + "register-page.create-profile.submit.success.head":"Rejestracja zakończona", + "register-page.registration.header":"Rejestracja nowego użytkownika", + "register-page.registration.info":"Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "register-page.registration.email":"Adres e-mail *", + "register-page.registration.email.error.required":"Wypełnij adres e-mail", + "register-page.registration.email.error.pattern":"Wypełnij poprawny adres e-mail", + "register-page.registration.email.hint":"Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "register-page.registration.submit":"Zarejestruj się", + "register-page.registration.success.head":"Wiadomość weryfikacyjna zostałą wysłana", + "register-page.registration.success.content":"Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "register-page.registration.error.head":"Błąd podczas próby rejestracji adresu e-mail", + "register-page.registration.error.content":"Błąd podczas próby rejestracji adresu e-mail: {{ email }}", + "relationships.add.error.relationship-type.content":"Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", + "relationships.add.error.server.content":"Błąd serwera", + "relationships.add.error.title":"Nie można dodać relacji", + "relationships.isAuthorOf":"Autorzy", + "relationships.isAuthorOf.Person":"Autorzy (osoby)", + "relationships.isAuthorOf.OrgUnit":"Autorzy (jednostki organizacyjne)", + "relationships.isIssueOf":"Numery czasopisma", + "relationships.isJournalIssueOf":"Numer czasopisma", + "relationships.isJournalOf":"Czasopisma", + "relationships.isOrgUnitOf":"Jednostki organizacyjne", + "relationships.isPersonOf":"Autorzy", + "relationships.isProjectOf":"Projekty badawcze", + "relationships.isPublicationOf":"Publikacje", + "relationships.isPublicationOfJournalIssue":"Artykuły", + "relationships.isSingleJournalOf":"Czasopismo", + "relationships.isSingleVolumeOf":"Tom czasopisma", + "relationships.isVolumeOf":"Tomy czasopisma", + "relationships.isContributorOf":"Autorzy", + "relationships.isContributorOf.OrgUnit":"Autor (Jednostka organizacyjna)", + "relationships.isContributorOf.Person":"Autor", + "relationships.isFundingAgencyOf.OrgUnit":"Instytucja finansująca", + "repository.image.logo":"Logo repozytorium", + "repository.title.prefix":"DSpace Angular :: ", + "researcher.profile.action.processing":"Procesowanie...", + "researcher.profile.associated":"Przypisanie profilu badacza", + "researcher.profile.create.new":"Utwórz nowy", + "researcher.profile.create.success":"Profil badacza został utworzony", + "researcher.profile.create.fail":"Wystąpił błąd poczas tworzenia profilu badacza.", + "researcher.profile.delete":"Usuń", + "researcher.profile.expose":"Ujawnij", + "researcher.profile.hide":"Ukryj", + "researcher.profile.not.associated":"Profil badacza nie został jeszcze przypisany", + "researcher.profile.view":"Widok", + "researcher.profile.private.visibility":"PRYWATNY", + "researcher.profile.public.visibility":"PUBLICZNY", + "researcher.profile.status":"Status:", + "researcherprofile.claim.not-authorized":"Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", + "researcherprofile.error.claim.body":"Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", + "researcherprofile.error.claim.title":"Błąd", + "researcherprofile.success.claim.body":"Wystąpienie z prośbą o przypisanie profilu udane", + "researcherprofile.success.claim.title":"Sukces", + "repository.title.prefixDSpace":"DSpace Angular ::", + "resource-policies.add.button":"Dodaj", + "resource-policies.add.for.":"Dodaj nową politykę", + "resource-policies.add.for.bitstream":"Dodaj nową politykę dla plików", + "resource-policies.add.for.bundle":"Dodaj nową politykę paczek", + "resource-policies.add.for.item":"Dodaj nową politykę pozycji", + "resource-policies.add.for.community":"Dodaj nową politykę zbioru", + "resource-policies.add.for.collection":"Dodaj nową politykę kolekcji", + "resource-policies.create.page.heading":"Utwórz nową politykę zasobu dla ", + "resource-policies.create.page.failure.content":"Wystąpił błąd podczas dodawania polityki zasobów.", + "resource-policies.create.page.success.content":"Działanie powiodło się", + "resource-policies.create.page.title":"Utwórz nową politykę zasobu", + "resource-policies.delete.btn":"Usuń zaznaczone", + "resource-policies.delete.btn.title":"Usuń zaznaczone polityki zasobów", + "resource-policies.delete.failure.content":"Wystąpił błąd podczas usuwania wybranych polityk zasobów.", + "resource-policies.delete.success.content":"Działanie powiodło się", + "resource-policies.edit.page.heading":"Edytuj politykę zasobu ", + "resource-policies.edit.page.failure.content":"Wystąpił błąd poczas edytowania polityki zasobu.", + "resource-policies.edit.page.success.content":"Działanie udało się", + "resource-policies.edit.page.title":"Edytuj politykę zasobu", + "resource-policies.form.action-type.label":"Wybierz ten typ akcji", + "resource-policies.form.action-type.required":"Musisz wybrać akcję polityki zasobu.", + "resource-policies.form.eperson-group-list.label":"Użytkownik lub grupa, która otrzyma uprawnienia.", + "resource-policies.form.eperson-group-list.select.btn":"Wybierz", + "resource-policies.form.eperson-group-list.tab.eperson":"Wyszukaj użytkownika", + "resource-policies.form.eperson-group-list.tab.group":"Wyszukaj grupę", + "resource-policies.form.eperson-group-list.table.headers.action":"Akcja", + "resource-policies.form.eperson-group-list.table.headers.id":"ID", + "resource-policies.form.eperson-group-list.table.headers.name":"Nazwa", + "resource-policies.form.date.end.label":"Data zakończenia", + "resource-policies.form.date.start.label":"Data rozpoczęcia", + "resource-policies.form.description.label":"Opis", + "resource-policies.form.name.label":"Nazwa", + "resource-policies.form.policy-type.label":"Wybierz typ polityki", + "resource-policies.form.policy-type.required":"Musisz wybrać typ polityki zasobu.", + "resource-policies.table.headers.action":"Akcja", + "resource-policies.table.headers.date.end":"Data zakończenia", + "resource-policies.table.headers.date.start":"Data rozpoczęcia", + "resource-policies.table.headers.edit":"Edytuj", + "resource-policies.table.headers.edit.group":"Edytuj grupę", + "resource-policies.table.headers.edit.policy":"Edytuj politykę", + "resource-policies.table.headers.eperson":"Użytkownik", + "resource-policies.table.headers.group":"Grupa", + "resource-policies.table.headers.id":"ID", + "resource-policies.table.headers.name":"Nazwa", + "resource-policies.table.headers.policyType":"typ", + "resource-policies.table.headers.title.for.bitstream":"Polityki dla plików", + "resource-policies.table.headers.title.for.bundle":"Polityki dla paczek", + "resource-policies.table.headers.title.for.item":"Polityki dla pozycji", + "resource-policies.table.headers.title.for.community":"Polityki dla zbioru", + "resource-policies.table.headers.title.for.collection":"Polityki dla kolekcji", + "search.description":"", + "search.switch-configuration.title":"Pokaż", + "search.title":"Szukaj", + "search.breadcrumbs":"Szukaj", + "search.search-form.placeholder":"Szukaj w repozytorium...", + "search.filters.applied.f.author":"Autor", + "search.filters.applied.f.dateIssued.max":"Data zakończenia", + "search.filters.applied.f.dateIssued.min":"Data rozpoczęcia", + "search.filters.applied.f.dateSubmitted":"Data zgłoszenia", + "search.filters.applied.f.discoverable":"Ukryty", + "search.filters.applied.f.entityType":"Typ pozycji", + "search.filters.applied.f.has_content_in_original_bundle":"Ma przypisane pliki", + "search.filters.applied.f.itemtype":"Typ", + "search.filters.applied.f.namedresourcetype":"Status", + "search.filters.applied.f.subject":"Temat", + "search.filters.applied.f.submitter":"Zgłaszający", + "search.filters.applied.f.jobTitle":"Stanowisko", + "search.filters.applied.f.birthDate.max":"Data zakończenia tworzenia", + "search.filters.applied.f.birthDate.min":"Data rozpoczęcia tworzenia", + "search.filters.applied.f.withdrawn":"Wycofane", + "search.filters.filter.author.head":"Autor", + "search.filters.filter.author.placeholder":"Autor", + "search.filters.filter.author.label":"Wyszukaj autora", + "search.filters.filter.birthDate.head":"Data urodzenia", + "search.filters.filter.birthDate.placeholder":"Data urodzenia", + "search.filters.filter.birthDate.label":"Wyszukaj datę urodzenia", + "search.filters.filter.collapse":"Ukryj filtr", + "search.filters.filter.creativeDatePublished.head":"Data opublikowania", + "search.filters.filter.creativeDatePublished.placeholder":"Data opublikowania", + "search.filters.filter.creativeDatePublished.label":"Wyszukaj datę opublikowania", + "search.filters.filter.creativeWorkEditor.head":"Redaktor", + "search.filters.filter.creativeWorkEditor.placeholder":"Redaktor", + "search.filters.filter.creativeWorkEditor.label":"Wyszukaj redaktora", + "search.filters.filter.creativeWorkKeywords.head":"Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.placeholder":"Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.label":"Wyszukaj temat", + "search.filters.filter.creativeWorkPublisher.head":"Wydawca", + "search.filters.filter.creativeWorkPublisher.placeholder":"Wydawca", + "search.filters.filter.creativeWorkPublisher.label":"Wyszukaj wydawcę", + "search.filters.filter.dateIssued.head":"Data", + "search.filters.filter.dateIssued.max.placeholder":"Data maksymalna", + "search.filters.filter.dateIssued.max.label":"Koniec", + "search.filters.filter.dateIssued.min.placeholder":"Data minimalna", + "search.filters.filter.dateIssued.min.label":"Start", + "search.filters.filter.dateSubmitted.head":"Data zgłoszenia", + "search.filters.filter.dateSubmitted.placeholder":"Data zgłoszenia", + "search.filters.filter.dateSubmitted.label":"Wyszukaj datę zgłoszenia", + "search.filters.filter.discoverable.head":"Ukryty", + "search.filters.filter.withdrawn.head":"Wycofane", + "search.filters.filter.entityType.head":"Typ pozycji", + "search.filters.filter.entityType.placeholder":"Typ pozycji", + "search.filters.filter.entityType.label":"Wyszukaj typ pozycji", + "search.filters.filter.expand":"Rozwiń filtr", + "search.filters.filter.has_content_in_original_bundle.head":"Ma przypisane pliki", + "search.filters.filter.itemtype.head":"Typ", + "search.filters.filter.itemtype.placeholder":"Typ", + "search.filters.filter.itemtype.label":"Wyszukaj typ", + "search.filters.filter.jobTitle.head":"Stanowisko", + "search.filters.filter.jobTitle.placeholder":"Stanowisko", + "search.filters.filter.jobTitle.label":"Wyszukaj stanowisko", + "search.filters.filter.knowsLanguage.head":"Znajomość języka", + "search.filters.filter.knowsLanguage.placeholder":"Znajomość języka", + "search.filters.filter.knowsLanguage.label":"Wyszukaj wg znajomości języka", + "search.filters.filter.namedresourcetype.head":"Status", + "search.filters.filter.namedresourcetype.placeholder":"Status", + "search.filters.filter.namedresourcetype.label":"Wyszukaj status", + "search.filters.filter.objectpeople.head":"Osoby", + "search.filters.filter.objectpeople.placeholder":"Osoby", + "search.filters.filter.objectpeople.label":"Wyszukaj użytkowników", + "search.filters.filter.organizationAddressCountry.head":"Kraj", + "search.filters.filter.organizationAddressCountry.placeholder":"Kraj", + "search.filters.filter.organizationAddressCountry.label":"Wyszukaj kraj", + "search.filters.filter.organizationAddressLocality.head":"Miasto", + "search.filters.filter.organizationAddressLocality.placeholder":"Miasto", + "search.filters.filter.organizationAddressLocality.label":"Wyszukaj miasto", + "search.filters.filter.organizationFoundingDate.head":"Data założenia", + "search.filters.filter.organizationFoundingDate.placeholder":"Data założenia", + "search.filters.filter.organizationFoundingDate.label":"Wyszukaj datę założenia", + "search.filters.filter.scope.head":"Zakres", + "search.filters.filter.scope.placeholder":"Filtr zakresu", + "search.filters.filter.scope.label":"Wyszukaj filtr zakresu", + "search.filters.filter.show-less":"Pokaż mniej", + "search.filters.filter.show-more":"Pokaż więcej", + "search.filters.filter.subject.head":"Temat", + "search.filters.filter.subject.placeholder":"Temat", + "search.filters.filter.subject.label":"Wyszukaj temat", + "search.filters.filter.submitter.head":"Zgłaszający", + "search.filters.filter.submitter.placeholder":"Zgłaszający", + "search.filters.filter.submitter.label":"Wyszukaj zgłaszającego", + "search.filters.entityType.JournalIssue":"Numer czasopisma", + "search.filters.entityType.JournalVolume":"Tom czasopisma", + "search.filters.entityType.OrgUnit":"Jednostka organizacyjna", + "search.filters.has_content_in_original_bundle.true":"Tak", + "search.filters.has_content_in_original_bundle.false":"Nie", + "search.filters.discoverable.true":"Nie", + "search.filters.discoverable.false":"Tak", + "search.filters.withdrawn.true":"Tak", + "search.filters.withdrawn.false":"Nie", + "search.filters.head":"Filtry", + "search.filters.reset":"Resetuj filtry", + "search.filters.search.submit":"Zastosuj", + "search.form.search":"Wyszukaj", + "search.form.search_dspace":"W repozytorium", + "search.form.scope.all":"W całym DSpace", + "search.results.head":"Wyniki wyszukiwania", + "default.search.results.head":"Wyniki wyszukiwania", + "search.results.no-results":"Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", + "search.results.no-results-link":"fraz podobnych do Twojego wyszukiwania", + "search.results.empty":"Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", + "search.sidebar.close":"Wróć do wyników wyszukiwania", + "search.sidebar.filters.title":"Filtry", + "search.sidebar.open":"Narzędzia wyszukiwania", + "search.sidebar.results":"wyniki", + "search.sidebar.settings.rpp":"Wyników na stronie", + "search.sidebar.settings.sort-by":"Sortuj według", + "search.sidebar.settings.title":"Ustawienia", + "search.view-switch.show-detail":"Wyświetl widok szczegółowy", + "search.view-switch.show-grid":"Wyświetl jako siatkę", + "search.view-switch.show-list":"Wyświetl jako listę", + "sorting.ASC":"Rosnąco", + "sorting.DESC":"Malejąco", + "sorting.dc.title.ASC":"Tytułami rosnąco", + "sorting.dc.title.DESC":"Tytułami malejąco", + "sorting.score.ASC":"Najmniej trafne", + "sorting.score.DESC":"Najbardziej trafne", + "sorting.dc.date.issued.ASC":"Data wydania rosnąco", + "sorting.dc.date.issued.DESC":"Data wydania malejąco", + "sorting.dc.date.accessioned.ASC":"Data dostępu rosnąco", + "sorting.dc.date.accessioned.DESC":"Data dostępu malejąco", + "sorting.lastModified.ASC":"Ostatnia modyfikacja rosnąco", + "sorting.lastModified.DESC":"Ostatnia modyfikacja malejąco", + "statistics.title":"Statystyki", + "statistics.header":"Statystyki dla {{ scope }}", + "statistics.breadcrumbs":"Statystyki", + "statistics.page.no-data":"Brak dostępnych danych", + "statistics.table.no-data":"Brak dostępnych danych", + "statistics.table.header.views":"Wyświetlenia", + "submission.edit.breadcrumbs":"Edytuj zgłoszenie", + "submission.edit.title":"Edytuj zgłoszenie", + "submission.general.cancel":"Anuluj", + "submission.general.cannot_submit":"Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", + "submission.general.deposit":"Deponuj", + "submission.general.discard.confirm.cancel":"Anuluj", + "submission.general.discard.confirm.info":"Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.general.discard.confirm.submit":"Tak, na pewno", + "submission.general.discard.confirm.title":"Odrzuć zgłoszenie", + "submission.general.discard.submit":"Odrzuć", + "submission.general.info.saved":"Zapisane", + "submission.general.info.pending-changes":"Niezapisane zmiany", + "submission.general.save":"Zapisz", + "submission.general.save-later":"Zapisz wersję roboczą", + "submission.import-external.page.title":"Importuj metdane z zewnętrznego źródła", + "submission.import-external.title":"Importuj metadane z zewnętrznego źródła", + "submission.import-external.title.Journal":"Importuj czasopismo z zewnętrznego źródła", + "submission.import-external.title.JournalIssue":"Importuj numer czasopisma z zewnętrznego źródła", + "submission.import-external.title.JournalVolume":"Importuj tom czasopisma z zewnętrznego źródła", + "submission.import-external.title.OrgUnit":"Importuj wydawcę z zewnętrznego źródła", + "submission.import-external.title.Person":"Importuj osobę z zewnętrznego źródła", + "submission.import-external.title.Project":"Importuj projekt z zewnętrznego źródła", + "submission.import-external.title.Publication":"Importuj publikację z zewnętrznego źródła", + "submission.import-external.title.none":"Importuj metadane z zewnętrznego źródła", + "submission.import-external.page.hint":"Enter a query above to find items from the web to import in to DSpace.", + "submission.import-external.back-to-my-dspace":"Powrót do MyDSpace", + "submission.import-external.search.placeholder":"Wyszukaj zewnętrzne źródła danych", + "submission.import-external.search.button":"Szukaj", + "submission.import-external.search.button.hint":"Zacznij wpisywać frazę, aby wyszukać", + "submission.import-external.search.source.hint":"Wybierz zewnętrzne źródło", + "submission.import-external.source.ads":"NASA/ADS", + "submission.import-external.source.arxiv":"arXiv", + "submission.import-external.source.cinii":"CiNii", + "submission.import-external.source.crossref":"CrossRef", + "submission.import-external.source.loading":"ładowanie...", + "submission.import-external.source.sherpaJournal":"Czasopisma w SHERPA", + "submission.import-external.source.sherpaJournalIssn":"Czasopisma w SHERPA wg ISSN", + "submission.import-external.source.sherpaPublisher":"Wydawcy w SHERPA", + "submission.import-external.source.openAIREFunding":"Finansowanie OpenAIRE API", + "submission.import-external.source.orcid":"ORCID", + "submission.import-external.source.orcidWorks":"ORCID", + "submission.import-external.source.pubmed":"Pubmed", + "submission.import-external.source.pubmedeu":"Pubmed Europe", + "submission.import-external.source.lcname":"Nazwy Biblioteki Kongresu", + "submission.import-external.source.scielo":"SciELO", + "submission.import-external.source.scopus":"Scopus", + "submission.import-external.source.vufind":"VuFind", + "submission.import-external.source.wos":"Web Of Science", + "submission.import-external.source.epo":"Europejski Urząd Patentowy (EPO)", + "submission.import-external.preview.title.Journal":"Podgląd czasopisma", + "submission.import-external.preview.title.OrgUnit":"Podgląd organizacji", + "submission.import-external.preview.title.Person":"Podgląd osoby", + "submission.import-external.preview.title.Project":"Podgląd projektu", + "submission.import-external.preview.title.Publication":"Podgląd publikacji", + "submission.import-external.preview.subtitle":"Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", + "submission.import-external.preview.button.import":"Rozpocznij zgłoszenie", + "submission.import-external.preview.error.import.title":"Błąd zgłoszenia", + "submission.import-external.preview.error.import.body":"Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", + "submission.sections.describe.relationship-lookup.close":"Zamknij", + "submission.sections.describe.relationship-lookup.external-source.added":"Udało się dodać wpis do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication":"Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal":"Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue":"Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume":"Importuj zdalny tom czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication":"Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity":"Nowy typ danych dodany!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title":"Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding":"Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title":"Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person":"Importuj zdalną osobę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product":"Importuj zdalny produkt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment":"Importuj zdalną aparaturę badawczą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event":"Importuj zdalne wydarzenie", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding":"Importuj zdalną instytucję finansującą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit":"Importuj zdalnego wydawcę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent":"Importuj zdalnie patent", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project":"Importuj zdalnie projekt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication":"Importuj zdalnie publikację", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity":"Udało się dodać autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity":"Udało się zaimportować i dodać zewnętrznego autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority":"Nadrzędność", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new":"Importuj jako nową, lokalną, nadrzędną pozycję", + "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel":"Anuluj", + "submission.sections.describe.relationship-lookup.external-source.import-modal.collection":"Wybierz kolekcję do zaimportowania nowych pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities":"Typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new":"Importuj jako nowy lokalny typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname":"Importuj z LC Name", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid":"Importuj z ORCID", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal":"Importuj z Sherpa Journal", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher":"Importuj z Sherpa Publisher", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed":"Importuj z PubMed", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv":"Importuj z arXiv", + "submission.sections.describe.relationship-lookup.external-source.import-modal.import":"Import", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title":"Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity":"Successfully added local journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity":"Successfully imported and added external journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title":"Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity":"Udało się dodać lokalne czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity":"Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title":"Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity":"Udało się dodać lokalny numer czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity":"Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select":"Wybierz lokalne powiązanie:", + "submission.sections.describe.relationship-lookup.search-tab.deselect-all":"Odznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.deselect-page":"Odznacz stronę", + "submission.sections.describe.relationship-lookup.search-tab.loading":"Ładowanie...", + "submission.sections.describe.relationship-lookup.search-tab.placeholder":"Wyszukaj zapytanie", + "submission.sections.describe.relationship-lookup.search-tab.search":"Zastosuj", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder":"Wyszukaj...", + "submission.sections.describe.relationship-lookup.search-tab.select-all":"Zaznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.select-page":"Zaznacz stronę", + "submission.sections.describe.relationship-lookup.selected":"Zaznacz {{ size }} pozycji", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication":"Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication":"Czasopisma lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project":"Projekty lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication":"Publikacje lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person":"Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit":"Lokalne jednostki organizacyjne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage":"Lokalne paczki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile":"Lokalne pliki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal":"Lokalne czasopisma ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication":"Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue":"Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication":"Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume":"Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal":"Sherpa Journals ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher":"Sherpa Publishers ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid":"ORCID ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname":"LC Names ({{ 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":"Wyszukaj instytucje finansujące", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication":"Wyszukaj finansowanie", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf":"Wyszukaj jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding":"Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication":"Projekty", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject":"Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding":"Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication":"Projekt", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication":"Projekty", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject":"Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder":"Wyszukaj...", + "submission.sections.describe.relationship-lookup.selection-tab.tab-title":"Aktualne zaznaczenie ({{ count }})", + "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication":"Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalIssue":"Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication":"Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalVolume":"Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalOfPublication":"Czasopisma", + "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication":"Autorzy", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication":"Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.Project":"Projekty", + "submission.sections.describe.relationship-lookup.title.Publication":"Publikacje", + "submission.sections.describe.relationship-lookup.title.Person":"Autorzy", + "submission.sections.describe.relationship-lookup.title.OrgUnit":"Jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.title.DataPackage":"Paczki danych", + "submission.sections.describe.relationship-lookup.title.DataFile":"Pliki danych", + "submission.sections.describe.relationship-lookup.title.Funding Agency":"Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.isFundingOfPublication":"Finansowanie", + "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf":"Nadrzędna jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown":"Przełącz na listę rozwijaną", + "submission.sections.describe.relationship-lookup.selection-tab.settings":"Ustawienia", + "submission.sections.describe.relationship-lookup.selection-tab.no-selection":"Twoje zaznaczenie jest puste.", + "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication":"Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication":"Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication":"Wybrane tomy czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.Project":"Wybrane projekty", + "submission.sections.describe.relationship-lookup.selection-tab.title.Publication":"Wybrane publikacje", + "submission.sections.describe.relationship-lookup.selection-tab.title.Person":"Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit":"Wybrane jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage":"Wybrane pakiety danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile":"Wybrane pliki danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.Journal":"Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication":"Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume":"Wybrany tom czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication":"Wybrane instytucje finansujące", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication":"Wybrane finansowanie", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue":"Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf":"Wybrana jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcid":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.lcname":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title":"Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.name-variant.notification.content":"Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", + "submission.sections.describe.relationship-lookup.name-variant.notification.confirm":"Zapisz nowy wariant imienia", + "submission.sections.describe.relationship-lookup.name-variant.notification.decline":"Użyj tylko w tym zgłoszeniu", + "submission.sections.ccLicense.type":"Typ licencji", + "submission.sections.ccLicense.select":"Wybierz typ licencji…", + "submission.sections.ccLicense.change":"Zmień typ licencji…", + "submission.sections.ccLicense.none":"Brak dostępnych licencji", + "submission.sections.ccLicense.option.select":"Wybierz opcję…", + "submission.sections.ccLicense.link":"Wybrano licencję:", + "submission.sections.ccLicense.confirmation":"Udzielam powyższej licencji", + "submission.sections.general.add-more":"Dodaj więcej", + "submission.sections.general.collection":"Kolekcja", + "submission.sections.general.deposit_error_notice":"Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", + "submission.sections.general.deposit_success_notice":"Udało się wprowadzić pozycję.", + "submission.sections.general.discard_error_notice":"Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", + "submission.sections.general.discard_success_notice":"Udało się odrzucić pozycję.", + "submission.sections.general.metadata-extracted":"Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", + "submission.sections.general.metadata-extracted-new-section":"Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", + "submission.sections.general.no-collection":"Nie znaleziono kolekcji", + "submission.sections.general.no-sections":"Opcje niedostępne", + "submission.sections.general.save_error_notice":"Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", + "submission.sections.general.save_success_notice":"Udało się zapisać zgłoszenie.", + "submission.sections.general.search-collection":"Szukaj kolekcji", + "submission.sections.general.sections_not_valid":"Niektóre sekcje są niekompletne.", + "submission.sections.submit.progressbar.CClicense":"Licencja Creative Commons", + "submission.sections.submit.progressbar.describe.recycle":"Odzyskaj", + "submission.sections.submit.progressbar.describe.stepcustom":"Opisz", + "submission.sections.submit.progressbar.describe.stepone":"Opisz", + "submission.sections.submit.progressbar.describe.steptwo":"Opisz", + "submission.sections.submit.progressbar.detect-duplicate":"Potencjalne duplikaty", + "submission.sections.submit.progressbar.license":"Zdeponuj licencję", + "submission.sections.submit.progressbar.upload":"Prześlij pliki", + "submission.sections.status.errors.title":"Błędy", + "submission.sections.status.valid.title":"Poprawność", + "submission.sections.status.warnings.title":"Ostrzeżenia", + "submission.sections.status.errors.aria":"ma błędy", + "submission.sections.status.valid.aria":"jest poprawne", + "submission.sections.status.warnings.aria":"ma ostrzeżenia", + "submission.sections.toggle.open":"Otwórz sekcję", + "submission.sections.toggle.close":"Zamknij sekcję", + "submission.sections.toggle.aria.open":"Rozwiń sekcję {{sectionHeader}}", + "submission.sections.toggle.aria.close":"Zwiń sekcję {{sectionHeader}}", + "submission.sections.upload.delete.confirm.cancel":"Anuluj", + "submission.sections.upload.delete.confirm.info":"Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.sections.upload.delete.confirm.submit":"Tak, na pewno", + "submission.sections.upload.delete.confirm.title":"Usuń plik", + "submission.sections.upload.delete.submit":"Usuń", + "submission.sections.upload.download.title":"Pobierz plik", + "submission.sections.upload.drop-message":"Upuść pliki, aby załączyć je do tej pozycji", + "submission.sections.upload.edit.title":"Edytuj plik", + "submission.sections.upload.form.access-condition-label":"Typ dostępu", + "submission.sections.upload.form.date-required":"Data jest wymagana.", + "submission.sections.upload.form.date-required-from":"Data przyznania dostępu od jest wymagana.", + "submission.sections.upload.form.date-required-until":"Data przyznania dostępu do jest wymagana.", + "submission.sections.upload.form.from-label":"Pozwól na dostęp od", + "submission.sections.upload.form.from-placeholder":"Od", + "submission.sections.upload.form.group-label":"Grupa", + "submission.sections.upload.form.group-required":"Grupa jest wymagana", + "submission.sections.upload.form.until-label":"Pozwól na dostęp do", + "submission.sections.upload.form.until-placeholder":"Do", + "submission.sections.upload.header.policy.default.nolist":"Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", + "submission.sections.upload.header.policy.default.withlist":"Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", + "submission.sections.upload.info":"Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", + "submission.sections.upload.no-entry":"Nie", + "submission.sections.upload.no-file-uploaded":"Pliki nie zostały jeszcze wgrane.", + "submission.sections.upload.save-metadata":"Zapisz metadane", + "submission.sections.upload.undo":"Anuluj", + "submission.sections.upload.upload-failed":"Przesyłanie nieudane", + "submission.sections.upload.upload-successful":"Przesyłanie udane", + "submission.submit.breadcrumbs":"Nowe zgłoszenie", + "submission.submit.title":"Nowe zgłoszenie", + "submission.workflow.generic.delete":"Usuń", + "submission.workflow.generic.delete-help":"Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", + "submission.workflow.generic.edit":"Edytuj", + "submission.workflow.generic.edit-help":"Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.generic.view":"Podgląd", + "submission.workflow.generic.view-help":"Wybierz tę opcję, aby wyświetlić metadane pozycji.", + "submission.workflow.tasks.claimed.approve":"Zatwierdź", + "submission.workflow.tasks.claimed.approve_help":"Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", + "submission.workflow.tasks.claimed.edit":"Edytuj", + "submission.workflow.tasks.claimed.edit_help":"Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.tasks.claimed.reject.reason.info":"Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", + "submission.workflow.tasks.claimed.reject.reason.placeholder":"Opisz powód odrzucenia zgłoszenia", + "submission.workflow.tasks.claimed.reject.reason.submit":"Odrzuć pozycję", + "submission.workflow.tasks.claimed.reject.reason.title":"Powód", + "submission.workflow.tasks.claimed.reject.submit":"Odrzuć", + "submission.workflow.tasks.claimed.reject_help":"Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", + "submission.workflow.tasks.claimed.return":"Cofnij do puli zadań", + "submission.workflow.tasks.claimed.return_help":"Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", + "submission.workflow.tasks.generic.error":"Podczas działania wystąpił błąd...", + "submission.workflow.tasks.generic.processing":"Procesowanie...", + "submission.workflow.tasks.generic.submitter":"Zgłaszający", + "submission.workflow.tasks.generic.success":"Udało się", + "submission.workflow.tasks.pool.claim":"Podejmij pracę", + "submission.workflow.tasks.pool.claim_help":"Przypisz to zadanie do siebie.", + "submission.workflow.tasks.pool.hide-detail":"Ukryj szczegóły", + "submission.workflow.tasks.pool.show-detail":"Pokaż szczegóły", + "thumbnail.default.alt":"Miniatura", + "thumbnail.default.placeholder":"Brak miniatury", + "thumbnail.project.alt":"Logo projektu", + "thumbnail.project.placeholder":"Obraz zastępczy projketu", + "thumbnail.orgunit.alt":"Logo jednostki organizacyjnej", + "thumbnail.orgunit.placeholder":"Obraz zastępczy jednostki organizacyjnej", + "thumbnail.person.alt":"Zdjęcie profilowe", + "thumbnail.person.placeholder":"Brak zdjęcia profilowego", + "title":"DSpace", + "vocabulary-treeview.header":"Widok drzewka", + "vocabulary-treeview.load-more":"Pokaż więcej", + "vocabulary-treeview.search.form.reset":"Resetuj", + "vocabulary-treeview.search.form.search":"Szukaj", + "vocabulary-treeview.search.no-result":"Brak pozycji do wyświetlenia", + "vocabulary-treeview.tree.description.nsi":"The Norwegian Science Index", + "vocabulary-treeview.tree.description.srsc":"Kategorie tematów badań", + "uploader.browse":"wyszukaj na swoim urządzeniu", + "uploader.drag-message":"Przeciągnij i upuść pliki tutaj", + "uploader.delete.btn-title":"Usuń", + "uploader.or":", lub ", + "uploader.processing":"Procesowanie", + "uploader.queue-length":"Długość kolejki", + "virtual-metadata.delete-item.info":"Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "virtual-metadata.delete-item.modal-head":"Wirtualne metadane tego powiązania", + "virtual-metadata.delete-relationship.modal-head":"Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "workflowAdmin.search.results.head":"Zarządzaj procesami", + "workflow-item.edit.breadcrumbs":"Edytuj pozycję procesu", + "workflow-item.edit.title":"Edytuj pozycję procesu", + "workflow-item.delete.notification.success.title":"Usunięte", + "workflow-item.delete.notification.success.content":"Ten element procesu został usunięty", + "workflow-item.delete.notification.error.title":"Coś poszło nie tak", + "workflow-item.delete.notification.error.content":"Ten element procesu nie mógł zostać usunięty", + "workflow-item.delete.title":"Usuń element procesu", + "workflow-item.delete.header":"Usuń element procesu", + "workflow-item.delete.button.cancel":"Anuluj", + "workflow-item.delete.button.confirm":"Usuń", + "workflow-item.send-back.notification.success.title":"SOdeślij do zgłaszającego", + "workflow-item.send-back.notification.success.content":"Ten element procesu został odesłany do zgłaszającego", + "workflow-item.send-back.notification.error.title":"Coś poszło nie tak", + "workflow-item.send-back.notification.error.content":"Ten element procesu nie mógł zostać odesłany do zgłaszającego", + "workflow-item.send-back.title":"Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.header":"Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.button.cancel":"Anuluj", + "workflow-item.send-back.button.confirm":"Odeślij", + "workflow-item.view.breadcrumbs":"Widok procesu", + "idle-modal.header":"Sesja wkrótce wygaśnie", + "idle-modal.info":"Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", + "idle-modal.log-out":"Wyloguj", + "idle-modal.extend-session":"Wydłuż sesję", + "workspace.search.results.head":"Twoje zadania", + "orgunit.listelement.badge":"Jednostka organizacyjna", + "orgunit.page.city":"Miasto", + "orgunit.page.country":"Kraj", + "orgunit.page.dateestablished":"Data założenia", + "orgunit.page.description":"Opis", + "orgunit.page.edit":"Edytuj pozycję", + "orgunit.page.id":"ID", + "orgunit.page.titleprefix":"Jednostka organizacyjna: ", + "pagination.options.description":"Opcje strony", + "pagination.results-per-page":"Wyników na stronę", + "pagination.showing.detail":"{{ range }} z {{ total }}", + "pagination.showing.label":"Teraz wyświetlane ", + "pagination.sort-direction":"Opcje sortowania", + "cookies.consent.purpose.sharing":"Udostępnianie", + "item.preview.dc.identifier.issn":"ISSN", + "500.page-internal-server-error":"Usługa niedostępna", + "500.help":"Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", + "500.link.home-page":"Zabierz mnie na stronę główną", + "error-page.description.401":"brak autoryzacji", + "error-page.description.403":"brak dostępu", + "error-page.description.500":"usługa niedostępna", + "error-page.description.404":"nie znaleziono strony", + "error-page.orcid.generic-error":"Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", + "access-status.embargo.listelement.badge":"Embargo", + "access-status.metadata.only.listelement.badge":"Tylko metadane", + "access-status.open.access.listelement.badge":"Open Access", + "access-status.restricted.listelement.badge":"Brak dostępu", + "access-status.unknown.listelement.badge":"Nieznane", + "admin.access-control.groups.table.edit.buttons.remove":"Usuń \"{{name}}\"", + "admin.metadata-import.page.validateOnly":"Tylko waliduj", + "admin.metadata-import.page.validateOnly.hint":"Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", + "bitstream.edit.form.iiifLabel.label":"Etykieta canvyIIIF", + "bitstream.edit.form.iiifLabel.hint":"Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", + "bitstream.edit.form.iiifToc.label":"Spis treści IIIF", + "bitstream.edit.form.iiifToc.hint":"Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", + "bitstream.edit.form.iiifWidth.label":"Szerokość canvy IIIF", + "bitstream.edit.form.iiifWidth.hint":"Szerokość canvy jest zwykle równa szerokości obrazu.", + "bitstream.edit.form.iiifHeight.label":"Wysokość canvy IIIF", + "bitstream.edit.form.iiifHeight.hint":"Wysokość canvy jest zwykle równa szerokości obrazu.", + "browse.back.all-results":"Wszystkie wyniki wyszukiwania", + "pagination.next.button":"Następny", + "pagination.previous.button":"Poprzedni", + "pagination.next.button.disabled.tooltip":"Brak więcej stron z wynikami wyszukiwania", + "browse.startsWith":", zaczyna się od {{ startsWith }}", + "browse.title.page":"Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", + "collection.edit.item.authorizations.load-bundle-button":"Załaduj więcej paczek", + "collection.edit.item.authorizations.load-more-button":"Załaduj więcej", + "collection.edit.item.authorizations.show-bitstreams-button":"Pokaż polityki plików dla paczek", + "comcol-role.edit.create.error.title":"Nie udało się utworzyć grupy dla roli '{{ role }}'", + "curation.form.submit.error.invalid-handle":"Nie ustalono identyfikatora dla tego obiektu", + "confirmation-modal.delete-profile.header":"Usuń profil", + "confirmation-modal.delete-profile.info":"Czy na pewno chcesz usunąć profil", + "confirmation-modal.delete-profile.cancel":"Anuluj", + "confirmation-modal.delete-profile.confirm":"Usuń", + "error.invalid-search-query":"Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", + "feed.description":"Aktualności", + "footer.link.feedback":"Prześlij uwagi", + "form.group-collapse":"Zwiń", + "form.group-collapse-help":"Kliknij tutaj, aby zwinąć", + "form.group-expand":"Rozwiń", + "form.group-expand-help":"Kliknij tutaj, aby rozwinąć", + "health.breadcrumbs":"Stan systemu", + "health-page.heading":"Stan systemu", + "health-page.info-tab":"Informacje", + "health-page.status-tab":"Status", + "health-page.error.msg":"Serwis stanu systemu jest tymczasowo niedostępny", + "health-page.property.status":"Kod statusu", + "health-page.section.db.title":"Baza danych", + "health-page.section.geoIp.title":"GeoIp", + "health-page.section.solrAuthorityCore.title":"Autentykacja", + "health-page.section.solrOaiCore.title":"OAI", + "health-page.section.solrSearchCore.title":"Wyszukiwarka", + "health-page.section.solrStatisticsCore.title":"Statystyki", + "health-page.section-info.app.title":"Backend aplikacji", + "health-page.section-info.java.title":"Java", + "health-page.status":"Status", + "health-page.status.ok.info":"operacyjny", + "health-page.status.error.info":"Wykryte problemy", + "health-page.status.warning.info":"Wykryte potencjalne problemy", + "health-page.title":"Stan systemu", + "health-page.section.no-issues":"Nie wykryto żadnych problemów", + "info.feedback.breadcrumbs":"Uwagi", + "info.feedback.head":"Uwagi", + "info.feedback.title":"Uwagi", + "info.feedback.info":"Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", + "info.feedback.email_help":"Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", + "info.feedback.send":"Prześlij uwagi", + "info.feedback.comments":"Komentarz", + "info.feedback.email-label":"Twoj adres e-mail", + "info.feedback.create.success":"Uwagi przesłane!", + "info.feedback.error.email.required":"Poprawny adres e-mail jest wymagany", + "info.feedback.error.message.required":"Treść komentarza jest wymagana", + "info.feedback.page-label":"Strona", + "info.feedback.page_help":"Ta strona odnosi się do uwag.", + "item.orcid.return":"Powrót", + "item.truncatable-part.show-more":"Pokaż więcej", + "item.truncatable-part.show-less":"Pokaż mniej", + "item.page.orcid.title":"ORCID", + "item.page.orcid.tooltip":"Otwórz ustawienia ORCID", + "item.page.claim.button":"Podejmij pracę", + "item.page.claim.tooltip":"Podejmij pracę jako profil", + "item.version.create.modal.submitted.header":"Tworzenie nowej wersji...", + "item.version.create.modal.submitted.text":"Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", + "journal-relationships.search.results.head":"Wyniki wyszukiwania czasopism", + "menu.section.icon.health":"Sekcja menu Stan systemu", + "menu.section.health":"Stan systemu", + "metadata-export-search.tooltip":"Eksportuj wyniki wyszukiwania w formacie CSV", + "metadata-export-search.submit.success":"Eksport rozpoczął się", + "metadata-export-search.submit.error":"Eksport nie rozpoczął się", + "person.page.name":"Nazwa", + "person-relationships.search.results.head":"Wyniki wyszukiwania osób", + "profile.special.groups.head":"Autoryzacja do specjalnych grup, do których należysz", + "project-relationships.search.results.head":"Wyniki wyszukiwania projektów", + "publication-relationships.search.results.head":"Wyniki wyszukiwania publikacji", + "resource-policies.edit.page.target-failure.content":"Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", + "resource-policies.edit.page.other-failure.content":"Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", + "resource-policies.form.eperson-group-list.modal.header":"Nie można zmienić typu", + "resource-policies.form.eperson-group-list.modal.text1.toGroup":"Nie można zastąpić użytkownika grupą.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson":"Nie można zastąpić grupy użytkownikiem.", + "resource-policies.form.eperson-group-list.modal.text2":"Usuń obecną polityke zasobu i stwórz nową o określonym typie.", + "resource-policies.form.eperson-group-list.modal.close":"Ok", + "search.results.view-result":"Widok", + "default-relationships.search.results.head":"Wyniki wyszukiwania", + "statistics.table.title.TotalVisits":"Wyświetlnia ogółem", + "statistics.table.title.TotalVisitsPerMonth":"Wyświetlenia w miesiącu", + "statistics.table.title.TotalDownloads":"Pobrania", + "statistics.table.title.TopCountries":"Wyświetlenia wg krajów", + "statistics.table.title.TopCities":"Wyświetlenia wg miast", + "submission.import-external.preview.title":"Podgląd pozycji", + "submission.import-external.preview.title.none":"Podgląd pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none":"Import pozycji zdalnie", + "submission.sections.general.cannot_deposit":"Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", + "submission.sections.submit.progressbar.accessCondition":"Warunki dostępu do pozycji", + "submission.sections.submit.progressbar.sherpapolicy":"Polityki Sherpa", + "submission.sections.submit.progressbar.sherpaPolicies":"Informacje o polityce open access wydawcy.", + "submission.sections.status.info.title":"Dodatkowe informacje", + "submission.sections.status.info.aria":"Dodatkowe informacje", + "submission.sections.upload.form.access-condition-hint":"Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", + "submission.sections.upload.form.from-hint":"Wybierz datę, od której ma zostać zastosowany warunek dostępu", + "submission.sections.upload.form.until-hint":"Wybierz datę, do której ma zostać zastosowany warunek dostępu", + "submission.sections.accesses.form.discoverable-description":"Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", + "submission.sections.accesses.form.discoverable-label":"Niemożliwe do wyszukania", + "submission.sections.accesses.form.access-condition-label":"Typ warunku dostępu", + "submission.sections.accesses.form.access-condition-hint":"Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", + "submission.sections.accesses.form.date-required":"Data jest wymagana.", + "submission.sections.accesses.form.date-required-from":"Początkowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.date-required-until":"Końcowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.from-label":"Udziel dostępu od", + "submission.sections.accesses.form.from-hint":"Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.from-placeholder":"Od", + "submission.sections.accesses.form.group-label":"Grupa", + "submission.sections.accesses.form.group-required":"Grupa jest wymagana.", + "submission.sections.accesses.form.until-label":"Udziel dostępu do", + "submission.sections.accesses.form.until-hint":"Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.until-placeholder":"Do", + "submission.sections.sherpa.publication.information":"Informacje o publikacji", + "submission.sections.sherpa.publication.information.title":"Tytuł", + "submission.sections.sherpa.publication.information.issns":"Numery ISSN", + "submission.sections.sherpa.publication.information.url":"URL", + "submission.sections.sherpa.publication.information.publishers":"Wydawca", + "submission.sections.sherpa.publication.information.romeoPub":"Wydawca Romeo", + "submission.sections.sherpa.publication.information.zetoPub":"Wydawca Zeto", + "submission.sections.sherpa.publisher.policy":"Polityka wydawnicza", + "submission.sections.sherpa.publisher.policy.description":"Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", + "submission.sections.sherpa.publisher.policy.openaccess":"Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", + "submission.sections.sherpa.publisher.policy.more.information":"Aby uzuyskać więcej informacji, kliknij tutaj:", + "submission.sections.sherpa.publisher.policy.version":"Wersja", + "submission.sections.sherpa.publisher.policy.embargo":"Embargo", + "submission.sections.sherpa.publisher.policy.noembargo":"Brak embargo", + "submission.sections.sherpa.publisher.policy.nolocation":"Brak", + "submission.sections.sherpa.publisher.policy.license":"Licencja", + "submission.sections.sherpa.publisher.policy.prerequisites":"Wymagania wstępne", + "submission.sections.sherpa.publisher.policy.location":"Lokalizacja", + "submission.sections.sherpa.publisher.policy.conditions":"Wymagania", + "submission.sections.sherpa.publisher.policy.refresh":"Odśwież", + "submission.sections.sherpa.record.information":"Informacje o rekordzie", + "submission.sections.sherpa.record.information.id":"ID", + "submission.sections.sherpa.record.information.date.created":"Data utworzenia", + "submission.sections.sherpa.record.information.date.modified":"Ostatnia modyfikacja", + "submission.sections.sherpa.record.information.uri":"URI", + "submission.sections.sherpa.error.message":"Wystąpił błąd podczas pobierania informacji z Sherpa", + "submission.workspace.generic.view":"Podgląd", + "submission.workspace.generic.view-help":"Wybierz tę opcje, aby zobaczyć metadane.", + "workflow.search.results.head":"Zadania na workflow", + "workspace-item.view.breadcrumbs":"Widok wersji roboczej", + "workspace-item.view.title":"Widok wersji roboczej", + "researcher.profile.change-visibility.fail":"Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", + "person.page.orcid.link.processing":"Łączenie profilu z ORCID...", + "person.page.orcid.link.error.message":"Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", + "person.page.orcid.sync-queue.table.header.type":"Typ", + "person.page.orcid.sync-queue.table.header.description":"Opis", + "person.page.orcid.sync-queue.table.header.action":"Akcja", + "person.page.orcid.sync-queue.tooltip.project":"Projekt", + "person.page.orcid.sync-queue.send.validation-error.country.invalid":"Niewłaściwy dwuznakowy kod kraju ISO 3166", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid":"Wymagana data publikacji to co najmniej rok po 1900", + "person.page.orcid.synchronization-mode-funding-message":"Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", + "person.page.orcid.synchronization-mode-publication-message":"Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", + "person.page.orcid.synchronization-mode-profile-message":"Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", + "person.orcid.sync.setting":"Ustawienia synchronizacji z ORCID", + "person.orcid.registry.queue":"Kolejka rejestru z ORCID", + "person.orcid.registry.auth":"Autoryzacje z ORCID", + "home.recent-submissions.head":"Najnowsze publikacje", + "submission.sections.sherpa-policy.title-empty":"Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", + "admin.batch-import.breadcrumbs":"Import zbiorczy", + "admin.batch-import.page.dropMsg":"Drop a batch ZIP to import", + "admin.batch-import.page.dropMsgReplace":"Drop to replace the batch ZIP to import", + "admin.batch-import.page.error.addFile":"Najpierw wybierz plik (ZIP)", + "admin.batch-import.page.header":"Import masowy", + "admin.batch-import.page.help":"Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", + "admin.batch-import.page.remove":"usuń", + "admin.batch-import.page.validateOnly.hint":"Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", + "collection.form.correctionSubmissionDefinition":"Wzór zgłoszenia do prośby o korektę", + "comcol-role.edit.delete.error.title":"Nie udało się usunąć roli '{{ role }}' dla grup", + "confirmation-modal.export-batch.header":"Eksport maasowy (ZIP) {{ dsoName }}", + "confirmation-modal.export-batch.info":"Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", + "dso-selector.export-batch.dspaceobject.head":"Eksport masowy (ZIP) z", + "menu.section.export_batch":"Eksport masowy (ZIP)", + "nav.user-profile-menu-and-logout":"Profil użytkownika i wylogowywanie", + "process.detail.actions":"Akcje", + "process.detail.delete.body":"Czy na pewno chcesz usunąć bieżący proces?", + "process.detail.delete.button":"Usuń proces", + "process.detail.delete.cancel":"Anuluj", + "process.detail.delete.confirm":"Usuń proces", + "process.detail.delete.error":"Nie udało się usunąć procesu", + "process.detail.delete.header":"Usuń proces", + "process.detail.delete.success":"Proces został usunięty.", + "admin.batch-import.title":"Masowy import", + "admin.metadata-import.page.button.select-collection":"Wybierz kolekcję", + "admin.registries.bitstream-formats.table.id":"ID", + "admin.registries.schema.fields.table.id":"ID", + "cookies.consent.app.description.google-recaptcha":"Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", + "cookies.consent.app.disable-all.description":"Przełącz, aby zaakceptować lub odrzucić wszystkie", + "cookies.consent.app.disable-all.title":"Akceptowacja lub odrzucenie wszystkich", + "cookies.consent.app.title.google-recaptcha":"Google reCaptcha", + "cookies.consent.content-modal.service":"usługa", + "cookies.consent.content-modal.services":"usługi", + "cookies.consent.content-notice.description.no-privacy":"Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", + "cookies.consent.content-notice.title":"Zgoda na ciasteczka", + "cookies.consent.ok":"Zgadzam się", + "cookies.consent.purpose.registration-password-recovery":"Rejestracja i odzyskiwanie hasła", + "cookies.consent.save":"Zapisz", + "curation-task.task.citationpage.label":"Generuj stronę z cytowaniem", + "dso-selector.import-batch.dspaceobject.head":"Import masowy z", + "orgunit.listelement.no-title":"Brak tytyłu", + "process.bulk.delete.error.body":"Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", + "process.bulk.delete.error.head":"Błąd podczas usuwania procesu", + "process.bulk.delete.success":"{{count}} proces/y został/y usunięte", + "process.overview.delete":"Usuń {{count}} proces/y", + "process.overview.delete.body":"Czy na pewno usunąć {{count}} proces/y?", + "process.overview.delete.clear":"Wyczyść selekcję procesów do usunięcia", + "process.overview.delete.header":"Usuń procesy", + "process.overview.delete.processing":"{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", + "process.overview.table.actions":"Akcje", + "profile.security.form.label.current-password":"Aktualne hasło", + "profile.security.form.notifications.error.change-failed":"Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", + "profile.security.form.notifications.error.general":"Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", + "register-page.registration.error.recaptcha":"Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", + "register-page.registration.google-recaptcha.must-accept-cookies":"Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", + "register-page.registration.google-recaptcha.notification.message.error":"Wystąpił błąd podczas weryfikacji reCaptcha", + "register-page.registration.google-recaptcha.notification.message.expired":"Weryfikacja wygasła. Zweryfikuj ponownie.", + "register-page.registration.google-recaptcha.notification.title":"Google reCaptcha", + "register-page.registration.google-recaptcha.open-cookie-settings":"Otwórz ustawienia plików cookies", + "search.results.response.500":"Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", + "submission.sections.license.granted-label":"Potwierdzam akceptację powyższej licencji", + "submission.sections.license.notgranted":"Najpierw musisz zaakceptować licencję", + "submission.sections.license.required":"Najpierw musisz zaakceptować licencję", + "confirmation-modal.export-batch.confirm":"Eksportuj", + "confirmation-modal.export-batch.cancel":"Anuluj", + "admin.access-control.bulk-access.breadcrumbs":"Zbiorcza edycja dostępu do osiągnięć", + "administrativeBulkAccess.search.results.head":"Wyniki wyszukiwania", + "admin.access-control.bulk-access":"Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access.title":"Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access-browse.header":"Krok 1: Wybierz pozycje", + "admin.access-control.bulk-access-browse.search.header":"Wyszukaj", + "admin.access-control.bulk-access-browse.selected.header":"Obecny wybór({{number}})", + "admin.access-control.bulk-access-settings.header":"Krok 2: Działanie do wykonania", + "admin.access-control.groups.form.tooltip.editGroupPage":"Na tej stronie można edytować opcje grupy i przypisane do niej osoby. W górnej sekcji można edytować nazwę i opis grupy, chyba że jest to grupa administratorów dla zbioru i kolekcji. W tym przypadku nazwa i opis grupy są generowane automatycznie i nie można ich edytować. W kolejnych sekcjach można edytować przypisanie użytkowników do grupy. Szczegóły na [stronie](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople":"Aby dodać lub usunąć użytkownika do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj paska wyszukiwania poniżej, aby wyszukać użytkowników (użyj listy rozwijanej po lewej stronie paska wyszukiwania, aby wybrać, czy chcesz wyszukiwać według imienia i nazwiska, czy według adresu e-mail). Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może mieć kilka stron: użyj strzałek pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups":"Aby dodać lub usunąć podgrupę do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj wyszukiwarki poniżej, aby wyszukać użytkowników. Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może składać się z kilku stron: użyj przycisków pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.workflow.item.workspace":"Przestrzeń robocza", + "admin.workflow.item.policies":"Polityki", + "admin.workflow.item.supervision":"Recenzja", + "admin.batch-import.page.toggle.help":"It is possible to perform import either with file upload or via URL, use above toggle to set the input source", + "admin.metadata-import.page.error.addFileUrl":"Najpierw wpisz URL pliku!", + "admin.metadata-import.page.toggle.upload":"Prześlij", + "admin.metadata-import.page.toggle.url":"URL", + "admin.metadata-import.page.urlMsg":"Wpisz URL pliku ZIP, aby wykonać import masowy", + "advanced-workflow-action.rating.form.rating.label":"Ocena", + "advanced-workflow-action.rating.form.rating.error":"Ta pozycja musi zostać oceniona", + "advanced-workflow-action.rating.form.review.label":"Recenzja", + "advanced-workflow-action.rating.form.review.error":"Musisz wpisać tekst recenzji", + "advanced-workflow-action.rating.description":"Wybierz ocenę poniżej", + "advanced-workflow-action.rating.description-requiredDescription":"Wybierz ocenę poniżej i wpisz uzasadnienie", + "advanced-workflow-action.select-reviewer.description-single":"Wybierz recenzenta przed zdeponowaniem pozycji", + "advanced-workflow-action.select-reviewer.description-multiple":"Wybierz jednego lub więcej recenzentów przed zdeponowaniem pozycji", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head":"Użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head":"Dodaj użytkownika", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all":"Przeglądaj wszystko", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers":"Aktualni użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata":"Metadane", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email":"Adres e-mail (dokładny)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button":"Wyszukaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id":"ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name":"Nazwa", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity":"Tożsamość", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email":"Adres e-mail", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid":"NetID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit":"Usuń / Dodaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove":"Usuń użytkownika z nazwę \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember":"Dodano użytkownika o nazwie: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember":"Nie dodano użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember":"Usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember":"Nie usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add":"Dodano użytkownika \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet":"W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items":"Nie znaleziono żadnych użytkowników", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error":"Recenzent nie jest wybrany.", + "bitstream.edit.notifications.error.primaryBitstream.title":"Wystąpił błąd podczas zapisu pliku.", + "browse.comcol.by.srsc":"Wg słów kluczowych", + "browse.metadata.srsc.breadcrumbs":"Przeglądaj wg słów kluczowych", + "browse.startsWith.input":"Filtr", + "browse.taxonomy.button":"Przeglądaj", + "search.browse.item-back":"Powrót do wyników wyszukiwania", + "claimed-approved-search-result-list-element.title":"Zaakceptowano", + "claimed-declined-search-result-list-element.title":"Odrzucono i przesłano do deponującego", + "claimed-declined-task-search-result-list-element.title":"Odrzucono i przesłano do recenzenta", + "collection.edit.tabs.access-control.head":"Dostępy", + "collection.edit.tabs.access-control.title":"Edycja kolekcji - dostępy", + "collection.listelement.badge":"Kolekcja", + "community.edit.tabs.access-control.head":"Dostępy", + "community.edit.tabs.access-control.title":"Edycja zbioru - dostępy", + "comcol-role.edit.scorereviewers.name":"Ocena recenzenta", + "comcol-role.edit.scorereviewers.description":"Recenzenci mogą oceniać zdeponowane pozycje, co określi, czy pozycja zostanie przyjęta lub odrzucona.", + "curation-task.task.register-doi.label":"Rejestracja DOI", + "dso.name.unnamed":"Bez nazwy", + "dso-selector.create.community.or-divider":"lub", + "dso-selector.set-scope.community.or-divider":"lub", + "dso-selector.results-could-not-be-retrieved":"Wystąpił błąd, proszę odświeżyć stronę", + "supervision-group-selector.header":"Wybór grupy recenzenckiej", + "supervision-group-selector.select.type-of-order.label":"Wybierz typ funkcji", + "supervision-group-selector.select.type-of-order.option.none":"BRAK", + "supervision-group-selector.select.type-of-order.option.editor":"REDAKTOR", + "supervision-group-selector.select.type-of-order.option.observer":"OBSERWATOR", + "supervision-group-selector.select.group.label":"Wybierz grupę", + "supervision-group-selector.button.cancel":"Anuluj", + "supervision-group-selector.button.save":"Zapisz", + "supervision-group-selector.select.type-of-order.error":"Wybierz typ funkcji", + "supervision-group-selector.select.group.error":"Wybierz grupę", + "supervision-group-selector.notification.create.success.title":"Grupa recenzencka został dodana dla grupy {{ name }}", + "supervision-group-selector.notification.create.failure.title":"Błąd", + "supervision-group-selector.notification.create.already-existing":"Funkcja recenzenta już jest przypisana do tej grupy", + "confirmation-modal.delete-subscription.header":"Usuń subksrypcje", + "confirmation-modal.delete-subscription.info":"Czy na pewno chcesz usunąć subskrypcję: \"{{ dsoName }}\"", + "confirmation-modal.delete-subscription.cancel":"Anuluj", + "confirmation-modal.delete-subscription.confirm":"Usuń", + "error.validation.metadata.name.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.name.max-length":"To pole nie może zawierać więcej niż 32 znaki", + "error.validation.metadata.namespace.max-length":"To pole nie może zawierać więcej niż 256 znaków", + "error.validation.metadata.element.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.element.max-length":"To pole nie może zawierać więcej niż 64 znaki", + "error.validation.metadata.qualifier.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji", + "error.validation.metadata.qualifier.max-length":"To pole nie może zawierać więcej niż 64 znaki", + "forgot-email.form.email.error.not-email-form":"Wpisz prawidłowy adres e-mail", + "form.other-information.email":"Adres e-mail", + "form.other-information.first-name":"Imię", + "form.other-information.insolr":"Solr Index", + "form.other-information.institution":"Instytucja", + "form.other-information.last-name":"Nazwisko", + "form.other-information.orcid":"ORCID", + "form.create":"Utwórz", + "info.end-user-agreement.hosting-country":"Stany Zjednoczone", + "item.edit.identifiers.doi.status.UNKNOWN":"Nieznane", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED":"W kolejce do rejestracji", + "item.edit.identifiers.doi.status.TO_BE_RESERVED":"W kolejce do rezerwacji", + "item.edit.identifiers.doi.status.IS_REGISTERED":"Zarejestrowane", + "item.edit.identifiers.doi.status.IS_RESERVED":"Zarezerwowane", + "item.edit.identifiers.doi.status.UPDATE_RESERVED":"Zarezerwowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED":"Zarejestrowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION":"W kolejce do aktualizacji i rejestracji", + "item.edit.identifiers.doi.status.TO_BE_DELETED":"Zakolejkowane do usunięcia", + "item.edit.identifiers.doi.status.DELETED":"Usunięte", + "item.edit.identifiers.doi.status.PENDING":"Oczekujące (niezarejestrowane)", + "item.edit.identifiers.doi.status.MINTED":"Rezerwowanie nazwy (niezarejestrowane)", + "item.edit.tabs.status.buttons.register-doi.label":"Zarejestruj nowe lub oczekujące DOI", + "item.edit.tabs.status.buttons.register-doi.button":"Rejestruj DOI...", + "item.edit.register-doi.header":"Zarejestruj nowe lub oczekujące DOI", + "item.edit.register-doi.description":"Zweryfikuj poniższe identyfikatory i metadane pozycji i rozpocznij rejestrację DOI lub anuluj", + "item.edit.register-doi.confirm":"Zatwierdź", + "item.edit.register-doi.cancel":"Anuluj", + "item.edit.register-doi.success":"DOI jest w kolejce do rejestracji.", + "item.edit.register-doi.error":"Wystąpił błąd poczas rejestracji DOI", + "item.edit.register-doi.to-update":"To DOI zostało zarezerwowane i będzie znajdować się w kolejce do rejestracji", + "item.edit.metadata.edit.buttons.confirm":"Zatwierdź", + "item.edit.metadata.edit.buttons.drag":"Przeciągnij, aby zmienić kolejność", + "item.edit.metadata.edit.buttons.virtual":"To pole przechowuje wirutalne wartości metadanych, np. wartość pobraną z encji, z którą jest połączona ta pozycja. Dodaj lub usuń relację w zakładce 'Relacje' ", + "item.edit.metadata.metadatafield.error":"Wystąpił błąd podczas walidcji pól metadanych", + "item.edit.metadata.reset-order-button":"Cofnij zamianę kolejności", + "item.edit.curate.title":"Zarządzaj pozycją: {{item}}", + "item.edit.tabs.access-control.head":"Dostęp", + "item.edit.tabs.access-control.title":"Edycja pozycji - dostęp", + "workflow-item.search.result.delete-supervision.modal.header":"Usuń zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.info":"Czy na pewno usunąć zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.cancel":"Anuluj", + "workflow-item.search.result.delete-supervision.modal.confirm":"Usuń", + "workflow-item.search.result.notification.deleted.success":"Usunięto zadanie dla recenzenta \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure":"Nie usunięto zadania dla recenzenta \"{{name}}\"", + "workflow-item.search.result.list.element.supervised-by":"Recenzja:", + "workflow-item.search.result.list.element.supervised.remove-tooltip":"Usuń grupę recenzencką", + "item.preview.dc.subject":"Słowo kluczowe:", + "item.preview.dc.publisher":"Wydawca:", + "itemtemplate.edit.metadata.add-button":"Dodaj", + "itemtemplate.edit.metadata.discard-button":"Cofnij", + "itemtemplate.edit.metadata.edit.buttons.confirm":"Zatwierdź", + "itemtemplate.edit.metadata.edit.buttons.drag":"Przeciągnij, aby zmienić kolejność", + "itemtemplate.edit.metadata.edit.buttons.edit":"Edytuj", + "itemtemplate.edit.metadata.edit.buttons.remove":"Usuń", + "itemtemplate.edit.metadata.edit.buttons.undo":"Cofnij zmiany", + "itemtemplate.edit.metadata.edit.buttons.unedit":"Nie edytuj", + "itemtemplate.edit.metadata.empty":"To pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby je wprowadzić.", + "itemtemplate.edit.metadata.headers.edit":"Edytuj", + "itemtemplate.edit.metadata.headers.field":"Pole", + "itemtemplate.edit.metadata.headers.language":"Język", + "itemtemplate.edit.metadata.headers.value":"Wartość", + "itemtemplate.edit.metadata.metadatafield.error":"Wystąpił błąd podczas walidowania pola metadanych", + "itemtemplate.edit.metadata.metadatafield.invalid":"Wybierz odpowiednie pole metadanych", + "itemtemplate.edit.metadata.notifications.discarded.content":"Twoje zmiany nie zostały zachowane. Aby spróbować wprowadzić je ponownie wybierz Cofnij", + "itemtemplate.edit.metadata.notifications.discarded.title":"Zmiany nie zostały zachowane", + "itemtemplate.edit.metadata.notifications.error.title":"Wystąpił błąd", + "itemtemplate.edit.metadata.notifications.invalid.content":"Twoje zmiany nie zostały zapisane. Upewnij się, że wszystkie pola zostały wypełnione prawidłowo.", + "itemtemplate.edit.metadata.notifications.invalid.title":"Nieprawidłowe metadan", + "itemtemplate.edit.metadata.notifications.outdated.content":"Wzór dla pozycji, na którą w tym momencie pracujesz, został zmodyfikowany przez innego użytkownika. Twoje zmiany zostały odrzucone, aby uniknąć konfliktów pomiędzy wersjami.", + "itemtemplate.edit.metadata.notifications.outdated.title":"Zmiany zostały odrzucone", + "itemtemplate.edit.metadata.notifications.saved.content":"Zmiany w metadanych wzoru pozycji zostały zapisane.", + "itemtemplate.edit.metadata.notifications.saved.title":"Metadane zostały zapisane", + "itemtemplate.edit.metadata.reinstate-button":"Cofnij", + "itemtemplate.edit.metadata.reset-order-button":"Cofnij zmianę kolejności", + "itemtemplate.edit.metadata.save-button":"Zapisz", + "menu.section.access_control_bulk":"Zbiorowe zarządzanie dostępem", + "menu.section.browse_global_by_srsc":"Wg słów kluczowych", + "mydspace.show.supervisedWorkspace":"Pozycje recenzowane", + "mydspace.status.mydspaceArchived":"Opublikowano", + "mydspace.status.mydspaceValidation":"Walidacja", + "mydspace.status.mydspaceWaitingController":"Oczekiwanie na redakctora", + "mydspace.status.mydspaceWorkflow":"Redakcja", + "mydspace.status.mydspaceWorkspace":"Przestrzeń robocza", + "nav.context-help-toggle":"Przełącz pomoc kontekstową", + "nav.search.button":"Wpisz wyszukiwaną frazę", + "nav.subscriptions":"Subksrypcje", + "process.new.notification.error.max-upload.content":"Plik jest większy niż maksymalny dozwolony rozmiar pliku", + "register-page.registration.email.error.not-email-form":"Wprowadź poprawny adres e-mail", + "register-page.registration.email.error.not-valid-domain":"Użyj adresu e-mail z domeny: {{ domains }}", + "register-page.registration.error.maildomain":"Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", + "register-page.registration.info.maildomain":"Konta mogą być założone dla adresów e-mail z domeną", + "repository.title":"Repozytorium DSpace", + "search.filters.applied.f.supervisedBy":"Recenzent", + "search.filters.filter.show-tree":"Przeglądaj {{ name }} strukturę recenzentów", + "search.filters.filter.supervisedBy.head":"Recenzent", + "search.filters.filter.supervisedBy.placeholder":"Recenzent", + "search.filters.filter.supervisedBy.label":"Wyszukaj recenzenta", + "statistics.table.no-name":"(nazwa obiektu nie może zostać załadowana)", + "submission.import-external.source.datacite":"DataCite", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor":"Publikacje autora", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor":"Publikacje", + "submission.sections.identifiers.info":"Te identyfikatory zostaną utworzone dla pozycji:", + "submission.sections.identifiers.no_handle":"Do tej pozycji nie zostały przypisane żadne Handle", + "submission.sections.identifiers.no_doi":"Do tej pozycji nie zostały przypisane żadne DOI", + "submission.sections.identifiers.handle_label":"Handle: ", + "submission.sections.identifiers.doi_label":"DOI: ", + "submission.sections.identifiers.otherIdentifiers_label":"Inne identyfikatory: ", + "submission.sections.submit.progressbar.identifiers":"Identyfikatory", + "submission.workflow.generic.submit_select_reviewer":"Wybierz recenzenta", + "submission.workflow.generic.submit_select_reviewer-help":"", + "submission.workflow.generic.submit_score":"Wynik", + "submission.workflow.generic.submit_score-help":"", + "submission.workflow.tasks.claimed.decline":"Odrzuć", + "submission.workflow.tasks.claimed.decline_help":"", + "submitter.empty":"n.d.", + "subscriptions.title":"Subskrypcje", + "subscriptions.item":"Subskrypcje pozycji", + "subscriptions.collection":"Subskrypcje kolekcji", + "subscriptions.community":"Subskrypcje zbiorów", + "subscriptions.subscription_type":"Typ subksrypcji", + "subscriptions.frequency":"Częstotliwość subskrypcji", + "subscriptions.frequency.D":"Codziennie", + "subscriptions.frequency.M":"Co miesiąc", + "subscriptions.frequency.W":"Co tydzień", + "subscriptions.tooltip":"Subskrybuj", + "subscriptions.modal.title":"Subksrypcje", + "subscriptions.modal.type-frequency":"Rodzaj i częstotliwość subksrypcji", + "subscriptions.modal.close":"Zamknij", + "subscriptions.modal.delete-info":"Aby usunąć tę subksrypcję przejdź do strony 'Subskrypcje', która znajduje się w profilu użytkownika", + "subscriptions.modal.new-subscription-form.type.content":"Zawartość", + "subscriptions.modal.new-subscription-form.frequency.D":"Codziennie", + "subscriptions.modal.new-subscription-form.frequency.W":"Co tydzień", + "subscriptions.modal.new-subscription-form.frequency.M":"Co miesiąc", + "subscriptions.modal.new-subscription-form.submit":"Zapisz", + "subscriptions.modal.new-subscription-form.processing":"Ładowanie...", + "subscriptions.modal.create.success":"Zasubskrybowano {{ type }}", + "subscriptions.modal.delete.success":"Subskrypcja została anulowana", + "subscriptions.modal.update.success":"Twoja subskrypcja {{ type }} została zaktualizowana", + "subscriptions.modal.create.error":"Wystąpił bład podczas tworzenia subskrypcji", + "subscriptions.modal.delete.error":"Wystąpił bład podczas usuwania subskrypcji", + "subscriptions.modal.update.error":"Wystąpił bład podczas aktualizacji subskrypcji", + "subscriptions.table.dso":"Słowo kluczowe", + "subscriptions.table.subscription_type":"Typ subskrypcji", + "subscriptions.table.subscription_frequency":"Częstotliwość subskrypcji", + "subscriptions.table.action":"Akcja", + "subscriptions.table.edit":"Edytuj", + "subscriptions.table.delete":"Usuń", + "subscriptions.table.not-available":"Niedostępne", + "subscriptions.table.not-available-message":"Ta pozycja została usunięta lun nie masz do niej dostępu, aby ją wyswietlić", + "subscriptions.table.empty.message":"Ta pozycja nie ma w tym momencie żadnych subksrypcji. Aby zasubkrybować i otrzymywać aktualizacje o tym zbiorze lub kolekcji, wybierz przycisk subskrypcji na stronie pozycji.", + "vocabulary-treeview.info":"Wybierz słowo kluczowe, aby dodać je do filtra", + "supervisedWorkspace.search.results.head":"Pozycje recenzowane", + "supervision.search.results.head":"Status zadań: Szkic i redakcja", + "workspace-item.delete.breadcrumbs":"Usunięto wersję roboczą", + "workspace-item.delete.header":"Usuń wersję roboczą", + "workspace-item.delete.button.confirm":"Usuń", + "workspace-item.delete.button.cancel":"Anuluj", + "workspace-item.delete.notification.success.title":"Usunięto", + "workspace-item.delete.title":"Wersja robocza została usunieta", + "workspace-item.delete.notification.error.title":"Coś poszło nie tak", + "workspace-item.delete.notification.error.content":"Wersja robocza nie może zostać usunieta", + "workflow-item.advanced.title":"Zaawansowane workflow", + "workflow-item.selectrevieweraction.notification.success.title":"Wybrany recenzent", + "workflow-item.selectrevieweraction.notification.success.content":"Recenzent został przypisany", + "workflow-item.selectrevieweraction.notification.error.title":"Coś poszło nie tak", + "workflow-item.selectrevieweraction.notification.error.content":"Nie udało się wybrać recenzenta dla pozycji", + "workflow-item.selectrevieweraction.title":"Wybierz recenzenta", + "workflow-item.selectrevieweraction.header":"Wybierz recenzenta", + "workflow-item.selectrevieweraction.button.cancel":"Anuluj", + "workflow-item.selectrevieweraction.button.confirm":"Zatwierdź", + "workflow-item.scorereviewaction.notification.success.title":"Ocena recenzji", + "workflow-item.scorereviewaction.notification.success.content":"Ocena tej pozycji została zapisana", + "workflow-item.scorereviewaction.notification.error.title":"Coś poszło nie tak", + "workflow-item.scorereviewaction.notification.error.content":"Nie można ocenić tej pozycji", + "workflow-item.scorereviewaction.title":"Oceń pozycję", + "workflow-item.scorereviewaction.header":"Oceń pozycję", + "workflow-item.scorereviewaction.button.cancel":"Anuluj", + "workflow-item.scorereviewaction.button.confirm":"Potwierdź", + "listable-notification-object.default-message":"Ta pozycja nie może być odzyskana", + "system-wide-alert-banner.retrieval.error":"Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert-banner.countdown.prefix":"W", + "system-wide-alert-banner.countdown.days":"{{days}} dni,", + "system-wide-alert-banner.countdown.hours":"{{hours}} godziny", + "system-wide-alert-banner.countdown.minutes":"{{minutes}} minut:", + "menu.section.system-wide-alert":"Alert systemowy", + "system-wide-alert.form.header":"Alert systemowy", + "system-wide-alert-form.retrieval.error":"Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert.form.cancel":"Anuluj", + "system-wide-alert.form.save":"Zapisz", + "system-wide-alert.form.label.active":"AKTYWNE", + "system-wide-alert.form.label.inactive":"NIEAKTYWNE", + "system-wide-alert.form.error.message":"Alert systemowy musi zawierać wiadomość", + "system-wide-alert.form.label.message":"Alert systemowy", + "system-wide-alert.form.label.countdownTo.enable":"Wprowadź licznik czasowy", + "system-wide-alert.form.label.countdownTo.hint":"Wskazówka: Wpisz wartość licznika czasu. Kiedy licznik jest włączony, alert systemowy zostanie wyświetlony o wybranym czasie. Kiedy odliczanie zostanie zakończone, alert systemowy zostanie wyłączony. Serwer NIE zostanie zatrzymany automatycznie.", + "system-wide-alert.form.label.preview":"Podgląd alertu systemowego", + "system-wide-alert.form.update.success":"Alert systemowy został zaktualizowany", + "system-wide-alert.form.update.error":"Coś poszło nie tak podczas aktualizacji alertu systemowego", + "system-wide-alert.form.create.success":"Alert systemowy został utworzony", + "system-wide-alert.form.create.error":"Coś poszło nie tak podczas tworzenia alertu systemowego", + "admin.system-wide-alert.breadcrumbs":"Alerty systemowe", + "admin.system-wide-alert.title":"Alerty systemowe", + "item-access-control-title":"Ta strona pozwala na zmianę dostępów metadanych pozycji i plików do nich dołączonych.", + "collection-access-control-title":"Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w tej kolekcji. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "community-access-control-title":"Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w każdej kolekcji w tym zbiorze. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "access-control-item-header-toggle":"Metadane pozycji", + "access-control-bitstream-header-toggle":"Pliki", + "access-control-mode":"Tryb", + "access-control-access-conditions":"Warunki dostępu", + "access-control-no-access-conditions-warning-message":"W tym momencie żadne warunki dostępu nie zostały określone. Jeśli zadanie zostanie rozpoczęte, obecne warunki dostępu zostaną zastąpione domyślnymi warunkami dostępu z nadrzędnej kolekcji.", + "access-control-replace-all":"Zastąp warunki dostępu", + "access-control-add-to-existing":"Dodaj do już istniejących", + "access-control-limit-to-specific":"Ogranicz zmiany do wybranych plików", + "access-control-process-all-bitstreams":"Zaktualizuj wszystkie pliki dla tej pozycji", + "access-control-bitstreams-selected":"wybrane pliki", + "access-control-cancel":"Anuluj", + "access-control-execute":"Wykonaj", + "access-control-add-more":"Dodaj więcej", + "access-control-select-bitstreams-modal.title":"Wybierz pliki", + "access-control-select-bitstreams-modal.no-items":"Brak pozycji do wyświetlenia.", + "access-control-select-bitstreams-modal.close":"Zamknij", + "access-control-option-label":"Typ warunków dostępu", + "access-control-option-note":"Wybierz warunki dostępu, które chcesz przypisać do zaznaczonych pozycji.", + "access-control-option-start-date":"Dostęp od", + "access-control-option-start-date-note":"Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", + "access-control-option-end-date":"Dostęp do", + "access-control-option-end-date-note":"Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać" } From cfd753f928a0ed8829ef7d7a00f727b81d782d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dykas?= <96572102+michdyk@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:09:09 +0200 Subject: [PATCH 100/282] Update pl.json5 Translation update of 2 spaces instead of 3 --- src/assets/i18n/pl.json5 | 5238 +++++++++++++++++++------------------- 1 file changed, 2619 insertions(+), 2619 deletions(-) diff --git a/src/assets/i18n/pl.json5 b/src/assets/i18n/pl.json5 index 7e6ef92c227..39e1fce8e62 100644 --- a/src/assets/i18n/pl.json5 +++ b/src/assets/i18n/pl.json5 @@ -1,2621 +1,2621 @@ { - "401.help":"Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", - "401.link.home-page":"Zabierz mnie na stronę główną", - "401.unauthorized":"nieautoryzowany", - "403.help":"Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "403.link.home-page":"Zabierz mnie na stronę główną", - "403.forbidden":"zabroniony", - "404.help":"Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", - "404.link.home-page":"Zabierz mnie na stronę główną", - "404.page-not-found":"strona nie została znaleziona", - "admin.curation-tasks.breadcrumbs":"Systemowe zadania administracyjne", - "admin.curation-tasks.title":"Systemowe zadania administracyjne", - "admin.curation-tasks.header":"Systemowe zadania administracyjne", - "admin.registries.bitstream-formats.breadcrumbs":"Rejestr formatów", - "admin.registries.bitstream-formats.create.breadcrumbs":"Format strumienia bitów", - "admin.registries.bitstream-formats.create.failure.content":"Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", - "admin.registries.bitstream-formats.create.failure.head":"Nie udało się", - "admin.registries.bitstream-formats.create.head":"Utwórz nowy format", - "admin.registries.bitstream-formats.create.new":"Dodaj nowy format", - "admin.registries.bitstream-formats.create.success.content":"Nowy format strumienia bitów został pomyślnie utworzony.", - "admin.registries.bitstream-formats.create.success.head":"Udało się", - "admin.registries.bitstream-formats.delete.failure.amount":"Nie udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.failure.head":"Nie udało się", - "admin.registries.bitstream-formats.delete.success.amount":"Udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.success.head":"Udało się", - "admin.registries.bitstream-formats.description":"Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", - "admin.registries.bitstream-formats.edit.breadcrumbs":"Format strumienia bitów", - "admin.registries.bitstream-formats.edit.description.hint":"", - "admin.registries.bitstream-formats.edit.description.label":"Opis", - "admin.registries.bitstream-formats.edit.extensions.hint":"Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", - "admin.registries.bitstream-formats.edit.extensions.label":"Rozszerzenia plików", - "admin.registries.bitstream-formats.edit.extensions.placeholder":"Wprowadź rozszerzenie pliku bez kropki", - "admin.registries.bitstream-formats.edit.failure.content":"Wystąpił błąd podczas edycji formatu pliku.", - "admin.registries.bitstream-formats.edit.failure.head":"Nie udało się", - "admin.registries.bitstream-formats.edit.head":"Format plików: {{ format }}", - "admin.registries.bitstream-formats.edit.internal.hint":"Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", - "admin.registries.bitstream-formats.edit.internal.label":"Wewnętrzny", - "admin.registries.bitstream-formats.edit.mimetype.hint":"Typ MIME powiązany z tym formatem, nie musi być unikalny.", - "admin.registries.bitstream-formats.edit.mimetype.label":"Typ MIME", - "admin.registries.bitstream-formats.edit.shortDescription.hint":"Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", - "admin.registries.bitstream-formats.edit.shortDescription.label":"Nazwa", - "admin.registries.bitstream-formats.edit.success.content":"Format strumienia bitów został pomyślnie edytowany.", - "admin.registries.bitstream-formats.edit.success.head":"Udało się", - "admin.registries.bitstream-formats.edit.supportLevel.hint":"Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", - "admin.registries.bitstream-formats.edit.supportLevel.label":"Obsługiwany format", - "admin.registries.bitstream-formats.head":"Rejestr formatów", - "admin.registries.bitstream-formats.no-items":"Brak formatów plików do wyświetlenia.", - "admin.registries.bitstream-formats.table.delete":"Usuń zaznaczone", - "admin.registries.bitstream-formats.table.deselect-all":"Odznacz wszystkie", - "admin.registries.bitstream-formats.table.internal":"wewnętrzne", - "admin.registries.bitstream-formats.table.mimetype":"Typ MIME", - "admin.registries.bitstream-formats.table.name":"Nazwa", - "admin.registries.bitstream-formats.table.return":"Powrót", - "admin.registries.bitstream-formats.table.supportLevel.KNOWN":"Znane", - "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED":"Wspierane", - "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN":"Nieznane", - "admin.registries.bitstream-formats.table.supportLevel.head":"Obsługiwany format", - "admin.registries.bitstream-formats.title":"Rejestr formatów plików", - "admin.registries.metadata.breadcrumbs":"Rejestr metadanych", - "admin.registries.metadata.description":"W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", - "admin.registries.metadata.form.create":"Utwórz schemat metadanych", - "admin.registries.metadata.form.edit":"Edytuj schemat metadanych", - "admin.registries.metadata.form.name":"Nazwa", - "admin.registries.metadata.form.namespace":"Nazwa schematu", - "admin.registries.metadata.head":"Rejestr metadanych", - "admin.registries.metadata.schemas.no-items":"Brak rejestrów metadanych do pokazania.", - "admin.registries.metadata.schemas.table.delete":"Usuń zaznaczone", - "admin.registries.metadata.schemas.table.id":"ID", - "admin.registries.metadata.schemas.table.name":"Nazwa", - "admin.registries.metadata.schemas.table.namespace":"Nazwa schematu", - "admin.registries.metadata.title":"Rejestr metadanych", - "admin.registries.schema.breadcrumbs":"Schemat metadanych", - "admin.registries.schema.description":"Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", - "admin.registries.schema.fields.head":"Pola schematu metadanych", - "admin.registries.schema.fields.no-items":"Brak pól metadanych do pokazania.", - "admin.registries.schema.fields.table.delete":"Usuń zaznaczone", - "admin.registries.schema.fields.table.field":"Pole", - "admin.registries.schema.fields.table.scopenote":"Uwagi", - "admin.registries.schema.form.create":"Stwórz pole metadanych", - "admin.registries.schema.form.edit":"Edytuj pole metadanych", - "admin.registries.schema.form.element":"Element", - "admin.registries.schema.form.qualifier":"Kwalifikator", - "admin.registries.schema.form.scopenote":"Uwagi", - "admin.registries.schema.head":"Schemat metadanych", - "admin.registries.schema.notification.created":"Udało się utworzyć schemat metdanych \"{{prefix}}\"", - "admin.registries.schema.notification.deleted.failure":"Nie udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.deleted.success":"Udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.edited":"Udało się edytować schemat metadanych \"{{prefix}}\"", - "admin.registries.schema.notification.failure":"Błąd", - "admin.registries.schema.notification.field.created":"Udało się utworzyć pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.field.deleted.failure":"Nie udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.deleted.success":"Udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.edited":"SUdało się edytować pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.success":"Udało się", - "admin.registries.schema.return":"Powrót", - "admin.registries.schema.title":"Rejestr schematów metadanych", - "admin.access-control.epeople.actions.delete":"Usuń użytkownika", - "admin.access-control.epeople.actions.impersonate":"Personifikuj użytkownika", - "admin.access-control.epeople.actions.reset":"Zresetuj hasło", - "admin.access-control.epeople.actions.stop-impersonating":"Przestań personifikować użytkownika", - "admin.access-control.epeople.breadcrumbs":"Użytkownicy", - "admin.access-control.epeople.title":"Użytkownicy", - "admin.access-control.epeople.head":"Użytkownicy", - "admin.access-control.epeople.search.head":"Wyszukaj", - "admin.access-control.epeople.button.see-all":"Przeglądaj wszystko", - "admin.access-control.epeople.search.scope.metadata":"Metadane", - "admin.access-control.epeople.search.scope.email":"E-mail", - "admin.access-control.epeople.search.button":"Wyszukaj", - "admin.access-control.epeople.search.placeholder":"Wyszukaj użytkownika...", - "admin.access-control.epeople.button.add":"Dodaj użytkownika", - "admin.access-control.epeople.table.id":"ID", - "admin.access-control.epeople.table.name":"Nazwa", - "admin.access-control.epeople.table.email":"E-mail", - "admin.access-control.epeople.table.edit":"Edytuj", - "admin.access-control.epeople.table.edit.buttons.edit":"Edytuj \"{{name}}\"", - "admin.access-control.epeople.table.edit.buttons.edit-disabled":"Brak uprawnień do edycji wybranej grupy", - "admin.access-control.epeople.table.edit.buttons.remove":"Usuń \"{{name}}\"", - "admin.access-control.epeople.no-items":"Brak użytkowników do wyświetlenia.", - "admin.access-control.epeople.form.create":"Utwórz użytkownika", - "admin.access-control.epeople.form.edit":"Edytuj użytkownika", - "admin.access-control.epeople.form.firstName":"Imię", - "admin.access-control.epeople.form.lastName":"Nazwisko", - "admin.access-control.epeople.form.email":"E-mail", - "admin.access-control.epeople.form.emailHint":"Adres e-mail musi być poprawny", - "admin.access-control.epeople.form.canLogIn":"Możliwość zalogowania", - "admin.access-control.epeople.form.requireCertificate":"Wymagany certyfikat", - "admin.access-control.epeople.form.return":"Powrót", - "admin.access-control.epeople.form.notification.created.success":"Udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure":"Nie udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure.emailInUse":"Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.failure.emailInUse":"Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.success":"Udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.edited.failure":"Nie udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.success":"Udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.failure":"Nie udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.groupsEPersonIsMemberOf":"Członek grup:", - "admin.access-control.epeople.form.table.id":"ID", - "admin.access-control.epeople.form.table.name":"Nazwa", - "admin.access-control.epeople.form.table.collectionOrCommunity":"Zbiór/kolekcja", - "admin.access-control.epeople.form.memberOfNoGroups":"Ten użytkownik nie jest członkiem żadnej grupy", - "admin.access-control.epeople.form.goToGroups":"Dodaj do grup", - "admin.access-control.epeople.notification.deleted.failure":"Nie udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.epeople.notification.deleted.success":"Udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.groups.title":"Grupy", - "admin.access-control.groups.breadcrumbs":"Grupy", - "admin.access-control.groups.singleGroup.breadcrumbs":"Edytuj grupę", - "admin.access-control.groups.title.singleGroup":"Edytuj grupę", - "admin.access-control.groups.title.addGroup":"Nowa grupa", - "admin.access-control.groups.addGroup.breadcrumbs":"Nowa grupa", - "admin.access-control.groups.head":"Grupy/role", - "admin.access-control.groups.button.add":"Dodaj grupę", - "admin.access-control.groups.search.head":"Szukaj grup", - "admin.access-control.groups.button.see-all":"Przeszukaj wszystko", - "admin.access-control.groups.search.button":"Wyszukaj", - "admin.access-control.groups.search.placeholder":"Wyszukaj grupy...", - "admin.access-control.groups.table.id":"ID", - "admin.access-control.groups.table.name":"Nazwa", - "admin.access-control.groups.table.collectionOrCommunity":"Zbiór/kolekcja", - "admin.access-control.groups.table.members":"Członkowie", - "admin.access-control.groups.table.edit":"Edytuj", - "admin.access-control.groups.table.edit.buttons.edit":"Edytuj \"{{name}}\"", - "admin.access-control.groups.no-items":"Nie znaleziono grup z podaną frazą lub podanym UUID", - "admin.access-control.groups.notification.deleted.success":"Udało się usunąć grupę \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.title":"Nie udało się usunąć grupy \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.content":"Powód: \"{{cause}}\"", - "admin.access-control.groups.form.alert.permanent":"Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", - "admin.access-control.groups.form.alert.workflowGroup":"Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", - "admin.access-control.groups.form.head.create":"Utwórz grupę", - "admin.access-control.groups.form.head.edit":"Edytuj grupę", - "admin.access-control.groups.form.groupName":"Nazwa grupy", - "admin.access-control.groups.form.groupCommunity":"Zbiór lub kolekcja", - "admin.access-control.groups.form.groupDescription":"Opis", - "admin.access-control.groups.form.notification.created.success":"Udało się utworzyć grupę \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure":"Nie udało się utworzyć grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure.groupNameInUse":"Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", - "admin.access-control.groups.form.notification.edited.failure":"Nie udało się edytować grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.edited.failure.groupNameInUse":"Nazwa \"{{name}}\" już w użyciu!", - "admin.access-control.groups.form.notification.edited.success":"Udało się edytować grupę \"{{name}}\"", - "admin.access-control.groups.form.actions.delete":"Usuń grupę", - "admin.access-control.groups.form.delete-group.modal.header":"Usuń grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.info":"Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.cancel":"Anuluj", - "admin.access-control.groups.form.delete-group.modal.confirm":"Usuń", - "admin.access-control.groups.form.notification.deleted.success":"Udało się usunąć grupę \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.title":"Nie udało się usunąć grupy \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.content":"Powód: \"{{ cause }}\"", - "admin.access-control.groups.form.members-list.head":"Użytkownik", - "admin.access-control.groups.form.members-list.search.head":"Dodaj użytkownika", - "admin.access-control.groups.form.members-list.button.see-all":"Pokaż wszystkich", - "admin.access-control.groups.form.members-list.headMembers":"Aktualni członkowie", - "admin.access-control.groups.form.members-list.search.scope.metadata":"Metadane", - "admin.access-control.groups.form.members-list.search.scope.email":"E-mail", - "admin.access-control.groups.form.members-list.search.button":"Wyszukaj", - "admin.access-control.groups.form.members-list.table.id":"ID", - "admin.access-control.groups.form.members-list.table.name":"Nazwa", - "admin.access-control.groups.form.members-list.table.identity":"Tożsamość", - "admin.access-control.groups.form.members-list.table.email":"E-mail", - "admin.access-control.groups.form.members-list.table.netid":"NetID", - "admin.access-control.groups.form.members-list.table.edit":"Usuń / Dodaj", - "admin.access-control.groups.form.members-list.table.edit.buttons.remove":"Usuń użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.addMember":"Udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.addMember":"Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.deleteMember":"Udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.deleteMember":"Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.table.edit.buttons.add":"Dodaj użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.members-list.no-members-yet":"Brak użytkowników w grupie, wyszukaj ich i dodaj.", - "admin.access-control.groups.form.members-list.no-items":"Nie znaleziono użytkowników podczas wyszukiwania", - "admin.access-control.groups.form.subgroups-list.notification.failure":"Coś poszło nie tak: \"{{cause}}\"", - "admin.access-control.groups.form.subgroups-list.head":"Grupy", - "admin.access-control.groups.form.subgroups-list.search.head":"Dodaj podgrupę", - "admin.access-control.groups.form.subgroups-list.button.see-all":"Przeglądaj wszystkie", - "admin.access-control.groups.form.subgroups-list.headSubgroups":"Aktualne podgrupy", - "admin.access-control.groups.form.subgroups-list.search.button":"Wyszukaj", - "admin.access-control.groups.form.subgroups-list.table.id":"ID", - "admin.access-control.groups.form.subgroups-list.table.name":"Nazwa", - "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity":"Zbiór/kolekcja", - "admin.access-control.groups.form.subgroups-list.table.edit":"Usuń / Dodaj", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove":"Usuń podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add":"Dodaj podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup":"Aktualna grupa", - "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup":"Udało się dodać podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup":"Nie udało się dodać podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup":"Udało się usunąć podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup":"Nie udało się usunąć podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup":"Ta grupa jest już stworzona i nie może zostać dodana pononwie.", - "admin.access-control.groups.form.subgroups-list.no-items":"Nie znaleziono grup z tą nazwą lub UUID", - "admin.access-control.groups.form.subgroups-list.no-subgroups-yet":"Brak podgrup w grupie.", - "admin.access-control.groups.form.return":"Powrót", - "admin.search.breadcrumbs":"Wyszukiwanie administracyjne", - "admin.search.collection.edit":"Edytuj", - "admin.search.community.edit":"Edytuj", - "admin.search.item.delete":"Usuń", - "admin.search.item.edit":"Edytuj", - "admin.search.item.make-private":"Ukryj", - "admin.search.item.make-public":"Upublicznij", - "admin.search.item.move":"Przenieś", - "admin.search.item.reinstate":"Zmień instancję", - "admin.search.item.withdraw":"Wycofane", - "admin.search.title":"Wyszukiwanie administracyjne", - "administrativeView.search.results.head":"Wyszukiwanie administracyjne", - "admin.workflow.breadcrumbs":"Zarządzaj procesem", - "admin.workflow.title":"Zarządzaj procesem", - "admin.workflow.item.workflow":"Proces", - "admin.workflow.item.delete":"Usuń", - "admin.workflow.item.send-back":"Odeślij z powrotem", - "admin.metadata-import.breadcrumbs":"Importuj metadane", - "admin.metadata-import.title":"Importuj metadane", - "admin.metadata-import.page.header":"Importuj metadane", - "admin.metadata-import.page.help":"Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", - "admin.metadata-import.page.dropMsg":"Upuść plik w formacie CSV", - "admin.metadata-import.page.dropMsgReplace":"Upuść, aby zastąpić metadane w formacie CSV do importu", - "admin.metadata-import.page.button.return":"Powrót", - "admin.metadata-import.page.button.proceed":"Zastosuj", - "admin.metadata-import.page.error.addFile":"Najpierw wybierz plik!", - "auth.errors.invalid-user":"Niewłaściwy adres e-mail lub hasło.", - "auth.messages.expired":"Twoja sesja wygasła. Zaloguj się ponownie.", - "auth.messages.token-refresh-failed":"Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", - "bitstream.download.page":"Pobieranie {{bitstream}}...", - "bitstream.download.page.back":"Powrót", - "bitstream.edit.authorizations.link":"Edytuj polityki plików", - "bitstream.edit.authorizations.title":"Edytuj polityki plików", - "bitstream.edit.return":"Powrót", - "bitstream.edit.bitstream":"Pliki: ", - "bitstream.edit.form.description.hint":"Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", - "bitstream.edit.form.description.label":"Opis", - "bitstream.edit.form.embargo.hint":"Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", - "bitstream.edit.form.embargo.label":"Embargo do wybranej daty", - "bitstream.edit.form.fileName.hint":"Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", - "bitstream.edit.form.fileName.label":"Nazwa pliku", - "bitstream.edit.form.newFormat.label":"Opisz nowy format", - "bitstream.edit.form.newFormat.hint":"Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", - "bitstream.edit.form.primaryBitstream.label":"Pierwotny plik", - "bitstream.edit.form.selectedFormat.hint":"Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", - "bitstream.edit.form.selectedFormat.label":"Wybrany format", - "bitstream.edit.form.selectedFormat.unknown":"Tego formatu nie ma na liście", - "bitstream.edit.notifications.error.format.title":"Wystąpił błąd podczas zapisu formatu pliku", - "bitstream.edit.notifications.saved.content":"Zmiany w pliku zostały zapisane.", - "bitstream.edit.notifications.saved.title":"Plik został zapisany", - "bitstream.edit.title":"Edytuj plik", - "bitstream-request-a-copy.alert.canDownload1":"Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", - "bitstream-request-a-copy.alert.canDownload2":"tutaj", - "bitstream-request-a-copy.header":"Wystąp o kopię wybranego pliku", - "bitstream-request-a-copy.intro":"Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", - "bitstream-request-a-copy.intro.bitstream.one":"Wystąpienie o dostęp do następujących plików: ", - "bitstream-request-a-copy.intro.bitstream.all":"Wystąpienie o dostęp do wszystkich plików. ", - "bitstream-request-a-copy.name.label":"Imię *", - "bitstream-request-a-copy.name.error":"Imię jest wymagane", - "bitstream-request-a-copy.email.label":"Adres e-mail *", - "bitstream-request-a-copy.email.hint":"Plik zostanie przesłany na podany adres e-mail", - "bitstream-request-a-copy.email.error":"Proszę wprowadzić prawidłowy adres e-mail", - "bitstream-request-a-copy.allfiles.label":"Pliki", - "bitstream-request-a-copy.files-all-false.label":"Tylko plik, dla którego wystąpiono o dostęp", - "bitstream-request-a-copy.files-all-true.label":"Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", - "bitstream-request-a-copy.message.label":"Wiadomość", - "bitstream-request-a-copy.return":"Powrót", - "bitstream-request-a-copy.submit":"Wystąp o kopię", - "bitstream-request-a-copy.submit.success":"Wystąpienie o dostęp do pliku zostało przesłane.", - "bitstream-request-a-copy.submit.error":"Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", - "browse.comcol.by.author":"wg autorów", - "browse.comcol.by.dateissued":"wg daty wydania", - "browse.comcol.by.subject":"wg tematu", - "browse.comcol.by.title":"wg tytułu", - "browse.comcol.head":"Przeglądaj", - "browse.empty":"Brak rekordów do wyświetlenia.", - "browse.metadata.author":"Autor", - "browse.metadata.dateissued":"Data wydania", - "browse.metadata.subject":"Temat", - "browse.metadata.title":"Tytuł", - "browse.metadata.author.breadcrumbs":"Przeglądaj wg autorów", - "browse.metadata.dateissued.breadcrumbs":"Przeglądaj wg daty wydania", - "browse.metadata.subject.breadcrumbs":"Przeglądaj wg tematów", - "browse.metadata.title.breadcrumbs":"Przeglądaj wg tytułów", - "browse.startsWith.choose_start":"(Wybierz start)", - "browse.startsWith.choose_year":"(Wybierz rok)", - "browse.startsWith.choose_year.label":"Wybierz rok wydania", - "browse.startsWith.jump":"Przejdź do miejsca w indeksie:", - "browse.startsWith.months.april":"kwiecień", - "browse.startsWith.months.august":"sierpień", - "browse.startsWith.months.december":"grudzień", - "browse.startsWith.months.february":"luty", - "browse.startsWith.months.january":"styczeń", - "browse.startsWith.months.july":"lipiec", - "browse.startsWith.months.june":"czerwiec", - "browse.startsWith.months.march":"marzec", - "browse.startsWith.months.may":"maj", - "browse.startsWith.months.none":"(wybierz miesiąc)", - "browse.startsWith.months.none.label":"Wybierz miesiąc wydania", - "browse.startsWith.months.november":"listopad", - "browse.startsWith.months.october":"październik", - "browse.startsWith.months.september":"wrzesień", - "browse.startsWith.submit":"Zastosuj", - "browse.startsWith.type_date":"Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", - "browse.startsWith.type_date.label":"Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", - "browse.startsWith.type_text":"Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", - "browse.title":"Przeglądaj {{ collection }} wg {{ field }} {{ value }}", - "chips.remove":"Usuń chip", - "collection.create.head":"Utwórz kolekcję", - "collection.create.notifications.success":"Udało się utworzyć kolekcję", - "collection.create.sub-head":"Udało się utworzyć kolekcję dla zbioru {{ parent }}", - "collection.curate.header":"Administrator kolekcji: {{collection}}", - "collection.delete.cancel":"Anuluj", - "collection.delete.confirm":"Zatwierdź", - "collection.delete.processing":"Usuwanie", - "collection.delete.head":"Usuń kolekcję", - "collection.delete.notification.fail":"Kolekcja nie może być usunięt", - "collection.delete.notification.success":"Udało się usunąć kolekcję", - "collection.delete.text":"Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", - "collection.edit.delete":"Usuń kolekcję", - "collection.edit.head":"Edytuj kolekcję", - "collection.edit.breadcrumbs":"Edytuj kolekcję", - "collection.edit.tabs.mapper.head":"Item Mapper", - "collection.edit.tabs.item-mapper.title":"Edytuj kolekcję - Item Mapper", - "collection.edit.item-mapper.cancel":"Anuluj", - "collection.edit.item-mapper.collection":"Kolekcja: \"<b>{{name}}</b>\"", - "collection.edit.item-mapper.confirm":"Mapuj wybrane elementy", - "collection.edit.item-mapper.description":"To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", - "collection.edit.item-mapper.head":"Item Mapper - Mapuj pozycje z innych kolekcji", - "collection.edit.item-mapper.no-search":"Wpisz co chcesz wyszukać", - "collection.edit.item-mapper.notifications.map.error.content":"Wystąpiły błędy podczas mapowania {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.error.head":"Mapowanie błędów", - "collection.edit.item-mapper.notifications.map.success.content":"Udało się zmapować {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.success.head":"Mapowanie zakończone", - "collection.edit.item-mapper.notifications.unmap.error.content":"Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.error.head":"Usuń błędy mapowania", - "collection.edit.item-mapper.notifications.unmap.success.content":"Udało się usunąć błędy mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.success.head":"Usuwanie mapowania zakończone", - "collection.edit.item-mapper.remove":"Usuń wybrane mapowanie elementów", - "collection.edit.item-mapper.search-form.placeholder":"Wyszukaj pozycje...", - "collection.edit.item-mapper.tabs.browse":"Wyszukaj mapowane elementy", - "collection.edit.item-mapper.tabs.map":"Mapuj nowe elementy", - "collection.edit.logo.delete.title":"Usuń", - "collection.edit.logo.delete-undo.title":"Cofnij usunięcie", - "collection.edit.logo.label":"Logo kolekcji", - "collection.edit.logo.notifications.add.error":"Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", - "collection.edit.logo.notifications.add.success":"Udało się przesłać logo kolekcji.", - "collection.edit.logo.notifications.delete.success.title":"Logo usunięte", - "collection.edit.logo.notifications.delete.success.content":"Udało się usunąć logo kolekcji", - "collection.edit.logo.notifications.delete.error.title":"Błąd podczas usuwania loga", - "collection.edit.logo.upload":"Upuść logo kolekcji, aby je wgrać", - "collection.edit.notifications.success":"Udało się edytować kolekcję", - "collection.edit.return":"Powrót", - "collection.edit.tabs.curate.head":"Kurator", - "collection.edit.tabs.curate.title":"Edytowanie kolekcji - kurator", - "collection.edit.tabs.authorizations.head":"Autoryzacje", - "collection.edit.tabs.authorizations.title":"Edytowanie kolekcji - autoryzacje", - "collection.edit.tabs.metadata.head":"Edytuj metadane", - "collection.edit.tabs.metadata.title":"Edytowanie kolekcji - metadane", - "collection.edit.tabs.roles.head":"Przypisz role", - "collection.edit.tabs.roles.title":"Edytowanie kolekcji - role", - "collection.edit.tabs.source.external":"Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", - "collection.edit.tabs.source.form.errors.oaiSource.required":"Musisz wskazać id docelowej kolekcji.", - "collection.edit.tabs.source.form.harvestType":"Odczytywanie zawartości", - "collection.edit.tabs.source.form.head":"Skonfiguruj zewnętrzne źródło", - "collection.edit.tabs.source.form.metadataConfigId":"Format metadanych", - "collection.edit.tabs.source.form.oaiSetId":"Określony zestaw ID OAI", - "collection.edit.tabs.source.form.oaiSource":"Dostawca OAI", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS":"Odczytaj metadane i pliki (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF":"Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY":"Odczytaj tylko metadane", - "collection.edit.tabs.source.head":"Źródło treści", - "collection.edit.tabs.source.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", - "collection.edit.tabs.source.notifications.discarded.title":"Zmiany odrzucone", - "collection.edit.tabs.source.notifications.invalid.content":"Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", - "collection.edit.tabs.source.notifications.invalid.title":"Nieprawidłowe metadane", - "collection.edit.tabs.source.notifications.saved.content":"Zmiany wprowadzone w kolekcji zostały zapisane.", - "collection.edit.tabs.source.notifications.saved.title":"Źródło treści zapisane", - "collection.edit.tabs.source.title":"Collection Edit - Źródło treści", - "collection.edit.template.add-button":"Dodaj", - "collection.edit.template.breadcrumbs":"Szablon pozycji", - "collection.edit.template.cancel":"Anuluj", - "collection.edit.template.delete-button":"Usuń", - "collection.edit.template.edit-button":"Edytuj", - "collection.edit.template.error":"Wystąpił błąd podczas odzyskiwania szablonu pozycji", - "collection.edit.template.head":"Edytuj szablon dla kolekcji \"{{ collection }}\"", - "collection.edit.template.label":"Szablon pozycji", - "collection.edit.template.loading":"ładowanie szablonu pozycji...", - "collection.edit.template.notifications.delete.error":"Nie udało się usunąć szablonu pozycji", - "collection.edit.template.notifications.delete.success":"Udało się usunąć szablon pozycji", - "collection.edit.template.title":"Edytuj szablon pozycji", - "collection.form.abstract":"Opis skrócony", - "collection.form.description":"Tekst powitalny (HTML)", - "collection.form.errors.title.required":"Wpisz nazwę kolekcji", - "collection.form.license":"Licencja", - "collection.form.provenance":"Pochodzenie", - "collection.form.rights":"Tekst praw autorskich (HTML)", - "collection.form.tableofcontents":"Wiadomości (HTML)", - "collection.form.title":"Nazwa", - "collection.form.entityType":"Typ danych", - "collection.page.browse.recent.head":"Ostatnie zgłoszenia", - "collection.page.browse.recent.empty":"Brak pozycji do wyświetlenia", - "collection.page.edit":"Edytuj kolekcję", - "collection.page.handle":"Stały URI dla kolekcji", - "collection.page.license":"Licencja", - "collection.page.news":"Wiadomości", - "collection.select.confirm":"Zaakceptuj zaznaczone", - "collection.select.empty":"Brak kolekcji do wyświetlenia", - "collection.select.table.title":"Tytuł", - "collection.source.controls.head":"Kontrolki odczytywania", - "collection.source.controls.test.submit.error":"Coś poszło nie tak podczas rozpoczynania testów ustawień", - "collection.source.controls.test.failed":"Scenariusz testowy ustawień nie zadziałał", - "collection.source.controls.test.completed":"Scenariusz testowy ustawień został zakończony", - "collection.source.controls.test.submit":"Konfiguracja testowa", - "collection.source.controls.test.running":"Testowanie konfiguracji...", - "collection.source.controls.import.submit.success":"Import został rozpoczęty", - "collection.source.controls.import.submit.error":"Coś poszło nie tak podczas rozpoczynania importu", - "collection.source.controls.import.submit":"Importuj teraz", - "collection.source.controls.import.running":"Importowanie...", - "collection.source.controls.import.failed":"Wystąpił błąd podczas importu", - "collection.source.controls.import.completed":"Import zakończony", - "collection.source.controls.reset.submit.success":"Reset ustawień i powtórny import zostały rozpoczęte poprawnie", - "collection.source.controls.reset.submit.error":"Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", - "collection.source.controls.reset.failed":"Wystąpił błąd podczas resetowania ustawień i ponownego importu", - "collection.source.controls.reset.completed":"Reset ustawień i powtórny import zostały zakończone", - "collection.source.controls.reset.submit":"Resetowanie i powtórny import", - "collection.source.controls.reset.running":"Resetowanie i powtórny import...", - "collection.source.controls.harvest.status":"Status odczytywania:", - "collection.source.controls.harvest.start":"Czas rozpoczęcia odczytywania:", - "collection.source.controls.harvest.last":"Czas ostatniego odczytywania:", - "collection.source.controls.harvest.message":"Informacje nt. odczytywania:", - "collection.source.controls.harvest.no-information":"bd.", - "collection.source.update.notifications.error.content":"Te ustawienia zostały przetestowane i nie działają.", - "collection.source.update.notifications.error.title":"Błąd serwera", - "communityList.breadcrumbs":"Lista zbiorów", - "communityList.tabTitle":"Lista zbiorów", - "communityList.title":"Lista zbiorów", - "communityList.showMore":"Pokaż więcej", - "community.create.head":"Utwórz zbiór", - "community.create.notifications.success":"Udało się utworzyć zbiór", - "community.create.sub-head":"Utwórz podzbiór dla zbioru {{ parent }}", - "community.curate.header":"Zarządzaj zbiorem: {{community}}", - "community.delete.cancel":"Anuluj", - "community.delete.confirm":"Potwierdź", - "community.delete.processing":"Usuwanie...", - "community.delete.head":"Usuń zbiór", - "community.delete.notification.fail":"Zbiór nie może być usunięty", - "community.delete.notification.success":"Udało się usunąć zbiór", - "community.delete.text":"Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", - "community.edit.delete":"Usuń ten zbiór", - "community.edit.head":"Edytuj zbiór", - "community.edit.breadcrumbs":"Edytuj zbiór", - "community.edit.logo.delete.title":"Usuń logo", - "community.edit.logo.delete-undo.title":"Cofnij usunięcie", - "community.edit.logo.label":"Logo zbioru", - "community.edit.logo.notifications.add.error":"Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", - "community.edit.logo.notifications.add.success":"Przesłanie loga powiodło się.", - "community.edit.logo.notifications.delete.success.title":"Logo usunięte", - "community.edit.logo.notifications.delete.success.content":"Usunięcie loga zbioru powiodło się", - "community.edit.logo.notifications.delete.error.title":"Błąd podczas usuwania loga", - "community.edit.logo.upload":"Upuść logo zbioru, aby je przesłać", - "community.edit.notifications.success":"Udało się edytować zbiór", - "community.edit.notifications.unauthorized":"Nie masz uprawnień, aby wykonać te zmiany", - "community.edit.notifications.error":"Wystąpił błąd podczas edycji zbioru", - "community.edit.return":"Cofnij", - "community.edit.tabs.curate.head":"Administruj", - "community.edit.tabs.curate.title":"Edycja zbioru - administrator", - "community.edit.tabs.metadata.head":"Edytuj metadane", - "community.edit.tabs.metadata.title":"Edycja zbioru - metadane", - "community.edit.tabs.roles.head":"Przypisz role", - "community.edit.tabs.roles.title":"Edycja zbioru - role", - "community.edit.tabs.authorizations.head":"Uprawnienia", - "community.edit.tabs.authorizations.title":"Edycja zbioru - uprawnienia", - "community.listelement.badge":"Zbiór", - "comcol-role.edit.no-group":"Brak", - "comcol-role.edit.create":"Utwórz", - "comcol-role.edit.restrict":"Ogranicz", - "comcol-role.edit.delete":"Usuń", - "comcol-role.edit.community-admin.name":"Administratorzy", - "comcol-role.edit.collection-admin.name":"Administratorzy", - "comcol-role.edit.community-admin.description":"Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", - "comcol-role.edit.collection-admin.description":"Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", - "comcol-role.edit.submitters.name":"Zgłaszający", - "comcol-role.edit.submitters.description":"Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", - "comcol-role.edit.item_read.name":"Domyślny dostęp do odczytu pozycji", - "comcol-role.edit.item_read.description":"Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", - "comcol-role.edit.item_read.anonymous-group":"Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", - "comcol-role.edit.bitstream_read.name":"Domyślny dostęp do oczytu plików", - "comcol-role.edit.bitstream_read.description":"Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", - "comcol-role.edit.bitstream_read.anonymous-group":"Domyślny status odczytu dla nowych plików to Anonimowy.", - "comcol-role.edit.editor.name":"Redaktorzy", - "comcol-role.edit.editor.description":"Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", - "comcol-role.edit.finaleditor.name":"Redaktorzy końcowi", - "comcol-role.edit.finaleditor.description":"Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", - "comcol-role.edit.reviewer.name":"Recenzenci", - "comcol-role.edit.reviewer.description":"Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", - "community.form.abstract":"Opis skrócony", - "community.form.description":"Wstęp (HTML)", - "community.form.errors.title.required":"Wprowadź nazwę zbioru", - "community.form.rights":"Prawa autoskie (HTML)", - "community.form.tableofcontents":"Wiadomości (HTML)", - "community.form.title":"Nazwa", - "community.page.edit":"Edytuj ten zbiór", - "community.page.handle":"Stały URI zbioru", - "community.page.license":"Licencja", - "community.page.news":"Wiadomości", - "community.all-lists.head":"Podzbiory i kolekcje", - "community.sub-collection-list.head":"Kolekcje w tym zbiorze", - "community.sub-community-list.head":"Kolekcje w tym zbiorze", - "cookies.consent.accept-all":"Zaakceptuj wszystko", - "cookies.consent.accept-selected":"Zaakceptuj wybrane", - "cookies.consent.app.opt-out.description":"Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", - "cookies.consent.app.opt-out.title":"(możesz ją wyłaczyć)", - "cookies.consent.app.purpose":"cel", - "cookies.consent.app.required.description":"Ta aplikacja jest zawsze wymagana", - "cookies.consent.app.required.title":"(zawsze wymagana)", - "cookies.consent.update":"Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", - "cookies.consent.close":"Zamknij", - "cookies.consent.decline":"Odrzuć", - "cookies.consent.content-notice.description":"Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", - "cookies.consent.content-notice.learnMore":"Dostosuj", - "cookies.consent.content-modal.description":"Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", - "cookies.consent.content-modal.privacy-policy.name":"polityka prywatności", - "cookies.consent.content-modal.privacy-policy.text":"Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", - "cookies.consent.content-modal.title":"Informacje, które zbieramy", - "cookies.consent.app.title.authentication":"Logowanie", - "cookies.consent.app.description.authentication":"Musisz się zalogować", - "cookies.consent.app.title.preferences":"Preferencje", - "cookies.consent.app.description.preferences":"Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.acknowledgement":"Zgody", - "cookies.consent.app.description.acknowledgement":"Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.google-analytics":"Google Analytics", - "cookies.consent.app.description.google-analytics":"Pozwól na śledzenie do celów statystycznych", - "cookies.consent.purpose.functional":"Funkcjonalne", - "cookies.consent.purpose.statistical":"Statystyczne", - "curation-task.task.checklinks.label":"Sprawdź odnośniki w metadanych", - "curation-task.task.noop.label":"NOOP", - "curation-task.task.profileformats.label":"Profil formatów plików", - "curation-task.task.requiredmetadata.label":"Sprawdź poprawność wymaganych metadanych", - "curation-task.task.translate.label":"Microsoft Translator", - "curation-task.task.vscan.label":"Skan antywirusowy", - "curation.form.task-select.label":"Zadanie:", - "curation.form.submit":"Start", - "curation.form.submit.success.head":"Udało się rozpocząć zadanie administratora", - "curation.form.submit.success.content":"Zostaniesz przeniesiony na stronę procesu.", - "curation.form.submit.error.head":"Nie udało się się zakończyć zadania administratora", - "curation.form.submit.error.content":"Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", - "curation.form.handle.label":"Automatyzacja:", - "curation.form.handle.hint":"Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", - "deny-request-copy.email.message":"Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "deny-request-copy.email.subject":"Wystąp o kopię dokumentu", - "deny-request-copy.error":"Wystąpił błąd", - "deny-request-copy.header":"Odrzuć prośbę o przesłanie kopii dokumentu", - "deny-request-copy.intro":"Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", - "deny-request-copy.success":"Z powodzeniem odrzucono prośbę o udostępnienie pozycji", - "dso.name.untitled":"Brak tytułu", - "dso-selector.claim.item.head":"Wskazówki profilu", - "dso-selector.claim.item.body":"Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", - "dso-selector.claim.item.create-from-scratch":"Utwórz nowy", - "dso-selector.claim.item.not-mine-label":"Żaden nie jest mój", - "dso-selector.create.collection.head":"Nowa kolekcja", - "dso-selector.create.collection.sub-level":"Utwórz nową kolekcję w", - "dso-selector.create.community.head":"Nowy zbiór", - "dso-selector.create.community.sub-level":"Utwórz nowy zbiór", - "dso-selector.create.community.top-level":"Utwórz nowy nadrzędny zbiór", - "dso-selector.create.item.head":"Nowa pozycja", - "dso-selector.create.item.sub-level":"Utwórz nową pozycję w", - "dso-selector.create.submission.head":"Nowe zgłoszenie", - "dso-selector.edit.collection.head":"Edytuj kolekcję", - "dso-selector.edit.community.head":"Edytuj zbiór", - "dso-selector.edit.item.head":"Edytuj pozycję", - "dso-selector.error.title":"Wystąpił błąd podczas wyszukiwania typu {{ type }}", - "dso-selector.export-metadata.dspaceobject.head":"Eksportuj metadane z", - "dso-selector.no-results":"Nie znaleziono {{ type }}", - "dso-selector.placeholder":"Wyszukaj {{ type }}", - "dso-selector.select.collection.head":"Wybierz kolekcję", - "dso-selector.set-scope.community.head":"Wybierz wyszukiwanie zakresu", - "dso-selector.set-scope.community.button":"Wyszukaj w całym DSpace", - "dso-selector.set-scope.community.input-header":"Wyszukaj zbiór lub kolekcję", - "confirmation-modal.export-metadata.header":"Eksportuj metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.info":"Czy na pewno chcesz eksportować metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.cancel":"Anuluj", - "confirmation-modal.export-metadata.confirm":"Eksportuj", - "confirmation-modal.delete-eperson.header":"Usuń użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.info":"Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.cancel":"Anuluj", - "confirmation-modal.delete-eperson.confirm":"Usuń", - "error.bitstream":"Wystąpił błąd podczas tworzenia plików", - "error.browse-by":"Wystąpił błąd podczas tworzenia pozycji", - "error.collection":"Wystąpił błąd podczas tworzenia kolekcji", - "error.collections":"Wystąpił błąd podczas tworzenia kolekcji", - "error.community":"Wystąpił błąd podczas tworzenia ziboru", - "error.identifier":"Nie znaleziono pozycji z podanym identyfikatorem", - "error.default":"Błąd", - "error.item":"Wystąpił błąd podczas tworzenia pozycji", - "error.items":"Wystąpił błąd podczas tworzenia pozycji", - "error.objects":"Wystąpił błąd podczas tworzenia obiektów", - "error.recent-submissions":"Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", - "error.search-results":"Wystąpił błąd podczas tworzenia wyników wyszukiwania", - "error.sub-collections":"Wystąpił błąd podczas tworzenia podkolekcji", - "error.sub-communities":"Wystąpił błąd podczas tworzenia podzbiorów", - "error.submission.sections.init-form-error":"Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", - "error.top-level-communities":"Błąd podczas pobierania nadrzędnego zbioru", - "error.validation.license.notgranted":"Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", - "error.validation.pattern":"Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", - "error.validation.filerequired":"Przesłanie pliku jest obowiązkowe", - "error.validation.required":"Pole jest wymagane", - "error.validation.NotValidEmail":"E-mail nie jest poprawny", - "error.validation.emailTaken":"E-mail jest już zarejestrowany", - "error.validation.groupExists":"Ta grupa już istnieje", - "file-section.error.header":"Błąd podczas uzyskiwania plików dla tej pozycji", - "footer.copyright":"copyright © 2002-{{ year }}", - "footer.link.dspace":"oprogramowanie DSpace", - "footer.link.lyrasis":"LYRASIS", - "footer.link.cookies":"Ustawienia plików cookies", - "footer.link.privacy-policy":"Polityka prywatności", - "footer.link.end-user-agreement":"Umowa użytkownika", - "forgot-email.form.header":"Nie pamiętam hasła", - "forgot-email.form.info":"Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "forgot-email.form.email":"Adres e-mail *", - "forgot-email.form.email.error.required":"Uzupełnij adres e-mail", - "forgot-email.form.email.error.pattern":"Uzupełnij prawidłowy adres e-mail", - "forgot-email.form.email.hint":"Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "forgot-email.form.submit":"Wyślij", - "forgot-email.form.success.head":"Wysłano wiadomość weryfikacyjną", - "forgot-email.form.success.content":"Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "forgot-email.form.error.head":"Błąd podczas rejestracji adresu e-mail", - "forgot-email.form.error.content":"Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", - "forgot-password.title":"Nie pamiętam hasła", - "forgot-password.form.head":"Nie pamiętam hasła", - "forgot-password.form.info":"Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", - "forgot-password.form.card.security":"Bezpieczeństwo", - "forgot-password.form.identification.header":"Identifikacja", - "forgot-password.form.identification.email":"Adres e-mail: ", - "forgot-password.form.label.password":"Hasło", - "forgot-password.form.label.passwordrepeat":"Potwierdź hasło", - "forgot-password.form.error.empty-password":"Wpisz hasło poniżej.", - "forgot-password.form.error.matching-passwords":"Hasła nie są identyczne.", - "forgot-password.form.notification.error.title":"Błąd podczas próby ustawienia nowego hasła", - "forgot-password.form.notification.success.content":"Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", - "forgot-password.form.notification.success.title":"Resetowanie hasła udane", - "forgot-password.form.submit":"Wpisz hasło", - "form.add":"Dodaj", - "form.add-help":"Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", - "form.cancel":"Anuluj", - "form.clear":"Wyczyść", - "form.clear-help":"Kliknij tutaj, aby usunąć wybraną wartość", - "form.discard":"Odrzuć", - "form.drag":"Przeciągnij", - "form.edit":"Edytuj", - "form.edit-help":"Kliknij tutaj, aby edytować wybraną wartość", - "form.first-name":"Imię", - "form.last-name":"Nazwisko", - "form.loading":"Ładowanie...", - "form.lookup":"Przeglądaj", - "form.lookup-help":"Kliknij tutaj, aby zobaczyć istniejące powiązania", - "form.no-results":"Nie znaleziono rezultatów", - "form.no-value":"Nie wprowadzono wartości", - "form.remove":"Usuń", - "form.save":"Zapisz", - "form.save-help":"Zapisz zmiany", - "form.search":"Wyszukaj", - "form.search-help":"Kliknij tutaj, aby wyszukać w istniejących komentarzach", - "form.submit":"Zapisz", - "form.repeatable.sort.tip":"Upuść nową pozycję w nowym miejscu", - "grant-deny-request-copy.deny":"Nie przesyłaj kopii", - "grant-deny-request-copy.email.back":"Cofnij", - "grant-deny-request-copy.email.message":"Wiadomości", - "grant-deny-request-copy.email.message.empty":"Proszę wprowadzić wiadomość", - "grant-deny-request-copy.email.permissions.info":"W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", - "grant-deny-request-copy.email.permissions.label":"Ustaw jako otwarty dostęp", - "grant-deny-request-copy.email.send":"Wyślij", - "grant-deny-request-copy.email.subject":"Temat", - "grant-deny-request-copy.email.subject.empty":"Wpisz temat", - "grant-deny-request-copy.grant":"Wyślij kopię", - "grant-deny-request-copy.header":"Prośba o przesłanie kopii dokumentu", - "grant-deny-request-copy.home-page":"Zabierz mnie na stronę główną", - "grant-deny-request-copy.intro1":"Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", - "grant-deny-request-copy.intro2":"Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", - "grant-deny-request-copy.processed":"Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "grant-request-copy.email.message":"Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "grant-request-copy.email.subject":"Prośba o kopię dokumentu", - "grant-request-copy.error":"Wystąpił błąd", - "grant-request-copy.header":"Zezwól na wysłanie kopii dokumentu", - "grant-request-copy.intro":"To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", - "grant-request-copy.success":"Prośba o dostęp do dokumentu została przyjęta", - "home.description":"", - "home.breadcrumbs":"Strona główna", - "home.search-form.placeholder":"Przeszukaj repozytorium...", - "home.title":"Strona główna", - "home.top-level-communities.head":"Zbiory w DSpace", - "home.top-level-communities.help":"Przeszukaj kolekcje", - "info.end-user-agreement.accept":"Przeczytałem/am i akceptuję umowę użytkownika", - "info.end-user-agreement.accept.error":"Błąd wystąpił podczas akceptowania umowy użytkownika", - "info.end-user-agreement.accept.success":"Udało się zaktualizować umowę użytkownika", - "info.end-user-agreement.breadcrumbs":"Umowa użytkownika", - "info.end-user-agreement.buttons.cancel":"Anuluj", - "info.end-user-agreement.buttons.save":"Zapisz", - "info.end-user-agreement.head":"Umowa użytkownika", - "info.end-user-agreement.title":"Umowa użytkownika", - "info.privacy.breadcrumbs":"Oświadczenie polityki prywatności", - "info.privacy.head":"Oświadczenie polityki prywatności", - "info.privacy.title":"Oświadczenie polityki prywatności", - "item.alerts.private":"Ta pozycja jest prywatna", - "item.alerts.withdrawn":"Ta pozycja została wycofana", - "item.edit.authorizations.heading":"Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", - "item.edit.authorizations.title":"Edytuj politykę tej pozycji", - "item.badge.private":"Prywatny status publikacji", - "item.badge.withdrawn":"Wycofane publikacje", - "item.bitstreams.upload.bundle":"Pakiet", - "item.bitstreams.upload.bundle.placeholder":"Wybierz pakiet", - "item.bitstreams.upload.bundle.new":"Utworz pakiet", - "item.bitstreams.upload.bundles.empty":"Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", - "item.bitstreams.upload.cancel":"Anuluj", - "item.bitstreams.upload.drop-message":"Upuść plik, aby przesłać", - "item.bitstreams.upload.item":"Pozycja: ", - "item.bitstreams.upload.notifications.bundle.created.content":"Udało się utworzyć nowy pakiet.", - "item.bitstreams.upload.notifications.bundle.created.title":"Utwórz pakiet", - "item.bitstreams.upload.notifications.upload.failed":"Zweryfikuj pliki przed spróbowaniem ponownie.", - "item.bitstreams.upload.title":"Prześlij strumień bitów", - "item.edit.bitstreams.bundle.edit.buttons.upload":"Prześlij", - "item.edit.bitstreams.bundle.displaying":"Obecnie wyświetlono {{ amount }} plików z {{ total }}.", - "item.edit.bitstreams.bundle.load.all":"Załaduj wszystkie ({{ total }})", - "item.edit.bitstreams.bundle.load.more":"Załaduj więcej", - "item.edit.bitstreams.bundle.name":"PACZKA: {{ name }}", - "item.edit.bitstreams.discard-button":"Odrzuć", - "item.edit.bitstreams.edit.buttons.download":"Pobierz", - "item.edit.bitstreams.edit.buttons.drag":"Przeciągnij", - "item.edit.bitstreams.edit.buttons.edit":"Edytuj", - "item.edit.bitstreams.edit.buttons.remove":"Usuń", - "item.edit.bitstreams.edit.buttons.undo":"Cofnij zmiany", - "item.edit.bitstreams.empty":"Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", - "item.edit.bitstreams.headers.actions":"Akcje", - "item.edit.bitstreams.headers.bundle":"Paczka", - "item.edit.bitstreams.headers.description":"Opis", - "item.edit.bitstreams.headers.format":"Format", - "item.edit.bitstreams.headers.name":"Nazwa", - "item.edit.bitstreams.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", - "item.edit.bitstreams.notifications.discarded.title":"Zmiany odrzucone", - "item.edit.bitstreams.notifications.move.failed.title":"Błąd podczas przenoszenia plików", - "item.edit.bitstreams.notifications.move.saved.content":"Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", - "item.edit.bitstreams.notifications.move.saved.title":"Zmiana pozycji została zapisana", - "item.edit.bitstreams.notifications.outdated.content":"Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", - "item.edit.bitstreams.notifications.outdated.title":"Zmiany nieaktualne", - "item.edit.bitstreams.notifications.remove.failed.title":"Błąd podczas usuwania pliku", - "item.edit.bitstreams.notifications.remove.saved.content":"Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", - "item.edit.bitstreams.notifications.remove.saved.title":"Zmiany dotyczące usunięcia zapisane", - "item.edit.bitstreams.reinstate-button":"Cofnij", - "item.edit.bitstreams.save-button":"Zapisz", - "item.edit.bitstreams.upload-button":"Prześlij", - "item.edit.delete.cancel":"Anuluj", - "item.edit.delete.confirm":"Usuń", - "item.edit.delete.description":"Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", - "item.edit.delete.error":"Błąd wystąpił podczas usuwania pozycji", - "item.edit.delete.header":"Usuń pozycję: {{ id }}", - "item.edit.delete.success":"Ta pozycja została usunięta", - "item.edit.head":"Edytuj pozycję", - "item.edit.breadcrumbs":"Edytuj pozycję", - "item.edit.tabs.disabled.tooltip":"Nie masz dostępu do tej strony", - "item.edit.tabs.mapper.head":"Mapper kolekcji", - "item.edit.tabs.item-mapper.title":"Edytowanie pozycji - Mapper kolekcji", - "item.edit.item-mapper.buttons.add":"Mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.buttons.remove":"Usuń mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.cancel":"Anuluj", - "item.edit.item-mapper.description":"To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", - "item.edit.item-mapper.head":"Mapper pozycji - Mapowanie pozycji do kolekcji", - "item.edit.item-mapper.item":"Pozycja: \"<b>{{name}}</b>\"", - "item.edit.item-mapper.no-search":"Wpisz zapytanie, które chcesz wyszukać", - "item.edit.item-mapper.notifications.add.error.content":"Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.add.error.head":"Błędy mapowania", - "item.edit.item-mapper.notifications.add.success.content":"Udało się zmapować elementy dla {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.add.success.head":"Mapowanie zakończone", - "item.edit.item-mapper.notifications.remove.error.content":"Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.remove.error.head":"Usunięcie mapowania błędów", - "item.edit.item-mapper.notifications.remove.success.content":"Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.remove.success.head":"Usuwanie mapowania zakończone", - "item.edit.item-mapper.search-form.placeholder":"Przeszukaj kolekcje...", - "item.edit.item-mapper.tabs.browse":"Przeglądaj zmapowane kolekcje", - "item.edit.item-mapper.tabs.map":"Mapuj nowe kolekcje", - "item.edit.metadata.add-button":"Dodaj", - "item.edit.metadata.discard-button":"Odrzuć", - "item.edit.metadata.edit.buttons.edit":"Edytuj", - "item.edit.metadata.edit.buttons.remove":"Usuń", - "item.edit.metadata.edit.buttons.undo":"Cofnij zmiany", - "item.edit.metadata.edit.buttons.unedit":"Zatrzymaj edycję", - "item.edit.metadata.empty":"Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", - "item.edit.metadata.headers.edit":"Edytuj", - "item.edit.metadata.headers.field":"Pole", - "item.edit.metadata.headers.language":"Język", - "item.edit.metadata.headers.value":"Wartość", - "item.edit.metadata.metadatafield.invalid":"Wybierz aktualne pole metadanych", - "item.edit.metadata.notifications.discarded.content":"Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", - "item.edit.metadata.notifications.discarded.title":"Zmiany odrzucone", - "item.edit.metadata.notifications.error.title":"Wystąpił błąd", - "item.edit.metadata.notifications.invalid.content":"Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", - "item.edit.metadata.notifications.invalid.title":"Nieprawidłowe metadane", - "item.edit.metadata.notifications.outdated.content":"Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", - "item.edit.metadata.notifications.outdated.title":"Zmiany nieaktualne", - "item.edit.metadata.notifications.saved.content":"Twoje zmiany metadanych tej pozycji zostały zapisane.", - "item.edit.metadata.notifications.saved.title":"Metadane zostały zapisane", - "item.edit.metadata.reinstate-button":"Cofnij", - "item.edit.metadata.save-button":"Zapisz", - "item.edit.modify.overview.field":"Pole", - "item.edit.modify.overview.language":"Język", - "item.edit.modify.overview.value":"Wartość", - "item.edit.move.cancel":"Anuluj", - "item.edit.move.save-button":"Zapisz", - "item.edit.move.discard-button":"Odrzuć", - "item.edit.move.description":"Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", - "item.edit.move.error":"Wystąpił błąd podczas przenoszenia pozycji", - "item.edit.move.head":"Przenieś pozycję: {{id}}", - "item.edit.move.inheritpolicies.checkbox":"Dziedziczenie polityk", - "item.edit.move.inheritpolicies.description":"Dziedzczenie domyślnych polityk z kolekcji docelowej", - "item.edit.move.move":"Przenieś", - "item.edit.move.processing":"Przenoszenie...", - "item.edit.move.search.placeholder":"Wpisz zapytanie, aby wyszukać w kolekcjach", - "item.edit.move.success":"Pozycja została przeniesiona", - "item.edit.move.title":"Przenieś pozycję", - "item.edit.private.cancel":"Anuluj", - "item.edit.private.confirm":"Ukryj", - "item.edit.private.description":"Czy chcesz ukryć tę pozycję?", - "item.edit.private.error":"Wystąpił błąd podczas ukrywania pozycji", - "item.edit.private.header":"Ukryj pozycję: {{ id }}", - "item.edit.private.success":"Pozycja jest teraz ukryta", - "item.edit.public.cancel":"Anuluj", - "item.edit.public.confirm":"Upublicznij", - "item.edit.public.description":"Czy chcesz upublicznić tę pozycję?", - "item.edit.public.error":"Wystąpił błąd podczas upubliczniania pozycji", - "item.edit.public.header":"Upublicznij pozycję: {{ id }}", - "item.edit.public.success":"Pozycja jest teraz publiczna", - "item.edit.reinstate.cancel":"Anuluj", - "item.edit.reinstate.confirm":"Przywróć", - "item.edit.reinstate.description":"Czy chcesz przywrócić tę pozycję?", - "item.edit.reinstate.error":"Wystąpił błąd podczas przywracania pozycji", - "item.edit.reinstate.header":"Przywróć pozycję: {{ id }}", - "item.edit.reinstate.success":"Pozycja została przywrócona", - "item.edit.relationships.discard-button":"Odrzuć", - "item.edit.relationships.edit.buttons.add":"Dodaj", - "item.edit.relationships.edit.buttons.remove":"Usuń", - "item.edit.relationships.edit.buttons.undo":"Cofnij zmiany", - "item.edit.relationships.no-relationships":"Brak relacji", - "item.edit.relationships.notifications.discarded.content":"Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", - "item.edit.relationships.notifications.discarded.title":"Zmiany zostały cofnięte", - "item.edit.relationships.notifications.failed.title":"Wystąpił błąd podczas edytowania relacji", - "item.edit.relationships.notifications.outdated.content":"Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", - "item.edit.relationships.notifications.outdated.title":"Zmiany są nieaktualne", - "item.edit.relationships.notifications.saved.content":"Twoje zmiany w relacjach tej pozycji zostały zapisane.", - "item.edit.relationships.notifications.saved.title":"Relacje zostały zapisane", - "item.edit.relationships.reinstate-button":"Cofnij", - "item.edit.relationships.save-button":"Zapisz", - "item.edit.relationships.no-entity-type":"Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", - "item.edit.return":"Cofnij", - "item.edit.tabs.bitstreams.head":"Pliki", - "item.edit.tabs.bitstreams.title":"Edycja pozycji - pliki", - "item.edit.tabs.curate.head":"Administruj", - "item.edit.tabs.curate.title":"Edytowanie pozycji - administruj", - "item.edit.tabs.metadata.head":"Metadane", - "item.edit.tabs.metadata.title":"Edycja pozycji - metadane", - "item.edit.tabs.relationships.head":"Relacje", - "item.edit.tabs.relationships.title":"Edycja pozycja - relacje", - "item.edit.tabs.status.buttons.authorizations.button":"Dostępy...", - "item.edit.tabs.status.buttons.authorizations.label":"Określu dostęp do pozycji", - "item.edit.tabs.status.buttons.delete.button":"Usuń permanentnie", - "item.edit.tabs.status.buttons.delete.label":"Usuń pozycję permanentnie", - "item.edit.tabs.status.buttons.mappedCollections.button":"Zmapowane kolekcje", - "item.edit.tabs.status.buttons.mappedCollections.label":"Zarządzaj mapowanymi kolekcjami", - "item.edit.tabs.status.buttons.move.button":"Przenieś...", - "item.edit.tabs.status.buttons.move.label":"Przenieś pozycję do innej kolekcji", - "item.edit.tabs.status.buttons.private.button":"Ukryj...", - "item.edit.tabs.status.buttons.private.label":"Ukry pozycję", - "item.edit.tabs.status.buttons.public.button":"Upublicznij...", - "item.edit.tabs.status.buttons.public.label":"Upublicznij pozycję", - "item.edit.tabs.status.buttons.reinstate.button":"Przywróć...", - "item.edit.tabs.status.buttons.reinstate.label":"Przywróć pozycję", - "item.edit.tabs.status.buttons.unauthorized":"You're not authorized to perform this action", - "item.edit.tabs.status.buttons.withdraw.button":"Wycofaj...", - "item.edit.tabs.status.buttons.withdraw.label":"Wycofaj z repozytorium", - "item.edit.tabs.status.description":"Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", - "item.edit.tabs.status.head":"Status", - "item.edit.tabs.status.labels.handle":"Identyfikator", - "item.edit.tabs.status.labels.id":"ID pozycji", - "item.edit.tabs.status.labels.itemPage":"Strona pozycji", - "item.edit.tabs.status.labels.lastModified":"Ostatnia modyfikacja", - "item.edit.tabs.status.title":"Edycja pozycji - Status", - "item.edit.tabs.versionhistory.head":"Historia wersji", - "item.edit.tabs.versionhistory.title":"Edycja pozycji - historia wersji", - "item.edit.tabs.versionhistory.under-construction":"Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", - "item.edit.tabs.view.head":"Widok pozycji", - "item.edit.tabs.view.title":"Edycja pozycji - widok", - "item.edit.withdraw.cancel":"Anuluj", - "item.edit.withdraw.confirm":"Wycofaj", - "item.edit.withdraw.description":"Czy na pewno chcesz wycofać pozycję?", - "item.edit.withdraw.error":"Wystąpił błąd podczas wycofywania pozycji", - "item.edit.withdraw.header":"Wycofaj pozycję: {{ id }}", - "item.edit.withdraw.success":"Pozycja została wycofana", - "item.listelement.badge":"Pozycja", - "item.page.description":"Opis", - "item.page.journal-issn":"ISSN czasopisma", - "item.page.journal-title":"Tytuł czasopisma", - "item.page.publisher":"Wydawca", - "item.page.titleprefix":"Pozycja: ", - "item.page.volume-title":"Tytuł tomu", - "item.search.results.head":"Wyniki wyszukiwania pozycji", - "item.search.title":"Wyszukiwanie pozycji", - "item.page.abstract":"Abstrakt", - "item.page.author":"Autorzy", - "item.page.citation":"Cytowanie", - "item.page.collections":"Kolekcje", - "item.page.collections.loading":"Ładowanie...", - "item.page.collections.load-more":"Załaduj więcej", - "item.page.date":"Data", - "item.page.edit":"Edytuj pozycję", - "item.page.files":"Pliki", - "item.page.filesection.description":"Opis:", - "item.page.filesection.download":"Pobierz", - "item.page.filesection.format":"Format:", - "item.page.filesection.name":"Nazwa:", - "item.page.filesection.size":"Rozmiar:", - "item.page.journal.search.title":"Artykuły w czasopiśmie", - "item.page.link.full":"Zobacz szczegóły", - "item.page.link.simple":"Uproszczony widok", - "item.page.person.search.title":"Artykuły tego autora", - "item.page.related-items.view-more":"Pokaż o {{ amount }} więcej", - "item.page.related-items.view-less":"Ukryj {{ amount }}", - "item.page.relationships.isAuthorOfPublication":"Publikacje", - "item.page.relationships.isJournalOfPublication":"Publikacje", - "item.page.relationships.isOrgUnitOfPerson":"Autorzy", - "item.page.relationships.isOrgUnitOfProject":"Projekty naukowe", - "item.page.subject":"Słowa kluczowe", - "item.page.uri":"URI", - "item.page.bitstreams.view-more":"Pokaż więcej", - "item.page.bitstreams.collapse":"Pokaż mniej", - "item.page.filesection.original.bundle":"Oryginalne pliki", - "item.page.filesection.license.bundle":"Licencja", - "item.page.return":"Powrót", - "item.page.version.create":"Utwórz nową wersję", - "item.page.version.hasDraft":"Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.preview.dc.identifier.doi":"DOI", - "item.preview.dc.relation.ispartof":"Czasopismo lub seria", - "item.preview.dc.identifier.isbn":"ISBN", - "item.preview.dc.identifier.uri":"Identyfikator:", - "item.preview.dc.contributor.author":"Autorzy:", - "item.preview.dc.date.issued":"Data publikacji:", - "item.preview.dc.description.abstract":"Abstrakt:", - "item.preview.dc.identifier.other":"Inny identyfikator:", - "item.preview.dc.language.iso":"Język:", - "item.preview.dc.title":"Tytuł:", - "item.preview.dc.title.alternative":"Tytuł alternatywny", - "item.preview.dc.type":"Typ:", - "item.preview.dc.identifier":"Identyfikator:", - "item.preview.dc.relation.issn":"ISSN", - "item.preview.oaire.citation.issue":"Numer wydania", - "item.preview.oaire.citation.volume":"Numer tomu", - "item.preview.person.familyName":"Nazwisko:", - "item.preview.person.givenName":"Nazwa:", - "item.preview.person.identifier.orcid":"ORCID:", - "item.preview.project.funder.name":"Fundator:", - "item.preview.project.funder.identifier":"Identyfikator fundatora:", - "item.preview.oaire.awardNumber":"ID finansowania:", - "item.preview.dc.coverage.spatial":"Jurysdykcja:", - "item.preview.oaire.fundingStream":"Źródło finansowania:", - "item.select.confirm":"Potwierdź zaznaczone", - "item.select.empty":"Brak pozycji do wyświetlenia", - "item.select.table.author":"Autor", - "item.select.table.collection":"Kolekcja", - "item.select.table.title":"Tytuł", - "item.version.history.empty":"Jeszcze nie ma innych wersji tej pozycji.", - "item.version.history.head":"Poprzednie wersje", - "item.version.history.return":"Powrót", - "item.version.history.selected":"Wybrane wersje", - "item.version.history.selected.alert":"W tym momencie wyświetlono wersję {{version}} pozycji.", - "item.version.history.table.version":"Wersja", - "item.version.history.table.item":"Pozycja", - "item.version.history.table.editor":"Redaktor", - "item.version.history.table.date":"Data", - "item.version.history.table.summary":"Podsumowanie", - "item.version.history.table.workspaceItem":"Wersja robocza", - "item.version.history.table.workflowItem":"Pozycja workflow", - "item.version.history.table.actions":"Akcja", - "item.version.history.table.action.editWorkspaceItem":"Edytuj wersję roboczą pozycji", - "item.version.history.table.action.editSummary":"Edytuj podsumowanie", - "item.version.history.table.action.saveSummary":"Zapisz edycje podsumowania", - "item.version.history.table.action.discardSummary":"Odrzuć edycje podsumowania", - "item.version.history.table.action.newVersion":"Utwórz nową wersję z tej wersji", - "item.version.history.table.action.deleteVersion":"Wersja usunięta", - "item.version.history.table.action.hasDraft":"Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.version.notice":"To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", - "item.version.create.modal.header":"Nowa wersja", - "item.version.create.modal.text":"Utwórz nową wersję tej pozycji", - "item.version.create.modal.text.startingFrom":"zaczynając od wersji {{version}}", - "item.version.create.modal.button.confirm":"Utwórz", - "item.version.create.modal.button.confirm.tooltip":"Utwórz nową wersję", - "item.version.create.modal.button.cancel":"Anuluj", - "item.version.create.modal.button.cancel.tooltip":"Nie stwarzaj nowej wersji", - "item.version.create.modal.form.summary.label":"Podsumowanie", - "item.version.create.modal.form.summary.placeholder":"Wprowadź podsumowanie nowej wersji", - "item.version.create.notification.success":"Nowa wersja została utworzona z numerem {{version}}", - "item.version.create.notification.failure":"Nowa wersja nie została utworzona", - "item.version.create.notification.inProgress":"Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", - "item.version.delete.modal.header":"Usuń wersję", - "item.version.delete.modal.text":"Czy chcesz usunąć wersję {{version}}?", - "item.version.delete.modal.button.confirm":"Usuń", - "item.version.delete.modal.button.confirm.tooltip":"Usuń wersję", - "item.version.delete.modal.button.cancel":"Anuluj", - "item.version.delete.modal.button.cancel.tooltip":"Nie usuwaj tej wersji", - "item.version.delete.notification.success":"Wersja {{version}} została usunięta", - "item.version.delete.notification.failure":"Wersja {{version}} nie została usunięta", - "item.version.edit.notification.success":"Podsumowanie wersji {{version}} zostało zmienione", - "item.version.edit.notification.failure":"Podsumowanie wersji {{version}} nie zostało zmienione", - "journal.listelement.badge":"Czasopismo", - "journal.page.description":"Opis", - "journal.page.edit":"Edytuj tę pozycję", - "journal.page.editor":"Redaktor naczelny", - "journal.page.issn":"ISSN", - "journal.page.publisher":"Wydawca", - "journal.page.titleprefix":"Czasopismo: ", - "journal.search.results.head":"Wyniki wyszukiwania czasopism", - "journal.search.title":"Wyszukiwanie czasopism", - "journalissue.listelement.badge":"Numer czasopisma", - "journalissue.page.description":"Opis", - "journalissue.page.edit":"Edytuj pozycję", - "journalissue.page.issuedate":"Data wydania", - "journalissue.page.journal-issn":"ISSN czasopisma", - "journalissue.page.journal-title":"Tytuł czasopisma", - "journalissue.page.keyword":"Słowa kluczowe", - "journalissue.page.number":"Numer", - "journalissue.page.titleprefix":"Wydanie czasopisma: ", - "journalvolume.listelement.badge":"Numer tomu czasopisma", - "journalvolume.page.description":"Opis", - "journalvolume.page.edit":"Edytuj pozycję", - "journalvolume.page.issuedate":"Data wydania", - "journalvolume.page.titleprefix":"Numer tomu czasopisma: ", - "journalvolume.page.volume":"Numer wydania", - "iiifsearchable.listelement.badge":"Multimedia dokumentu", - "iiifsearchable.page.titleprefix":"Dokument: ", - "iiifsearchable.page.doi":"Stały link: ", - "iiifsearchable.page.issue":"Wydanie: ", - "iiifsearchable.page.description":"Opis: ", - "iiifviewer.fullscreen.notice":"Wyświetl na pełnym ekranie dla lepszego widoku.", - "iiif.listelement.badge":"Multimedia obrazu", - "iiif.page.titleprefix":"Obraz: ", - "iiif.page.doi":"Stały link: ", - "iiif.page.issue":"Numer wydania: ", - "iiif.page.description":"Opis: ", - "loading.bitstream":"Ładowanie pliku...", - "loading.bitstreams":"Ładowanie plików...", - "loading.browse-by":"Ładowanie pozycji...", - "loading.browse-by-page":"Ładowanie strony...", - "loading.collection":"Ładowanie kolekcji...", - "loading.collections":"Ładowanie kolekcji...", - "loading.content-source":"Ładowanie źródła treści...", - "loading.community":"Ładowanie zbioru...", - "loading.default":"Ładowanie...", - "loading.item":"Ładowanie pozycji...", - "loading.items":"Ładowanie pozycji...", - "loading.mydspace-results":"Ładowanie pozycji...", - "loading.objects":"Ładowanie...", - "loading.recent-submissions":"Ładowanie ostatnich zgłoszeń...", - "loading.search-results":"Ładowanie wyników wyszukiwania...", - "loading.sub-collections":"Ładowanie podkolekcji...", - "loading.sub-communities":"Ładowanie podzbioru...", - "loading.top-level-communities":"Ładowanie zbioru wyszego szczebla...", - "login.form.email":"Adres e-mail", - "login.form.forgot-password":"Nie pamiętasz hasła?", - "login.form.header":"Zaloguj się do DSpace", - "login.form.new-user":"Nie masz konta? Zarejestruj się.", - "login.form.or-divider":"lub", - "login.form.orcid":"Zaloguj za pomocą ORCID", - "login.form.oidc":"Zaloguj za pomocą OIDC", - "login.form.password":"Hasło", - "login.form.shibboleth":"Zaloguj za pomocą Shibboleth", - "login.form.submit":"Zaloguj się", - "login.title":"Zaloguj", - "login.breadcrumbs":"Zaloguj", - "logout.form.header":"Wyloguj się z DSpace", - "logout.form.submit":"Wyloguj się", - "logout.title":"Wylogowywanie", - "menu.header.admin":"Panel administracyjny", - "menu.header.image.logo":"Logo repozytorium", - "menu.header.admin.description":"Menu administratora", - "menu.section.access_control":"Uprawnienia", - "menu.section.access_control_authorizations":"Dostępy", - "menu.section.access_control_groups":"Grupy", - "menu.section.access_control_people":"Użytkownicy", - "menu.section.admin_search":"Wyszukiwanie administracyjne", - "menu.section.browse_community":"Ten zbiór", - "menu.section.browse_community_by_author":"Wg autorów", - "menu.section.browse_community_by_issue_date":"Wg daty wydania", - "menu.section.browse_community_by_title":"Wg tytułów", - "menu.section.browse_global":"Wszystko na DSpace", - "menu.section.browse_global_by_author":"Wg autorów", - "menu.section.browse_global_by_dateissued":"Wg daty wydania", - "menu.section.browse_global_by_subject":"Wg tematu", - "menu.section.browse_global_by_title":"Wg tytułu", - "menu.section.browse_global_communities_and_collections":"Zbiory i kolekcje", - "menu.section.control_panel":"Panel sterowania", - "menu.section.curation_task":"Zadanie administracyjne", - "menu.section.edit":"Edytuj", - "menu.section.edit_collection":"Kolekcja", - "menu.section.edit_community":"Zbiór", - "menu.section.edit_item":"Pozycja", - "menu.section.export":"Eksport", - "menu.section.export_collection":"Kolekcja", - "menu.section.export_community":"Zbiór", - "menu.section.export_item":"Pozycja", - "menu.section.export_metadata":"Metadane", - "menu.section.icon.access_control":"Sekcja menu Uprawnienia", - "menu.section.icon.admin_search":"Sekcja menu Wyszukiwanie administracyjne", - "menu.section.icon.control_panel":"Sekcja menu Panel sterowania", - "menu.section.icon.curation_tasks":"Sekcja menu Zadanie administracyjne", - "menu.section.icon.edit":"Sekcja menu Edycja", - "menu.section.icon.export":"Sekcja menu Eksport", - "menu.section.icon.find":"Sekcja menu Wyszukiwanie", - "menu.section.icon.import":"Sekcja menu Import", - "menu.section.icon.new":"Sekcja menu Dodaj", - "menu.section.icon.pin":"Przypnij boczny pasek", - "menu.section.icon.processes":"Sekcja menu Procesy", - "menu.section.icon.registries":"Sekcja menu Rejestry", - "menu.section.icon.statistics_task":"Sekcja menu Zadanie statystyczne", - "menu.section.icon.workflow":"Sekcja menu Zarządzanie workflow", - "menu.section.icon.unpin":"Odepnij boczny pasek", - "menu.section.import":"Import", - "menu.section.import_batch":"Import masowy (ZIP)", - "menu.section.import_metadata":"Metadane", - "menu.section.new":"Dodaj", - "menu.section.new_collection":"Kolekcja", - "menu.section.new_community":"Zbiór", - "menu.section.new_item":"Pozycja", - "menu.section.new_item_version":"Wersja pozycji", - "menu.section.new_process":"Proces", - "menu.section.pin":"Przypnij pasek boczny", - "menu.section.unpin":"Odepnij pasek boczny", - "menu.section.processes":"Procesy", - "menu.section.registries":"Rejestry", - "menu.section.registries_format":"Formaty", - "menu.section.registries_metadata":"Metadane", - "menu.section.statistics":"Statystyki", - "menu.section.statistics_task":"Zadanie statystyczne", - "menu.section.toggle.access_control":"Przełącz sekcję Uprawnienia", - "menu.section.toggle.control_panel":"Przełącz sekcję Panel sterowania", - "menu.section.toggle.curation_task":"Przełącz sekcję Zadanie kuratora", - "menu.section.toggle.edit":"Przełącz sekcję Edytuj", - "menu.section.toggle.export":"Przełącz sekcję Eksport", - "menu.section.toggle.find":"Przełącz sekcję Wyszukiwanie", - "menu.section.toggle.import":"Przełącz sekcję Import", - "menu.section.toggle.new":"Przełącz nową sekcję", - "menu.section.toggle.registries":"Przełącz sekcję Rejestry", - "menu.section.toggle.statistics_task":"Przełącz sekcję Zadanie statystyczne", - "menu.section.workflow":"Zarządzaj Workflow", - "mydspace.breadcrumbs":"Mój DSpace", - "mydspace.description":"", - "mydspace.messages.controller-help":"Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", - "mydspace.messages.description-placeholder":"Wpisz swoją wiadomość tutaj...", - "mydspace.messages.hide-msg":"Ukryj wiadomość", - "mydspace.messages.mark-as-read":"Oznacz jako przeczytane", - "mydspace.messages.mark-as-unread":"Oznacz jako nieprzeczytane", - "mydspace.messages.no-content":"Brak treści.", - "mydspace.messages.no-messages":"Brak wiadomości.", - "mydspace.messages.send-btn":"Wysłano", - "mydspace.messages.show-msg":"Pokaż wiadomość", - "mydspace.messages.subject-placeholder":"Temat...", - "mydspace.messages.submitter-help":"Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", - "mydspace.messages.title":"Wiadomości", - "mydspace.messages.to":"Do", - "mydspace.new-submission":"Nowe zgłoszenie", - "mydspace.new-submission-external":"Import medatanych z zewnętrznego źródła", - "mydspace.new-submission-external-short":"Import metadanych", - "mydspace.results.head":"Twoje zadania", - "mydspace.results.no-abstract":"Brak abstraktu", - "mydspace.results.no-authors":"Brak autorów", - "mydspace.results.no-collections":"Brak kolekcji", - "mydspace.results.no-date":"Brak daty", - "mydspace.results.no-files":"Brak plików", - "mydspace.results.no-results":"Brak pozycji do wyświetlenia", - "mydspace.results.no-title":"Brak tytułu", - "mydspace.results.no-uri":"Brak Uri", - "mydspace.search-form.placeholder":"Wyszukaj w mydspace...", - "mydspace.show.workflow":"Wszystkie zadania", - "mydspace.show.workspace":"Twoje zadania", - "mydspace.status.mydspaceArchived":"Zarchiwizowano", - "mydspace.status.mydspaceValidation":"Walidacja", - "mydspace.status.mydspaceWaitingController":"Oczekiwanie na redaktora", - "mydspace.status.mydspaceWorkflow":"Workflow", - "mydspace.status.mydspaceWorkspace":"Wersja robocza", - "mydspace.title":"Mój DSpace", - "mydspace.upload.upload-failed":"Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", - "mydspace.upload.upload-failed-manyentries":"Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", - "mydspace.upload.upload-failed-moreonefile":"Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", - "mydspace.upload.upload-multiple-successful":"Utworzono {{qty}} przestrzeni roboczych.", - "mydspace.view-btn":"Widok", - "nav.browse.header":"Cały DSpace", - "nav.community-browse.header":"Wg zbiorów", - "nav.language":"Zmień język", - "nav.login":"Zaloguj", - "nav.logout":"Menu profilu użytkownika i wylogowywanie", - "nav.main.description":"Główny pasek nawigacji", - "nav.mydspace":"Mój DSpace", - "nav.profile":"Profil", - "nav.search":"Wyszukiwanie", - "nav.statistics.header":"Statystyki", - "nav.stop-impersonating":"Przestań impersonifikować użytkownika", - "nav.toggle":"Przełącz nawigację", - "nav.user.description":"Pasek profilu użytkownika", - "none.listelement.badge":"Pozycja", - "person.listelement.badge":"Osoba", - "person.listelement.no-title":"Nie znaleziono imienia", - "person.page.birthdate":"Data urodzenia", - "person.page.edit":"Edytuj pozycję", - "person.page.email":"Adres e-mail", - "person.page.firstname":"Imię", - "person.page.jobtitle":"Stanowisko", - "person.page.lastname":"Nazwisko", - "person.page.link.full":"Pokaż wszystkie metadane", - "person.page.orcid":"ORCID", - "person.page.orcid.create":"Utwórz ORCID ID", - "person.page.orcid.granted-authorizations":"Udzielone dostępy", - "person.page.orcid.grant-authorizations":"Udziel dostępu", - "person.page.orcid.link":"Połącz z ORCID ID", - "person.page.orcid.orcid-not-linked-message":"ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", - "person.page.orcid.unlink":"Odepnij z ORCID", - "person.page.orcid.unlink.processing":"Procesowanie...", - "person.page.orcid.missing-authorizations":"Brak dostępów", - "person.page.orcid.missing-authorizations-message":"Brakuj następujących dostępów:", - "person.page.orcid.no-missing-authorizations-message":"Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", - "person.page.orcid.no-orcid-message":"Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", - "person.page.orcid.profile-preferences":"Preferencje profilu", - "person.page.orcid.funding-preferences":"Preferencje finansowania", - "person.page.orcid.publications-preferences":"Preferencje publikacji", - "person.page.orcid.remove-orcid-message":"Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", - "person.page.orcid.save.preference.changes":"Aktualizuj ustawienia", - "person.page.orcid.sync-profile.affiliation":"Afiliacja", - "person.page.orcid.sync-profile.biographical":"Biografia", - "person.page.orcid.sync-profile.education":"Edukacja", - "person.page.orcid.sync-profile.identifiers":"Identyfikatory", - "person.page.orcid.sync-fundings.all":"Wszystkie źrodła finansowania", - "person.page.orcid.sync-fundings.mine":"Moje źrodła finansowania", - "person.page.orcid.sync-fundings.my_selected":"Wybrane źródła finansowania", - "person.page.orcid.sync-fundings.disabled":"Nieaktywne", - "person.page.orcid.sync-publications.all":"Wszystkie publikacje", - "person.page.orcid.sync-publications.mine":"Moje publikacje", - "person.page.orcid.sync-publications.my_selected":"Wybrane publikacje", - "person.page.orcid.sync-publications.disabled":"Nieaktywne", - "person.page.orcid.sync-queue.discard":"Odrzuć zmianę i nie synchronizuj z ORCID", - "person.page.orcid.sync-queue.discard.error":"Rekord kolejki ORCID nie został odrzucony", - "person.page.orcid.sync-queue.discard.success":"Rekord kolejki ORCID został odrzucony", - "person.page.orcid.sync-queue.empty-message":"Rejestr kolejki w ORCID jest pusty", - "person.page.orcid.sync-queue.description.affiliation":"Afiliacje", - "person.page.orcid.sync-queue.description.country":"Kraj", - "person.page.orcid.sync-queue.description.education":"Edukacja", - "person.page.orcid.sync-queue.description.external_ids":"Zewnętrzne identyfikatory", - "person.page.orcid.sync-queue.description.other_names":"Inne imiona", - "person.page.orcid.sync-queue.description.qualification":"Kwalifikacje", - "person.page.orcid.sync-queue.description.researcher_urls":"URL naukowca", - "person.page.orcid.sync-queue.description.keywords":"Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.insert":"Dodaj nowy wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.update":"Aktualizuj ten wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.delete":"Usuń ten wpis z rejestru ORCID", - "person.page.orcid.sync-queue.tooltip.publication":"Publikacja", - "person.page.orcid.sync-queue.tooltip.affiliation":"Afiliacja", - "person.page.orcid.sync-queue.tooltip.education":"Edukacja", - "person.page.orcid.sync-queue.tooltip.qualification":"Kwalifikacje", - "person.page.orcid.sync-queue.tooltip.other_names":"Inna nazwa", - "person.page.orcid.sync-queue.tooltip.country":"Kraj", - "person.page.orcid.sync-queue.tooltip.keywords":"Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.external_ids":"Zewnętrzny identyfikator", - "person.page.orcid.sync-queue.tooltip.researcher_urls":"URL naukowca", - "person.page.orcid.sync-queue.send":"Synchronizuj z rejestrem ORCID", - "person.page.orcid.sync-queue.send.unauthorized-error.title":"Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", - "person.page.orcid.sync-queue.send.unauthorized-error.content":"Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", - "person.page.orcid.sync-queue.send.bad-request-error":"Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", - "person.page.orcid.sync-queue.send.error":"Wysłanie zgłoszenia do ORCID nie powiodło się", - "person.page.orcid.sync-queue.send.conflict-error":"Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", - "person.page.orcid.sync-queue.send.not-found-warning":"Pozycja nie istnieje już w rejestrze ORCID.", - "person.page.orcid.sync-queue.send.success":"Zgłoszenie do ORCID zostało zakończone pomyślnie", - "person.page.orcid.sync-queue.send.validation-error":"Dane, które chcesz zsynchronizować z ORCID nie są poprawne", - "person.page.orcid.sync-queue.send.validation-error.amount-currency.required":"Waluta jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.external-id.required":"Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", - "person.page.orcid.sync-queue.send.validation-error.title.required":"Tytuł jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.type.required":"Typ jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.start-date.required":"Data początkowa jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.funder.required":"Instytucja finansująca jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.required":"Instytucja jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.name-required":"Nazwa instytucji jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.address-required":"Aby wysłać instytucję, należy podać adres", - "person.page.orcid.sync-queue.send.validation-error.organization.city-required":"Aby wysłać adres, należy podać miasto", - "person.page.orcid.sync-queue.send.validation-error.organization.country-required":"Aby wysłać adres, należy podać kraj", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required":"Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required":"Należy uzupełnić wartość w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required":"Należy uzupełnić źródło w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid":"Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", - "person.page.orcid.synchronization-mode":"Tryb synchronizacji", - "person.page.orcid.synchronization-mode.batch":"Wsad", - "person.page.orcid.synchronization-mode.label":"Tryb synchronizacji", - "person.page.orcid.synchronization-mode-message":"Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", - "person.page.orcid.synchronization-settings-update.success":"Opcje synchronizacji zostały zaktualizowane", - "person.page.orcid.synchronization-settings-update.error":"Opcje synchronizacji nie zostały zaktualizowane", - "person.page.orcid.synchronization-mode.manual":"Ręczna", - "person.page.orcid.scope.authenticate":"Uzyskaj swój ORCID iD", - "person.page.orcid.scope.read-limited":"Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", - "person.page.orcid.scope.activities-update":"Dodaj/aktualizuj swoje aktywności naukowe", - "person.page.orcid.scope.person-update":"Dodaj/aktualizuj inne informacje o Tobie", - "person.page.orcid.unlink.success":"Odłączenie Twojego profilu od rejestru ORCID powiodło się", - "person.page.orcid.unlink.error":"Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", - "person.page.staffid":"ID pracownika", - "person.page.titleprefix":"Osoba: ", - "person.search.results.head":"Wyniki wyszukiwania użytkowników", - "person.search.title":"Wyniki wyszukiwania użytkowników", - "process.new.select-parameters":"Parametry", - "process.new.cancel":"Anuluj", - "process.new.submit":"Zapisz", - "process.new.select-script":"Skrypt", - "process.new.select-script.placeholder":"Wybierz skrypt...", - "process.new.select-script.required":"Skrypt jest wymagany", - "process.new.parameter.file.upload-button":"Wybierz plik...", - "process.new.parameter.file.required":"Proszę wybrać plik", - "process.new.parameter.string.required":"Wartość parametru jest wymagana", - "process.new.parameter.type.value":"wartość", - "process.new.parameter.type.file":"plik", - "process.new.parameter.required.missing":"Te parametry są wymagane, ale nie zostały uzupełnione:", - "process.new.notification.success.title":"Udało się", - "process.new.notification.success.content":"Udało się stworzyć proces", - "process.new.notification.error.title":"Błąd", - "process.new.notification.error.content":"Wystąpił błąd podczas tworzenia procesu", - "process.new.header":"Utwórz nowy proces", - "process.new.title":"Utwórz nowy proces", - "process.new.breadcrumbs":"Utwórz nowy proces", - "process.detail.arguments":"Argumenty", - "process.detail.arguments.empty":"Do tego procesu nie zostały przypisane żadne argumenty", - "process.detail.back":"Cofnij", - "process.detail.output":"Dane wyjściowe procesu", - "process.detail.logs.button":"Odzyskaj dane wyjściowe procesu", - "process.detail.logs.loading":"Odzyskiwanie", - "process.detail.logs.none":"Ten proces nie ma danych wyjściowych", - "process.detail.output-files":"Pliki", - "process.detail.output-files.empty":"Ten proces nie ma żadnych plików danych wyjściowych", - "process.detail.script":"Skrypt", - "process.detail.title":"Proces: {{ id }} - {{ name }}", - "process.detail.start-time":"Czas rozpoczęcia procesu", - "process.detail.end-time":"Czas zakończenia procesu", - "process.detail.status":"Status", - "process.detail.create":"Stwórz podobny proces", - "process.overview.table.finish":"Czas zakończenia (UTC)", - "process.overview.table.id":"Identyfikator procesu", - "process.overview.table.name":"Nazwa", - "process.overview.table.start":"Czas rozpoczęcia (UTC)", - "process.overview.table.status":"Status", - "process.overview.table.user":"Użytkownik", - "process.overview.title":"Przegląd procesów", - "process.overview.breadcrumbs":"Przegląd procesów", - "process.overview.new":"Nowy", - "profile.breadcrumbs":"Zaktualizuj profil", - "profile.card.identify":"Dane", - "profile.card.security":"Bezpieczeństwo", - "profile.form.submit":"Zaktualizuj profil", - "profile.groups.head":"Posiadane uprawnienia do kolekcji", - "profile.head":"Zaktualizuj profil", - "profile.metadata.form.error.firstname.required":"Imię jest wymagane", - "profile.metadata.form.error.lastname.required":"Nazwisko jest wymagane", - "profile.metadata.form.label.email":"Adres e-mail", - "profile.metadata.form.label.firstname":"Imię", - "profile.metadata.form.label.language":"Język", - "profile.metadata.form.label.lastname":"Nazwisko", - "profile.metadata.form.label.phone":"Telefon kontaktowy", - "profile.metadata.form.notifications.success.content":"Zmiany w profilu zostały zapisane.", - "profile.metadata.form.notifications.success.title":"Profil zapisany", - "profile.notifications.warning.no-changes.content":"Nie dokonano żadnych zmian w profilu.", - "profile.notifications.warning.no-changes.title":"Brak zmian", - "profile.security.form.error.matching-passwords":"Hasła nie są identyczne.", - "profile.security.form.info":"Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", - "profile.security.form.label.password":"Hasło", - "profile.security.form.label.passwordrepeat":"Potwierdź hasło", - "profile.security.form.notifications.success.content":"Twoje zmiany w haśle zostały zapisane.", - "profile.security.form.notifications.success.title":"Hasło zapisane", - "profile.security.form.notifications.error.title":"Błąd podczas próby zmiany hasła", - "profile.security.form.notifications.error.not-same":"Hasła nie są identyczne.", - "profile.title":"Zaktualizuj profil", - "profile.card.researcher":"Profil naukowca", - "project.listelement.badge":"Projekt badawczy", - "project.page.contributor":"Autorzy", - "project.page.description":"Opis", - "project.page.edit":"Edytuj pozycję", - "project.page.expectedcompletion":"Spodziewany termin zakończenia", - "project.page.funder":"Instytucje finansujące", - "project.page.id":"ID", - "project.page.keyword":"Słowa kluczowe", - "project.page.status":"Status", - "project.page.titleprefix":"Projekt badawczy: ", - "project.search.results.head":"Wyniki wyszukiwania projektów", - "publication.listelement.badge":"Publikacja", - "publication.page.description":"Opis", - "publication.page.edit":"Edytuj pozycję", - "publication.page.journal-issn":"ISSN czasopisma", - "publication.page.journal-title":"Tytuł czasopisma", - "publication.page.publisher":"Wydawca", - "publication.page.titleprefix":"Publikacja: ", - "publication.page.volume-title":"Tytuł tomu", - "publication.search.results.head":"Wyniki wyszukiwania publikacji", - "publication.search.title":"Wyszukiwanie publikacji", - "media-viewer.next":"Nowy", - "media-viewer.previous":"Poprzedni", - "media-viewer.playlist":"Playlista", - "register-email.title":"Rejestracja nowego użytkownika", - "register-page.create-profile.header":"Stwórz profil", - "register-page.create-profile.identification.header":"Dane", - "register-page.create-profile.identification.email":"Adres e-mail", - "register-page.create-profile.identification.first-name":"Imię *", - "register-page.create-profile.identification.first-name.error":"Wpisz imię", - "register-page.create-profile.identification.last-name":"Nazwisko *", - "register-page.create-profile.identification.last-name.error":"Wpisz nazwisko", - "register-page.create-profile.identification.contact":"Telefon kontaktowy", - "register-page.create-profile.identification.language":"Język", - "register-page.create-profile.security.header":"Bezpieczeństwo", - "register-page.create-profile.security.info":"Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", - "register-page.create-profile.security.label.password":"Hasło *", - "register-page.create-profile.security.label.passwordrepeat":"Potwierdź hasło *", - "register-page.create-profile.security.error.empty-password":"Wprowadź hasło w polu poniżej.", - "register-page.create-profile.security.error.matching-passwords":"Hasła nie są identyczne.", - "register-page.create-profile.submit":"Rejestracja zakończona", - "register-page.create-profile.submit.error.content":"Coś się nie udało podczas rejestracji nowego użytkownika.", - "register-page.create-profile.submit.error.head":"Rejestracja nie powiodła się", - "register-page.create-profile.submit.success.content":"Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", - "register-page.create-profile.submit.success.head":"Rejestracja zakończona", - "register-page.registration.header":"Rejestracja nowego użytkownika", - "register-page.registration.info":"Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "register-page.registration.email":"Adres e-mail *", - "register-page.registration.email.error.required":"Wypełnij adres e-mail", - "register-page.registration.email.error.pattern":"Wypełnij poprawny adres e-mail", - "register-page.registration.email.hint":"Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "register-page.registration.submit":"Zarejestruj się", - "register-page.registration.success.head":"Wiadomość weryfikacyjna zostałą wysłana", - "register-page.registration.success.content":"Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "register-page.registration.error.head":"Błąd podczas próby rejestracji adresu e-mail", - "register-page.registration.error.content":"Błąd podczas próby rejestracji adresu e-mail: {{ email }}", - "relationships.add.error.relationship-type.content":"Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", - "relationships.add.error.server.content":"Błąd serwera", - "relationships.add.error.title":"Nie można dodać relacji", - "relationships.isAuthorOf":"Autorzy", - "relationships.isAuthorOf.Person":"Autorzy (osoby)", - "relationships.isAuthorOf.OrgUnit":"Autorzy (jednostki organizacyjne)", - "relationships.isIssueOf":"Numery czasopisma", - "relationships.isJournalIssueOf":"Numer czasopisma", - "relationships.isJournalOf":"Czasopisma", - "relationships.isOrgUnitOf":"Jednostki organizacyjne", - "relationships.isPersonOf":"Autorzy", - "relationships.isProjectOf":"Projekty badawcze", - "relationships.isPublicationOf":"Publikacje", - "relationships.isPublicationOfJournalIssue":"Artykuły", - "relationships.isSingleJournalOf":"Czasopismo", - "relationships.isSingleVolumeOf":"Tom czasopisma", - "relationships.isVolumeOf":"Tomy czasopisma", - "relationships.isContributorOf":"Autorzy", - "relationships.isContributorOf.OrgUnit":"Autor (Jednostka organizacyjna)", - "relationships.isContributorOf.Person":"Autor", - "relationships.isFundingAgencyOf.OrgUnit":"Instytucja finansująca", - "repository.image.logo":"Logo repozytorium", - "repository.title.prefix":"DSpace Angular :: ", - "researcher.profile.action.processing":"Procesowanie...", - "researcher.profile.associated":"Przypisanie profilu badacza", - "researcher.profile.create.new":"Utwórz nowy", - "researcher.profile.create.success":"Profil badacza został utworzony", - "researcher.profile.create.fail":"Wystąpił błąd poczas tworzenia profilu badacza.", - "researcher.profile.delete":"Usuń", - "researcher.profile.expose":"Ujawnij", - "researcher.profile.hide":"Ukryj", - "researcher.profile.not.associated":"Profil badacza nie został jeszcze przypisany", - "researcher.profile.view":"Widok", - "researcher.profile.private.visibility":"PRYWATNY", - "researcher.profile.public.visibility":"PUBLICZNY", - "researcher.profile.status":"Status:", - "researcherprofile.claim.not-authorized":"Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", - "researcherprofile.error.claim.body":"Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", - "researcherprofile.error.claim.title":"Błąd", - "researcherprofile.success.claim.body":"Wystąpienie z prośbą o przypisanie profilu udane", - "researcherprofile.success.claim.title":"Sukces", - "repository.title.prefixDSpace":"DSpace Angular ::", - "resource-policies.add.button":"Dodaj", - "resource-policies.add.for.":"Dodaj nową politykę", - "resource-policies.add.for.bitstream":"Dodaj nową politykę dla plików", - "resource-policies.add.for.bundle":"Dodaj nową politykę paczek", - "resource-policies.add.for.item":"Dodaj nową politykę pozycji", - "resource-policies.add.for.community":"Dodaj nową politykę zbioru", - "resource-policies.add.for.collection":"Dodaj nową politykę kolekcji", - "resource-policies.create.page.heading":"Utwórz nową politykę zasobu dla ", - "resource-policies.create.page.failure.content":"Wystąpił błąd podczas dodawania polityki zasobów.", - "resource-policies.create.page.success.content":"Działanie powiodło się", - "resource-policies.create.page.title":"Utwórz nową politykę zasobu", - "resource-policies.delete.btn":"Usuń zaznaczone", - "resource-policies.delete.btn.title":"Usuń zaznaczone polityki zasobów", - "resource-policies.delete.failure.content":"Wystąpił błąd podczas usuwania wybranych polityk zasobów.", - "resource-policies.delete.success.content":"Działanie powiodło się", - "resource-policies.edit.page.heading":"Edytuj politykę zasobu ", - "resource-policies.edit.page.failure.content":"Wystąpił błąd poczas edytowania polityki zasobu.", - "resource-policies.edit.page.success.content":"Działanie udało się", - "resource-policies.edit.page.title":"Edytuj politykę zasobu", - "resource-policies.form.action-type.label":"Wybierz ten typ akcji", - "resource-policies.form.action-type.required":"Musisz wybrać akcję polityki zasobu.", - "resource-policies.form.eperson-group-list.label":"Użytkownik lub grupa, która otrzyma uprawnienia.", - "resource-policies.form.eperson-group-list.select.btn":"Wybierz", - "resource-policies.form.eperson-group-list.tab.eperson":"Wyszukaj użytkownika", - "resource-policies.form.eperson-group-list.tab.group":"Wyszukaj grupę", - "resource-policies.form.eperson-group-list.table.headers.action":"Akcja", - "resource-policies.form.eperson-group-list.table.headers.id":"ID", - "resource-policies.form.eperson-group-list.table.headers.name":"Nazwa", - "resource-policies.form.date.end.label":"Data zakończenia", - "resource-policies.form.date.start.label":"Data rozpoczęcia", - "resource-policies.form.description.label":"Opis", - "resource-policies.form.name.label":"Nazwa", - "resource-policies.form.policy-type.label":"Wybierz typ polityki", - "resource-policies.form.policy-type.required":"Musisz wybrać typ polityki zasobu.", - "resource-policies.table.headers.action":"Akcja", - "resource-policies.table.headers.date.end":"Data zakończenia", - "resource-policies.table.headers.date.start":"Data rozpoczęcia", - "resource-policies.table.headers.edit":"Edytuj", - "resource-policies.table.headers.edit.group":"Edytuj grupę", - "resource-policies.table.headers.edit.policy":"Edytuj politykę", - "resource-policies.table.headers.eperson":"Użytkownik", - "resource-policies.table.headers.group":"Grupa", - "resource-policies.table.headers.id":"ID", - "resource-policies.table.headers.name":"Nazwa", - "resource-policies.table.headers.policyType":"typ", - "resource-policies.table.headers.title.for.bitstream":"Polityki dla plików", - "resource-policies.table.headers.title.for.bundle":"Polityki dla paczek", - "resource-policies.table.headers.title.for.item":"Polityki dla pozycji", - "resource-policies.table.headers.title.for.community":"Polityki dla zbioru", - "resource-policies.table.headers.title.for.collection":"Polityki dla kolekcji", - "search.description":"", - "search.switch-configuration.title":"Pokaż", - "search.title":"Szukaj", - "search.breadcrumbs":"Szukaj", - "search.search-form.placeholder":"Szukaj w repozytorium...", - "search.filters.applied.f.author":"Autor", - "search.filters.applied.f.dateIssued.max":"Data zakończenia", - "search.filters.applied.f.dateIssued.min":"Data rozpoczęcia", - "search.filters.applied.f.dateSubmitted":"Data zgłoszenia", - "search.filters.applied.f.discoverable":"Ukryty", - "search.filters.applied.f.entityType":"Typ pozycji", - "search.filters.applied.f.has_content_in_original_bundle":"Ma przypisane pliki", - "search.filters.applied.f.itemtype":"Typ", - "search.filters.applied.f.namedresourcetype":"Status", - "search.filters.applied.f.subject":"Temat", - "search.filters.applied.f.submitter":"Zgłaszający", - "search.filters.applied.f.jobTitle":"Stanowisko", - "search.filters.applied.f.birthDate.max":"Data zakończenia tworzenia", - "search.filters.applied.f.birthDate.min":"Data rozpoczęcia tworzenia", - "search.filters.applied.f.withdrawn":"Wycofane", - "search.filters.filter.author.head":"Autor", - "search.filters.filter.author.placeholder":"Autor", - "search.filters.filter.author.label":"Wyszukaj autora", - "search.filters.filter.birthDate.head":"Data urodzenia", - "search.filters.filter.birthDate.placeholder":"Data urodzenia", - "search.filters.filter.birthDate.label":"Wyszukaj datę urodzenia", - "search.filters.filter.collapse":"Ukryj filtr", - "search.filters.filter.creativeDatePublished.head":"Data opublikowania", - "search.filters.filter.creativeDatePublished.placeholder":"Data opublikowania", - "search.filters.filter.creativeDatePublished.label":"Wyszukaj datę opublikowania", - "search.filters.filter.creativeWorkEditor.head":"Redaktor", - "search.filters.filter.creativeWorkEditor.placeholder":"Redaktor", - "search.filters.filter.creativeWorkEditor.label":"Wyszukaj redaktora", - "search.filters.filter.creativeWorkKeywords.head":"Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.placeholder":"Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.label":"Wyszukaj temat", - "search.filters.filter.creativeWorkPublisher.head":"Wydawca", - "search.filters.filter.creativeWorkPublisher.placeholder":"Wydawca", - "search.filters.filter.creativeWorkPublisher.label":"Wyszukaj wydawcę", - "search.filters.filter.dateIssued.head":"Data", - "search.filters.filter.dateIssued.max.placeholder":"Data maksymalna", - "search.filters.filter.dateIssued.max.label":"Koniec", - "search.filters.filter.dateIssued.min.placeholder":"Data minimalna", - "search.filters.filter.dateIssued.min.label":"Start", - "search.filters.filter.dateSubmitted.head":"Data zgłoszenia", - "search.filters.filter.dateSubmitted.placeholder":"Data zgłoszenia", - "search.filters.filter.dateSubmitted.label":"Wyszukaj datę zgłoszenia", - "search.filters.filter.discoverable.head":"Ukryty", - "search.filters.filter.withdrawn.head":"Wycofane", - "search.filters.filter.entityType.head":"Typ pozycji", - "search.filters.filter.entityType.placeholder":"Typ pozycji", - "search.filters.filter.entityType.label":"Wyszukaj typ pozycji", - "search.filters.filter.expand":"Rozwiń filtr", - "search.filters.filter.has_content_in_original_bundle.head":"Ma przypisane pliki", - "search.filters.filter.itemtype.head":"Typ", - "search.filters.filter.itemtype.placeholder":"Typ", - "search.filters.filter.itemtype.label":"Wyszukaj typ", - "search.filters.filter.jobTitle.head":"Stanowisko", - "search.filters.filter.jobTitle.placeholder":"Stanowisko", - "search.filters.filter.jobTitle.label":"Wyszukaj stanowisko", - "search.filters.filter.knowsLanguage.head":"Znajomość języka", - "search.filters.filter.knowsLanguage.placeholder":"Znajomość języka", - "search.filters.filter.knowsLanguage.label":"Wyszukaj wg znajomości języka", - "search.filters.filter.namedresourcetype.head":"Status", - "search.filters.filter.namedresourcetype.placeholder":"Status", - "search.filters.filter.namedresourcetype.label":"Wyszukaj status", - "search.filters.filter.objectpeople.head":"Osoby", - "search.filters.filter.objectpeople.placeholder":"Osoby", - "search.filters.filter.objectpeople.label":"Wyszukaj użytkowników", - "search.filters.filter.organizationAddressCountry.head":"Kraj", - "search.filters.filter.organizationAddressCountry.placeholder":"Kraj", - "search.filters.filter.organizationAddressCountry.label":"Wyszukaj kraj", - "search.filters.filter.organizationAddressLocality.head":"Miasto", - "search.filters.filter.organizationAddressLocality.placeholder":"Miasto", - "search.filters.filter.organizationAddressLocality.label":"Wyszukaj miasto", - "search.filters.filter.organizationFoundingDate.head":"Data założenia", - "search.filters.filter.organizationFoundingDate.placeholder":"Data założenia", - "search.filters.filter.organizationFoundingDate.label":"Wyszukaj datę założenia", - "search.filters.filter.scope.head":"Zakres", - "search.filters.filter.scope.placeholder":"Filtr zakresu", - "search.filters.filter.scope.label":"Wyszukaj filtr zakresu", - "search.filters.filter.show-less":"Pokaż mniej", - "search.filters.filter.show-more":"Pokaż więcej", - "search.filters.filter.subject.head":"Temat", - "search.filters.filter.subject.placeholder":"Temat", - "search.filters.filter.subject.label":"Wyszukaj temat", - "search.filters.filter.submitter.head":"Zgłaszający", - "search.filters.filter.submitter.placeholder":"Zgłaszający", - "search.filters.filter.submitter.label":"Wyszukaj zgłaszającego", - "search.filters.entityType.JournalIssue":"Numer czasopisma", - "search.filters.entityType.JournalVolume":"Tom czasopisma", - "search.filters.entityType.OrgUnit":"Jednostka organizacyjna", - "search.filters.has_content_in_original_bundle.true":"Tak", - "search.filters.has_content_in_original_bundle.false":"Nie", - "search.filters.discoverable.true":"Nie", - "search.filters.discoverable.false":"Tak", - "search.filters.withdrawn.true":"Tak", - "search.filters.withdrawn.false":"Nie", - "search.filters.head":"Filtry", - "search.filters.reset":"Resetuj filtry", - "search.filters.search.submit":"Zastosuj", - "search.form.search":"Wyszukaj", - "search.form.search_dspace":"W repozytorium", - "search.form.scope.all":"W całym DSpace", - "search.results.head":"Wyniki wyszukiwania", - "default.search.results.head":"Wyniki wyszukiwania", - "search.results.no-results":"Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", - "search.results.no-results-link":"fraz podobnych do Twojego wyszukiwania", - "search.results.empty":"Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", - "search.sidebar.close":"Wróć do wyników wyszukiwania", - "search.sidebar.filters.title":"Filtry", - "search.sidebar.open":"Narzędzia wyszukiwania", - "search.sidebar.results":"wyniki", - "search.sidebar.settings.rpp":"Wyników na stronie", - "search.sidebar.settings.sort-by":"Sortuj według", - "search.sidebar.settings.title":"Ustawienia", - "search.view-switch.show-detail":"Wyświetl widok szczegółowy", - "search.view-switch.show-grid":"Wyświetl jako siatkę", - "search.view-switch.show-list":"Wyświetl jako listę", - "sorting.ASC":"Rosnąco", - "sorting.DESC":"Malejąco", - "sorting.dc.title.ASC":"Tytułami rosnąco", - "sorting.dc.title.DESC":"Tytułami malejąco", - "sorting.score.ASC":"Najmniej trafne", - "sorting.score.DESC":"Najbardziej trafne", - "sorting.dc.date.issued.ASC":"Data wydania rosnąco", - "sorting.dc.date.issued.DESC":"Data wydania malejąco", - "sorting.dc.date.accessioned.ASC":"Data dostępu rosnąco", - "sorting.dc.date.accessioned.DESC":"Data dostępu malejąco", - "sorting.lastModified.ASC":"Ostatnia modyfikacja rosnąco", - "sorting.lastModified.DESC":"Ostatnia modyfikacja malejąco", - "statistics.title":"Statystyki", - "statistics.header":"Statystyki dla {{ scope }}", - "statistics.breadcrumbs":"Statystyki", - "statistics.page.no-data":"Brak dostępnych danych", - "statistics.table.no-data":"Brak dostępnych danych", - "statistics.table.header.views":"Wyświetlenia", - "submission.edit.breadcrumbs":"Edytuj zgłoszenie", - "submission.edit.title":"Edytuj zgłoszenie", - "submission.general.cancel":"Anuluj", - "submission.general.cannot_submit":"Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", - "submission.general.deposit":"Deponuj", - "submission.general.discard.confirm.cancel":"Anuluj", - "submission.general.discard.confirm.info":"Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.general.discard.confirm.submit":"Tak, na pewno", - "submission.general.discard.confirm.title":"Odrzuć zgłoszenie", - "submission.general.discard.submit":"Odrzuć", - "submission.general.info.saved":"Zapisane", - "submission.general.info.pending-changes":"Niezapisane zmiany", - "submission.general.save":"Zapisz", - "submission.general.save-later":"Zapisz wersję roboczą", - "submission.import-external.page.title":"Importuj metdane z zewnętrznego źródła", - "submission.import-external.title":"Importuj metadane z zewnętrznego źródła", - "submission.import-external.title.Journal":"Importuj czasopismo z zewnętrznego źródła", - "submission.import-external.title.JournalIssue":"Importuj numer czasopisma z zewnętrznego źródła", - "submission.import-external.title.JournalVolume":"Importuj tom czasopisma z zewnętrznego źródła", - "submission.import-external.title.OrgUnit":"Importuj wydawcę z zewnętrznego źródła", - "submission.import-external.title.Person":"Importuj osobę z zewnętrznego źródła", - "submission.import-external.title.Project":"Importuj projekt z zewnętrznego źródła", - "submission.import-external.title.Publication":"Importuj publikację z zewnętrznego źródła", - "submission.import-external.title.none":"Importuj metadane z zewnętrznego źródła", - "submission.import-external.page.hint":"Enter a query above to find items from the web to import in to DSpace.", - "submission.import-external.back-to-my-dspace":"Powrót do MyDSpace", - "submission.import-external.search.placeholder":"Wyszukaj zewnętrzne źródła danych", - "submission.import-external.search.button":"Szukaj", - "submission.import-external.search.button.hint":"Zacznij wpisywać frazę, aby wyszukać", - "submission.import-external.search.source.hint":"Wybierz zewnętrzne źródło", - "submission.import-external.source.ads":"NASA/ADS", - "submission.import-external.source.arxiv":"arXiv", - "submission.import-external.source.cinii":"CiNii", - "submission.import-external.source.crossref":"CrossRef", - "submission.import-external.source.loading":"ładowanie...", - "submission.import-external.source.sherpaJournal":"Czasopisma w SHERPA", - "submission.import-external.source.sherpaJournalIssn":"Czasopisma w SHERPA wg ISSN", - "submission.import-external.source.sherpaPublisher":"Wydawcy w SHERPA", - "submission.import-external.source.openAIREFunding":"Finansowanie OpenAIRE API", - "submission.import-external.source.orcid":"ORCID", - "submission.import-external.source.orcidWorks":"ORCID", - "submission.import-external.source.pubmed":"Pubmed", - "submission.import-external.source.pubmedeu":"Pubmed Europe", - "submission.import-external.source.lcname":"Nazwy Biblioteki Kongresu", - "submission.import-external.source.scielo":"SciELO", - "submission.import-external.source.scopus":"Scopus", - "submission.import-external.source.vufind":"VuFind", - "submission.import-external.source.wos":"Web Of Science", - "submission.import-external.source.epo":"Europejski Urząd Patentowy (EPO)", - "submission.import-external.preview.title.Journal":"Podgląd czasopisma", - "submission.import-external.preview.title.OrgUnit":"Podgląd organizacji", - "submission.import-external.preview.title.Person":"Podgląd osoby", - "submission.import-external.preview.title.Project":"Podgląd projektu", - "submission.import-external.preview.title.Publication":"Podgląd publikacji", - "submission.import-external.preview.subtitle":"Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", - "submission.import-external.preview.button.import":"Rozpocznij zgłoszenie", - "submission.import-external.preview.error.import.title":"Błąd zgłoszenia", - "submission.import-external.preview.error.import.body":"Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", - "submission.sections.describe.relationship-lookup.close":"Zamknij", - "submission.sections.describe.relationship-lookup.external-source.added":"Udało się dodać wpis do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication":"Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal":"Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue":"Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume":"Importuj zdalny tom czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication":"Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity":"Nowy typ danych dodany!", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title":"Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding":"Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title":"Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person":"Importuj zdalną osobę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product":"Importuj zdalny produkt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment":"Importuj zdalną aparaturę badawczą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event":"Importuj zdalne wydarzenie", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding":"Importuj zdalną instytucję finansującą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit":"Importuj zdalnego wydawcę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent":"Importuj zdalnie patent", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project":"Importuj zdalnie projekt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication":"Importuj zdalnie publikację", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity":"Udało się dodać autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity":"Udało się zaimportować i dodać zewnętrznego autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority":"Nadrzędność", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new":"Importuj jako nową, lokalną, nadrzędną pozycję", - "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel":"Anuluj", - "submission.sections.describe.relationship-lookup.external-source.import-modal.collection":"Wybierz kolekcję do zaimportowania nowych pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities":"Typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new":"Importuj jako nowy lokalny typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname":"Importuj z LC Name", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid":"Importuj z ORCID", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal":"Importuj z Sherpa Journal", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher":"Importuj z Sherpa Publisher", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed":"Importuj z PubMed", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv":"Importuj z arXiv", - "submission.sections.describe.relationship-lookup.external-source.import-modal.import":"Import", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title":"Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity":"Successfully added local journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity":"Successfully imported and added external journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title":"Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity":"Udało się dodać lokalne czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity":"Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title":"Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity":"Udało się dodać lokalny numer czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity":"Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.select":"Wybierz lokalne powiązanie:", - "submission.sections.describe.relationship-lookup.search-tab.deselect-all":"Odznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.deselect-page":"Odznacz stronę", - "submission.sections.describe.relationship-lookup.search-tab.loading":"Ładowanie...", - "submission.sections.describe.relationship-lookup.search-tab.placeholder":"Wyszukaj zapytanie", - "submission.sections.describe.relationship-lookup.search-tab.search":"Zastosuj", - "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder":"Wyszukaj...", - "submission.sections.describe.relationship-lookup.search-tab.select-all":"Zaznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.select-page":"Zaznacz stronę", - "submission.sections.describe.relationship-lookup.selected":"Zaznacz {{ size }} pozycji", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication":"Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication":"Czasopisma lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project":"Projekty lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication":"Publikacje lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person":"Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit":"Lokalne jednostki organizacyjne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage":"Lokalne paczki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile":"Lokalne pliki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal":"Lokalne czasopisma ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication":"Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue":"Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication":"Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume":"Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal":"Sherpa Journals ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher":"Sherpa Publishers ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid":"ORCID ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname":"LC Names ({{ 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":"Wyszukaj instytucje finansujące", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication":"Wyszukaj finansowanie", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf":"Wyszukaj jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding":"Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication":"Projekty", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject":"Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding":"Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication":"Projekt", - "submission.sections.describe.relationship-lookup.title.isProjectOfPublication":"Projekty", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject":"Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder":"Wyszukaj...", - "submission.sections.describe.relationship-lookup.selection-tab.tab-title":"Aktualne zaznaczenie ({{ count }})", - "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication":"Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalIssue":"Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication":"Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalVolume":"Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalOfPublication":"Czasopisma", - "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication":"Autorzy", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication":"Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.Project":"Projekty", - "submission.sections.describe.relationship-lookup.title.Publication":"Publikacje", - "submission.sections.describe.relationship-lookup.title.Person":"Autorzy", - "submission.sections.describe.relationship-lookup.title.OrgUnit":"Jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.title.DataPackage":"Paczki danych", - "submission.sections.describe.relationship-lookup.title.DataFile":"Pliki danych", - "submission.sections.describe.relationship-lookup.title.Funding Agency":"Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.isFundingOfPublication":"Finansowanie", - "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf":"Nadrzędna jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown":"Przełącz na listę rozwijaną", - "submission.sections.describe.relationship-lookup.selection-tab.settings":"Ustawienia", - "submission.sections.describe.relationship-lookup.selection-tab.no-selection":"Twoje zaznaczenie jest puste.", - "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication":"Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication":"Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication":"Wybrane tomy czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.Project":"Wybrane projekty", - "submission.sections.describe.relationship-lookup.selection-tab.title.Publication":"Wybrane publikacje", - "submission.sections.describe.relationship-lookup.selection-tab.title.Person":"Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit":"Wybrane jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage":"Wybrane pakiety danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile":"Wybrane pliki danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.Journal":"Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication":"Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume":"Wybrany tom czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication":"Wybrane instytucje finansujące", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication":"Wybrane finansowanie", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue":"Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf":"Wybrana jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.crossref":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcid":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.lcname":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.epo":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scopus":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scielo":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.wos":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title":"Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.name-variant.notification.content":"Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", - "submission.sections.describe.relationship-lookup.name-variant.notification.confirm":"Zapisz nowy wariant imienia", - "submission.sections.describe.relationship-lookup.name-variant.notification.decline":"Użyj tylko w tym zgłoszeniu", - "submission.sections.ccLicense.type":"Typ licencji", - "submission.sections.ccLicense.select":"Wybierz typ licencji…", - "submission.sections.ccLicense.change":"Zmień typ licencji…", - "submission.sections.ccLicense.none":"Brak dostępnych licencji", - "submission.sections.ccLicense.option.select":"Wybierz opcję…", - "submission.sections.ccLicense.link":"Wybrano licencję:", - "submission.sections.ccLicense.confirmation":"Udzielam powyższej licencji", - "submission.sections.general.add-more":"Dodaj więcej", - "submission.sections.general.collection":"Kolekcja", - "submission.sections.general.deposit_error_notice":"Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", - "submission.sections.general.deposit_success_notice":"Udało się wprowadzić pozycję.", - "submission.sections.general.discard_error_notice":"Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", - "submission.sections.general.discard_success_notice":"Udało się odrzucić pozycję.", - "submission.sections.general.metadata-extracted":"Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", - "submission.sections.general.metadata-extracted-new-section":"Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", - "submission.sections.general.no-collection":"Nie znaleziono kolekcji", - "submission.sections.general.no-sections":"Opcje niedostępne", - "submission.sections.general.save_error_notice":"Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", - "submission.sections.general.save_success_notice":"Udało się zapisać zgłoszenie.", - "submission.sections.general.search-collection":"Szukaj kolekcji", - "submission.sections.general.sections_not_valid":"Niektóre sekcje są niekompletne.", - "submission.sections.submit.progressbar.CClicense":"Licencja Creative Commons", - "submission.sections.submit.progressbar.describe.recycle":"Odzyskaj", - "submission.sections.submit.progressbar.describe.stepcustom":"Opisz", - "submission.sections.submit.progressbar.describe.stepone":"Opisz", - "submission.sections.submit.progressbar.describe.steptwo":"Opisz", - "submission.sections.submit.progressbar.detect-duplicate":"Potencjalne duplikaty", - "submission.sections.submit.progressbar.license":"Zdeponuj licencję", - "submission.sections.submit.progressbar.upload":"Prześlij pliki", - "submission.sections.status.errors.title":"Błędy", - "submission.sections.status.valid.title":"Poprawność", - "submission.sections.status.warnings.title":"Ostrzeżenia", - "submission.sections.status.errors.aria":"ma błędy", - "submission.sections.status.valid.aria":"jest poprawne", - "submission.sections.status.warnings.aria":"ma ostrzeżenia", - "submission.sections.toggle.open":"Otwórz sekcję", - "submission.sections.toggle.close":"Zamknij sekcję", - "submission.sections.toggle.aria.open":"Rozwiń sekcję {{sectionHeader}}", - "submission.sections.toggle.aria.close":"Zwiń sekcję {{sectionHeader}}", - "submission.sections.upload.delete.confirm.cancel":"Anuluj", - "submission.sections.upload.delete.confirm.info":"Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.sections.upload.delete.confirm.submit":"Tak, na pewno", - "submission.sections.upload.delete.confirm.title":"Usuń plik", - "submission.sections.upload.delete.submit":"Usuń", - "submission.sections.upload.download.title":"Pobierz plik", - "submission.sections.upload.drop-message":"Upuść pliki, aby załączyć je do tej pozycji", - "submission.sections.upload.edit.title":"Edytuj plik", - "submission.sections.upload.form.access-condition-label":"Typ dostępu", - "submission.sections.upload.form.date-required":"Data jest wymagana.", - "submission.sections.upload.form.date-required-from":"Data przyznania dostępu od jest wymagana.", - "submission.sections.upload.form.date-required-until":"Data przyznania dostępu do jest wymagana.", - "submission.sections.upload.form.from-label":"Pozwól na dostęp od", - "submission.sections.upload.form.from-placeholder":"Od", - "submission.sections.upload.form.group-label":"Grupa", - "submission.sections.upload.form.group-required":"Grupa jest wymagana", - "submission.sections.upload.form.until-label":"Pozwól na dostęp do", - "submission.sections.upload.form.until-placeholder":"Do", - "submission.sections.upload.header.policy.default.nolist":"Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", - "submission.sections.upload.header.policy.default.withlist":"Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", - "submission.sections.upload.info":"Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", - "submission.sections.upload.no-entry":"Nie", - "submission.sections.upload.no-file-uploaded":"Pliki nie zostały jeszcze wgrane.", - "submission.sections.upload.save-metadata":"Zapisz metadane", - "submission.sections.upload.undo":"Anuluj", - "submission.sections.upload.upload-failed":"Przesyłanie nieudane", - "submission.sections.upload.upload-successful":"Przesyłanie udane", - "submission.submit.breadcrumbs":"Nowe zgłoszenie", - "submission.submit.title":"Nowe zgłoszenie", - "submission.workflow.generic.delete":"Usuń", - "submission.workflow.generic.delete-help":"Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", - "submission.workflow.generic.edit":"Edytuj", - "submission.workflow.generic.edit-help":"Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.generic.view":"Podgląd", - "submission.workflow.generic.view-help":"Wybierz tę opcję, aby wyświetlić metadane pozycji.", - "submission.workflow.tasks.claimed.approve":"Zatwierdź", - "submission.workflow.tasks.claimed.approve_help":"Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", - "submission.workflow.tasks.claimed.edit":"Edytuj", - "submission.workflow.tasks.claimed.edit_help":"Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.tasks.claimed.reject.reason.info":"Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", - "submission.workflow.tasks.claimed.reject.reason.placeholder":"Opisz powód odrzucenia zgłoszenia", - "submission.workflow.tasks.claimed.reject.reason.submit":"Odrzuć pozycję", - "submission.workflow.tasks.claimed.reject.reason.title":"Powód", - "submission.workflow.tasks.claimed.reject.submit":"Odrzuć", - "submission.workflow.tasks.claimed.reject_help":"Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", - "submission.workflow.tasks.claimed.return":"Cofnij do puli zadań", - "submission.workflow.tasks.claimed.return_help":"Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", - "submission.workflow.tasks.generic.error":"Podczas działania wystąpił błąd...", - "submission.workflow.tasks.generic.processing":"Procesowanie...", - "submission.workflow.tasks.generic.submitter":"Zgłaszający", - "submission.workflow.tasks.generic.success":"Udało się", - "submission.workflow.tasks.pool.claim":"Podejmij pracę", - "submission.workflow.tasks.pool.claim_help":"Przypisz to zadanie do siebie.", - "submission.workflow.tasks.pool.hide-detail":"Ukryj szczegóły", - "submission.workflow.tasks.pool.show-detail":"Pokaż szczegóły", - "thumbnail.default.alt":"Miniatura", - "thumbnail.default.placeholder":"Brak miniatury", - "thumbnail.project.alt":"Logo projektu", - "thumbnail.project.placeholder":"Obraz zastępczy projketu", - "thumbnail.orgunit.alt":"Logo jednostki organizacyjnej", - "thumbnail.orgunit.placeholder":"Obraz zastępczy jednostki organizacyjnej", - "thumbnail.person.alt":"Zdjęcie profilowe", - "thumbnail.person.placeholder":"Brak zdjęcia profilowego", - "title":"DSpace", - "vocabulary-treeview.header":"Widok drzewka", - "vocabulary-treeview.load-more":"Pokaż więcej", - "vocabulary-treeview.search.form.reset":"Resetuj", - "vocabulary-treeview.search.form.search":"Szukaj", - "vocabulary-treeview.search.no-result":"Brak pozycji do wyświetlenia", - "vocabulary-treeview.tree.description.nsi":"The Norwegian Science Index", - "vocabulary-treeview.tree.description.srsc":"Kategorie tematów badań", - "uploader.browse":"wyszukaj na swoim urządzeniu", - "uploader.drag-message":"Przeciągnij i upuść pliki tutaj", - "uploader.delete.btn-title":"Usuń", - "uploader.or":", lub ", - "uploader.processing":"Procesowanie", - "uploader.queue-length":"Długość kolejki", - "virtual-metadata.delete-item.info":"Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "virtual-metadata.delete-item.modal-head":"Wirtualne metadane tego powiązania", - "virtual-metadata.delete-relationship.modal-head":"Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "workflowAdmin.search.results.head":"Zarządzaj procesami", - "workflow-item.edit.breadcrumbs":"Edytuj pozycję procesu", - "workflow-item.edit.title":"Edytuj pozycję procesu", - "workflow-item.delete.notification.success.title":"Usunięte", - "workflow-item.delete.notification.success.content":"Ten element procesu został usunięty", - "workflow-item.delete.notification.error.title":"Coś poszło nie tak", - "workflow-item.delete.notification.error.content":"Ten element procesu nie mógł zostać usunięty", - "workflow-item.delete.title":"Usuń element procesu", - "workflow-item.delete.header":"Usuń element procesu", - "workflow-item.delete.button.cancel":"Anuluj", - "workflow-item.delete.button.confirm":"Usuń", - "workflow-item.send-back.notification.success.title":"SOdeślij do zgłaszającego", - "workflow-item.send-back.notification.success.content":"Ten element procesu został odesłany do zgłaszającego", - "workflow-item.send-back.notification.error.title":"Coś poszło nie tak", - "workflow-item.send-back.notification.error.content":"Ten element procesu nie mógł zostać odesłany do zgłaszającego", - "workflow-item.send-back.title":"Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.header":"Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.button.cancel":"Anuluj", - "workflow-item.send-back.button.confirm":"Odeślij", - "workflow-item.view.breadcrumbs":"Widok procesu", - "idle-modal.header":"Sesja wkrótce wygaśnie", - "idle-modal.info":"Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", - "idle-modal.log-out":"Wyloguj", - "idle-modal.extend-session":"Wydłuż sesję", - "workspace.search.results.head":"Twoje zadania", - "orgunit.listelement.badge":"Jednostka organizacyjna", - "orgunit.page.city":"Miasto", - "orgunit.page.country":"Kraj", - "orgunit.page.dateestablished":"Data założenia", - "orgunit.page.description":"Opis", - "orgunit.page.edit":"Edytuj pozycję", - "orgunit.page.id":"ID", - "orgunit.page.titleprefix":"Jednostka organizacyjna: ", - "pagination.options.description":"Opcje strony", - "pagination.results-per-page":"Wyników na stronę", - "pagination.showing.detail":"{{ range }} z {{ total }}", - "pagination.showing.label":"Teraz wyświetlane ", - "pagination.sort-direction":"Opcje sortowania", - "cookies.consent.purpose.sharing":"Udostępnianie", - "item.preview.dc.identifier.issn":"ISSN", - "500.page-internal-server-error":"Usługa niedostępna", - "500.help":"Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", - "500.link.home-page":"Zabierz mnie na stronę główną", - "error-page.description.401":"brak autoryzacji", - "error-page.description.403":"brak dostępu", - "error-page.description.500":"usługa niedostępna", - "error-page.description.404":"nie znaleziono strony", - "error-page.orcid.generic-error":"Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", - "access-status.embargo.listelement.badge":"Embargo", - "access-status.metadata.only.listelement.badge":"Tylko metadane", - "access-status.open.access.listelement.badge":"Open Access", - "access-status.restricted.listelement.badge":"Brak dostępu", - "access-status.unknown.listelement.badge":"Nieznane", - "admin.access-control.groups.table.edit.buttons.remove":"Usuń \"{{name}}\"", - "admin.metadata-import.page.validateOnly":"Tylko waliduj", - "admin.metadata-import.page.validateOnly.hint":"Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", - "bitstream.edit.form.iiifLabel.label":"Etykieta canvyIIIF", - "bitstream.edit.form.iiifLabel.hint":"Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", - "bitstream.edit.form.iiifToc.label":"Spis treści IIIF", - "bitstream.edit.form.iiifToc.hint":"Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", - "bitstream.edit.form.iiifWidth.label":"Szerokość canvy IIIF", - "bitstream.edit.form.iiifWidth.hint":"Szerokość canvy jest zwykle równa szerokości obrazu.", - "bitstream.edit.form.iiifHeight.label":"Wysokość canvy IIIF", - "bitstream.edit.form.iiifHeight.hint":"Wysokość canvy jest zwykle równa szerokości obrazu.", - "browse.back.all-results":"Wszystkie wyniki wyszukiwania", - "pagination.next.button":"Następny", - "pagination.previous.button":"Poprzedni", - "pagination.next.button.disabled.tooltip":"Brak więcej stron z wynikami wyszukiwania", - "browse.startsWith":", zaczyna się od {{ startsWith }}", - "browse.title.page":"Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", - "collection.edit.item.authorizations.load-bundle-button":"Załaduj więcej paczek", - "collection.edit.item.authorizations.load-more-button":"Załaduj więcej", - "collection.edit.item.authorizations.show-bitstreams-button":"Pokaż polityki plików dla paczek", - "comcol-role.edit.create.error.title":"Nie udało się utworzyć grupy dla roli '{{ role }}'", - "curation.form.submit.error.invalid-handle":"Nie ustalono identyfikatora dla tego obiektu", - "confirmation-modal.delete-profile.header":"Usuń profil", - "confirmation-modal.delete-profile.info":"Czy na pewno chcesz usunąć profil", - "confirmation-modal.delete-profile.cancel":"Anuluj", - "confirmation-modal.delete-profile.confirm":"Usuń", - "error.invalid-search-query":"Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", - "feed.description":"Aktualności", - "footer.link.feedback":"Prześlij uwagi", - "form.group-collapse":"Zwiń", - "form.group-collapse-help":"Kliknij tutaj, aby zwinąć", - "form.group-expand":"Rozwiń", - "form.group-expand-help":"Kliknij tutaj, aby rozwinąć", - "health.breadcrumbs":"Stan systemu", - "health-page.heading":"Stan systemu", - "health-page.info-tab":"Informacje", - "health-page.status-tab":"Status", - "health-page.error.msg":"Serwis stanu systemu jest tymczasowo niedostępny", - "health-page.property.status":"Kod statusu", - "health-page.section.db.title":"Baza danych", - "health-page.section.geoIp.title":"GeoIp", - "health-page.section.solrAuthorityCore.title":"Autentykacja", - "health-page.section.solrOaiCore.title":"OAI", - "health-page.section.solrSearchCore.title":"Wyszukiwarka", - "health-page.section.solrStatisticsCore.title":"Statystyki", - "health-page.section-info.app.title":"Backend aplikacji", - "health-page.section-info.java.title":"Java", - "health-page.status":"Status", - "health-page.status.ok.info":"operacyjny", - "health-page.status.error.info":"Wykryte problemy", - "health-page.status.warning.info":"Wykryte potencjalne problemy", - "health-page.title":"Stan systemu", - "health-page.section.no-issues":"Nie wykryto żadnych problemów", - "info.feedback.breadcrumbs":"Uwagi", - "info.feedback.head":"Uwagi", - "info.feedback.title":"Uwagi", - "info.feedback.info":"Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", - "info.feedback.email_help":"Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", - "info.feedback.send":"Prześlij uwagi", - "info.feedback.comments":"Komentarz", - "info.feedback.email-label":"Twoj adres e-mail", - "info.feedback.create.success":"Uwagi przesłane!", - "info.feedback.error.email.required":"Poprawny adres e-mail jest wymagany", - "info.feedback.error.message.required":"Treść komentarza jest wymagana", - "info.feedback.page-label":"Strona", - "info.feedback.page_help":"Ta strona odnosi się do uwag.", - "item.orcid.return":"Powrót", - "item.truncatable-part.show-more":"Pokaż więcej", - "item.truncatable-part.show-less":"Pokaż mniej", - "item.page.orcid.title":"ORCID", - "item.page.orcid.tooltip":"Otwórz ustawienia ORCID", - "item.page.claim.button":"Podejmij pracę", - "item.page.claim.tooltip":"Podejmij pracę jako profil", - "item.version.create.modal.submitted.header":"Tworzenie nowej wersji...", - "item.version.create.modal.submitted.text":"Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", - "journal-relationships.search.results.head":"Wyniki wyszukiwania czasopism", - "menu.section.icon.health":"Sekcja menu Stan systemu", - "menu.section.health":"Stan systemu", - "metadata-export-search.tooltip":"Eksportuj wyniki wyszukiwania w formacie CSV", - "metadata-export-search.submit.success":"Eksport rozpoczął się", - "metadata-export-search.submit.error":"Eksport nie rozpoczął się", - "person.page.name":"Nazwa", - "person-relationships.search.results.head":"Wyniki wyszukiwania osób", - "profile.special.groups.head":"Autoryzacja do specjalnych grup, do których należysz", - "project-relationships.search.results.head":"Wyniki wyszukiwania projektów", - "publication-relationships.search.results.head":"Wyniki wyszukiwania publikacji", - "resource-policies.edit.page.target-failure.content":"Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", - "resource-policies.edit.page.other-failure.content":"Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", - "resource-policies.form.eperson-group-list.modal.header":"Nie można zmienić typu", - "resource-policies.form.eperson-group-list.modal.text1.toGroup":"Nie można zastąpić użytkownika grupą.", - "resource-policies.form.eperson-group-list.modal.text1.toEPerson":"Nie można zastąpić grupy użytkownikiem.", - "resource-policies.form.eperson-group-list.modal.text2":"Usuń obecną polityke zasobu i stwórz nową o określonym typie.", - "resource-policies.form.eperson-group-list.modal.close":"Ok", - "search.results.view-result":"Widok", - "default-relationships.search.results.head":"Wyniki wyszukiwania", - "statistics.table.title.TotalVisits":"Wyświetlnia ogółem", - "statistics.table.title.TotalVisitsPerMonth":"Wyświetlenia w miesiącu", - "statistics.table.title.TotalDownloads":"Pobrania", - "statistics.table.title.TopCountries":"Wyświetlenia wg krajów", - "statistics.table.title.TopCities":"Wyświetlenia wg miast", - "submission.import-external.preview.title":"Podgląd pozycji", - "submission.import-external.preview.title.none":"Podgląd pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.none":"Import pozycji zdalnie", - "submission.sections.general.cannot_deposit":"Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", - "submission.sections.submit.progressbar.accessCondition":"Warunki dostępu do pozycji", - "submission.sections.submit.progressbar.sherpapolicy":"Polityki Sherpa", - "submission.sections.submit.progressbar.sherpaPolicies":"Informacje o polityce open access wydawcy.", - "submission.sections.status.info.title":"Dodatkowe informacje", - "submission.sections.status.info.aria":"Dodatkowe informacje", - "submission.sections.upload.form.access-condition-hint":"Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", - "submission.sections.upload.form.from-hint":"Wybierz datę, od której ma zostać zastosowany warunek dostępu", - "submission.sections.upload.form.until-hint":"Wybierz datę, do której ma zostać zastosowany warunek dostępu", - "submission.sections.accesses.form.discoverable-description":"Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", - "submission.sections.accesses.form.discoverable-label":"Niemożliwe do wyszukania", - "submission.sections.accesses.form.access-condition-label":"Typ warunku dostępu", - "submission.sections.accesses.form.access-condition-hint":"Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", - "submission.sections.accesses.form.date-required":"Data jest wymagana.", - "submission.sections.accesses.form.date-required-from":"Początkowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.date-required-until":"Końcowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.from-label":"Udziel dostępu od", - "submission.sections.accesses.form.from-hint":"Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.from-placeholder":"Od", - "submission.sections.accesses.form.group-label":"Grupa", - "submission.sections.accesses.form.group-required":"Grupa jest wymagana.", - "submission.sections.accesses.form.until-label":"Udziel dostępu do", - "submission.sections.accesses.form.until-hint":"Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.until-placeholder":"Do", - "submission.sections.sherpa.publication.information":"Informacje o publikacji", - "submission.sections.sherpa.publication.information.title":"Tytuł", - "submission.sections.sherpa.publication.information.issns":"Numery ISSN", - "submission.sections.sherpa.publication.information.url":"URL", - "submission.sections.sherpa.publication.information.publishers":"Wydawca", - "submission.sections.sherpa.publication.information.romeoPub":"Wydawca Romeo", - "submission.sections.sherpa.publication.information.zetoPub":"Wydawca Zeto", - "submission.sections.sherpa.publisher.policy":"Polityka wydawnicza", - "submission.sections.sherpa.publisher.policy.description":"Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", - "submission.sections.sherpa.publisher.policy.openaccess":"Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", - "submission.sections.sherpa.publisher.policy.more.information":"Aby uzuyskać więcej informacji, kliknij tutaj:", - "submission.sections.sherpa.publisher.policy.version":"Wersja", - "submission.sections.sherpa.publisher.policy.embargo":"Embargo", - "submission.sections.sherpa.publisher.policy.noembargo":"Brak embargo", - "submission.sections.sherpa.publisher.policy.nolocation":"Brak", - "submission.sections.sherpa.publisher.policy.license":"Licencja", - "submission.sections.sherpa.publisher.policy.prerequisites":"Wymagania wstępne", - "submission.sections.sherpa.publisher.policy.location":"Lokalizacja", - "submission.sections.sherpa.publisher.policy.conditions":"Wymagania", - "submission.sections.sherpa.publisher.policy.refresh":"Odśwież", - "submission.sections.sherpa.record.information":"Informacje o rekordzie", - "submission.sections.sherpa.record.information.id":"ID", - "submission.sections.sherpa.record.information.date.created":"Data utworzenia", - "submission.sections.sherpa.record.information.date.modified":"Ostatnia modyfikacja", - "submission.sections.sherpa.record.information.uri":"URI", - "submission.sections.sherpa.error.message":"Wystąpił błąd podczas pobierania informacji z Sherpa", - "submission.workspace.generic.view":"Podgląd", - "submission.workspace.generic.view-help":"Wybierz tę opcje, aby zobaczyć metadane.", - "workflow.search.results.head":"Zadania na workflow", - "workspace-item.view.breadcrumbs":"Widok wersji roboczej", - "workspace-item.view.title":"Widok wersji roboczej", - "researcher.profile.change-visibility.fail":"Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", - "person.page.orcid.link.processing":"Łączenie profilu z ORCID...", - "person.page.orcid.link.error.message":"Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", - "person.page.orcid.sync-queue.table.header.type":"Typ", - "person.page.orcid.sync-queue.table.header.description":"Opis", - "person.page.orcid.sync-queue.table.header.action":"Akcja", - "person.page.orcid.sync-queue.tooltip.project":"Projekt", - "person.page.orcid.sync-queue.send.validation-error.country.invalid":"Niewłaściwy dwuznakowy kod kraju ISO 3166", - "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid":"Wymagana data publikacji to co najmniej rok po 1900", - "person.page.orcid.synchronization-mode-funding-message":"Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", - "person.page.orcid.synchronization-mode-publication-message":"Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", - "person.page.orcid.synchronization-mode-profile-message":"Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", - "person.orcid.sync.setting":"Ustawienia synchronizacji z ORCID", - "person.orcid.registry.queue":"Kolejka rejestru z ORCID", - "person.orcid.registry.auth":"Autoryzacje z ORCID", - "home.recent-submissions.head":"Najnowsze publikacje", - "submission.sections.sherpa-policy.title-empty":"Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", - "admin.batch-import.breadcrumbs":"Import zbiorczy", - "admin.batch-import.page.dropMsg":"Drop a batch ZIP to import", - "admin.batch-import.page.dropMsgReplace":"Drop to replace the batch ZIP to import", - "admin.batch-import.page.error.addFile":"Najpierw wybierz plik (ZIP)", - "admin.batch-import.page.header":"Import masowy", - "admin.batch-import.page.help":"Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", - "admin.batch-import.page.remove":"usuń", - "admin.batch-import.page.validateOnly.hint":"Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", - "collection.form.correctionSubmissionDefinition":"Wzór zgłoszenia do prośby o korektę", - "comcol-role.edit.delete.error.title":"Nie udało się usunąć roli '{{ role }}' dla grup", - "confirmation-modal.export-batch.header":"Eksport maasowy (ZIP) {{ dsoName }}", - "confirmation-modal.export-batch.info":"Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", - "dso-selector.export-batch.dspaceobject.head":"Eksport masowy (ZIP) z", - "menu.section.export_batch":"Eksport masowy (ZIP)", - "nav.user-profile-menu-and-logout":"Profil użytkownika i wylogowywanie", - "process.detail.actions":"Akcje", - "process.detail.delete.body":"Czy na pewno chcesz usunąć bieżący proces?", - "process.detail.delete.button":"Usuń proces", - "process.detail.delete.cancel":"Anuluj", - "process.detail.delete.confirm":"Usuń proces", - "process.detail.delete.error":"Nie udało się usunąć procesu", - "process.detail.delete.header":"Usuń proces", - "process.detail.delete.success":"Proces został usunięty.", - "admin.batch-import.title":"Masowy import", - "admin.metadata-import.page.button.select-collection":"Wybierz kolekcję", - "admin.registries.bitstream-formats.table.id":"ID", - "admin.registries.schema.fields.table.id":"ID", - "cookies.consent.app.description.google-recaptcha":"Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", - "cookies.consent.app.disable-all.description":"Przełącz, aby zaakceptować lub odrzucić wszystkie", - "cookies.consent.app.disable-all.title":"Akceptowacja lub odrzucenie wszystkich", - "cookies.consent.app.title.google-recaptcha":"Google reCaptcha", - "cookies.consent.content-modal.service":"usługa", - "cookies.consent.content-modal.services":"usługi", - "cookies.consent.content-notice.description.no-privacy":"Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", - "cookies.consent.content-notice.title":"Zgoda na ciasteczka", - "cookies.consent.ok":"Zgadzam się", - "cookies.consent.purpose.registration-password-recovery":"Rejestracja i odzyskiwanie hasła", - "cookies.consent.save":"Zapisz", - "curation-task.task.citationpage.label":"Generuj stronę z cytowaniem", - "dso-selector.import-batch.dspaceobject.head":"Import masowy z", - "orgunit.listelement.no-title":"Brak tytyłu", - "process.bulk.delete.error.body":"Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", - "process.bulk.delete.error.head":"Błąd podczas usuwania procesu", - "process.bulk.delete.success":"{{count}} proces/y został/y usunięte", - "process.overview.delete":"Usuń {{count}} proces/y", - "process.overview.delete.body":"Czy na pewno usunąć {{count}} proces/y?", - "process.overview.delete.clear":"Wyczyść selekcję procesów do usunięcia", - "process.overview.delete.header":"Usuń procesy", - "process.overview.delete.processing":"{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", - "process.overview.table.actions":"Akcje", - "profile.security.form.label.current-password":"Aktualne hasło", - "profile.security.form.notifications.error.change-failed":"Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", - "profile.security.form.notifications.error.general":"Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", - "register-page.registration.error.recaptcha":"Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", - "register-page.registration.google-recaptcha.must-accept-cookies":"Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", - "register-page.registration.google-recaptcha.notification.message.error":"Wystąpił błąd podczas weryfikacji reCaptcha", - "register-page.registration.google-recaptcha.notification.message.expired":"Weryfikacja wygasła. Zweryfikuj ponownie.", - "register-page.registration.google-recaptcha.notification.title":"Google reCaptcha", - "register-page.registration.google-recaptcha.open-cookie-settings":"Otwórz ustawienia plików cookies", - "search.results.response.500":"Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", - "submission.sections.license.granted-label":"Potwierdzam akceptację powyższej licencji", - "submission.sections.license.notgranted":"Najpierw musisz zaakceptować licencję", - "submission.sections.license.required":"Najpierw musisz zaakceptować licencję", - "confirmation-modal.export-batch.confirm":"Eksportuj", - "confirmation-modal.export-batch.cancel":"Anuluj", - "admin.access-control.bulk-access.breadcrumbs":"Zbiorcza edycja dostępu do osiągnięć", - "administrativeBulkAccess.search.results.head":"Wyniki wyszukiwania", - "admin.access-control.bulk-access":"Zbiorcza edycja dostępu do osiągnięć", - "admin.access-control.bulk-access.title":"Zbiorcza edycja dostępu do osiągnięć", - "admin.access-control.bulk-access-browse.header":"Krok 1: Wybierz pozycje", - "admin.access-control.bulk-access-browse.search.header":"Wyszukaj", - "admin.access-control.bulk-access-browse.selected.header":"Obecny wybór({{number}})", - "admin.access-control.bulk-access-settings.header":"Krok 2: Działanie do wykonania", - "admin.access-control.groups.form.tooltip.editGroupPage":"Na tej stronie można edytować opcje grupy i przypisane do niej osoby. W górnej sekcji można edytować nazwę i opis grupy, chyba że jest to grupa administratorów dla zbioru i kolekcji. W tym przypadku nazwa i opis grupy są generowane automatycznie i nie można ich edytować. W kolejnych sekcjach można edytować przypisanie użytkowników do grupy. Szczegóły na [stronie](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", - "admin.access-control.groups.form.tooltip.editGroup.addEpeople":"Aby dodać lub usunąć użytkownika do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj paska wyszukiwania poniżej, aby wyszukać użytkowników (użyj listy rozwijanej po lewej stronie paska wyszukiwania, aby wybrać, czy chcesz wyszukiwać według imienia i nazwiska, czy według adresu e-mail). Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może mieć kilka stron: użyj strzałek pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", - "admin.access-control.groups.form.tooltip.editGroup.addSubgroups":"Aby dodać lub usunąć podgrupę do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj wyszukiwarki poniżej, aby wyszukać użytkowników. Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może składać się z kilku stron: użyj przycisków pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", - "admin.workflow.item.workspace":"Przestrzeń robocza", - "admin.workflow.item.policies":"Polityki", - "admin.workflow.item.supervision":"Recenzja", - "admin.batch-import.page.toggle.help":"It is possible to perform import either with file upload or via URL, use above toggle to set the input source", - "admin.metadata-import.page.error.addFileUrl":"Najpierw wpisz URL pliku!", - "admin.metadata-import.page.toggle.upload":"Prześlij", - "admin.metadata-import.page.toggle.url":"URL", - "admin.metadata-import.page.urlMsg":"Wpisz URL pliku ZIP, aby wykonać import masowy", - "advanced-workflow-action.rating.form.rating.label":"Ocena", - "advanced-workflow-action.rating.form.rating.error":"Ta pozycja musi zostać oceniona", - "advanced-workflow-action.rating.form.review.label":"Recenzja", - "advanced-workflow-action.rating.form.review.error":"Musisz wpisać tekst recenzji", - "advanced-workflow-action.rating.description":"Wybierz ocenę poniżej", - "advanced-workflow-action.rating.description-requiredDescription":"Wybierz ocenę poniżej i wpisz uzasadnienie", - "advanced-workflow-action.select-reviewer.description-single":"Wybierz recenzenta przed zdeponowaniem pozycji", - "advanced-workflow-action.select-reviewer.description-multiple":"Wybierz jednego lub więcej recenzentów przed zdeponowaniem pozycji", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head":"Użytkownicy", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head":"Dodaj użytkownika", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all":"Przeglądaj wszystko", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers":"Aktualni użytkownicy", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata":"Metadane", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email":"Adres e-mail (dokładny)", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button":"Wyszukaj", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id":"ID", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name":"Nazwa", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity":"Tożsamość", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email":"Adres e-mail", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid":"NetID", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit":"Usuń / Dodaj", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove":"Usuń użytkownika z nazwę \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember":"Dodano użytkownika o nazwie: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember":"Nie dodano użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember":"Usunięto użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember":"Nie usunięto użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add":"Dodano użytkownika \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup":"Brak aktywnej grupy, najpierw wpisz nazwę.", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet":"W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items":"Nie znaleziono żadnych użytkowników", - "advanced-workflow-action.select-reviewer.no-reviewer-selected.error":"Recenzent nie jest wybrany.", - "bitstream.edit.notifications.error.primaryBitstream.title":"Wystąpił błąd podczas zapisu pliku.", - "browse.comcol.by.srsc":"Wg słów kluczowych", - "browse.metadata.srsc.breadcrumbs":"Przeglądaj wg słów kluczowych", - "browse.startsWith.input":"Filtr", - "browse.taxonomy.button":"Przeglądaj", - "search.browse.item-back":"Powrót do wyników wyszukiwania", - "claimed-approved-search-result-list-element.title":"Zaakceptowano", - "claimed-declined-search-result-list-element.title":"Odrzucono i przesłano do deponującego", - "claimed-declined-task-search-result-list-element.title":"Odrzucono i przesłano do recenzenta", - "collection.edit.tabs.access-control.head":"Dostępy", - "collection.edit.tabs.access-control.title":"Edycja kolekcji - dostępy", - "collection.listelement.badge":"Kolekcja", - "community.edit.tabs.access-control.head":"Dostępy", - "community.edit.tabs.access-control.title":"Edycja zbioru - dostępy", - "comcol-role.edit.scorereviewers.name":"Ocena recenzenta", - "comcol-role.edit.scorereviewers.description":"Recenzenci mogą oceniać zdeponowane pozycje, co określi, czy pozycja zostanie przyjęta lub odrzucona.", - "curation-task.task.register-doi.label":"Rejestracja DOI", - "dso.name.unnamed":"Bez nazwy", - "dso-selector.create.community.or-divider":"lub", - "dso-selector.set-scope.community.or-divider":"lub", - "dso-selector.results-could-not-be-retrieved":"Wystąpił błąd, proszę odświeżyć stronę", - "supervision-group-selector.header":"Wybór grupy recenzenckiej", - "supervision-group-selector.select.type-of-order.label":"Wybierz typ funkcji", - "supervision-group-selector.select.type-of-order.option.none":"BRAK", - "supervision-group-selector.select.type-of-order.option.editor":"REDAKTOR", - "supervision-group-selector.select.type-of-order.option.observer":"OBSERWATOR", - "supervision-group-selector.select.group.label":"Wybierz grupę", - "supervision-group-selector.button.cancel":"Anuluj", - "supervision-group-selector.button.save":"Zapisz", - "supervision-group-selector.select.type-of-order.error":"Wybierz typ funkcji", - "supervision-group-selector.select.group.error":"Wybierz grupę", - "supervision-group-selector.notification.create.success.title":"Grupa recenzencka został dodana dla grupy {{ name }}", - "supervision-group-selector.notification.create.failure.title":"Błąd", - "supervision-group-selector.notification.create.already-existing":"Funkcja recenzenta już jest przypisana do tej grupy", - "confirmation-modal.delete-subscription.header":"Usuń subksrypcje", - "confirmation-modal.delete-subscription.info":"Czy na pewno chcesz usunąć subskrypcję: \"{{ dsoName }}\"", - "confirmation-modal.delete-subscription.cancel":"Anuluj", - "confirmation-modal.delete-subscription.confirm":"Usuń", - "error.validation.metadata.name.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", - "error.validation.metadata.name.max-length":"To pole nie może zawierać więcej niż 32 znaki", - "error.validation.metadata.namespace.max-length":"To pole nie może zawierać więcej niż 256 znaków", - "error.validation.metadata.element.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", - "error.validation.metadata.element.max-length":"To pole nie może zawierać więcej niż 64 znaki", - "error.validation.metadata.qualifier.invalid-pattern":"To pole nie może zawierać kropek, przecinków i spacji", - "error.validation.metadata.qualifier.max-length":"To pole nie może zawierać więcej niż 64 znaki", - "forgot-email.form.email.error.not-email-form":"Wpisz prawidłowy adres e-mail", - "form.other-information.email":"Adres e-mail", - "form.other-information.first-name":"Imię", - "form.other-information.insolr":"Solr Index", - "form.other-information.institution":"Instytucja", - "form.other-information.last-name":"Nazwisko", - "form.other-information.orcid":"ORCID", - "form.create":"Utwórz", - "info.end-user-agreement.hosting-country":"Stany Zjednoczone", - "item.edit.identifiers.doi.status.UNKNOWN":"Nieznane", - "item.edit.identifiers.doi.status.TO_BE_REGISTERED":"W kolejce do rejestracji", - "item.edit.identifiers.doi.status.TO_BE_RESERVED":"W kolejce do rezerwacji", - "item.edit.identifiers.doi.status.IS_REGISTERED":"Zarejestrowane", - "item.edit.identifiers.doi.status.IS_RESERVED":"Zarezerwowane", - "item.edit.identifiers.doi.status.UPDATE_RESERVED":"Zarezerwowane (aktualizacja w kolejce)", - "item.edit.identifiers.doi.status.UPDATE_REGISTERED":"Zarejestrowane (aktualizacja w kolejce)", - "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION":"W kolejce do aktualizacji i rejestracji", - "item.edit.identifiers.doi.status.TO_BE_DELETED":"Zakolejkowane do usunięcia", - "item.edit.identifiers.doi.status.DELETED":"Usunięte", - "item.edit.identifiers.doi.status.PENDING":"Oczekujące (niezarejestrowane)", - "item.edit.identifiers.doi.status.MINTED":"Rezerwowanie nazwy (niezarejestrowane)", - "item.edit.tabs.status.buttons.register-doi.label":"Zarejestruj nowe lub oczekujące DOI", - "item.edit.tabs.status.buttons.register-doi.button":"Rejestruj DOI...", - "item.edit.register-doi.header":"Zarejestruj nowe lub oczekujące DOI", - "item.edit.register-doi.description":"Zweryfikuj poniższe identyfikatory i metadane pozycji i rozpocznij rejestrację DOI lub anuluj", - "item.edit.register-doi.confirm":"Zatwierdź", - "item.edit.register-doi.cancel":"Anuluj", - "item.edit.register-doi.success":"DOI jest w kolejce do rejestracji.", - "item.edit.register-doi.error":"Wystąpił błąd poczas rejestracji DOI", - "item.edit.register-doi.to-update":"To DOI zostało zarezerwowane i będzie znajdować się w kolejce do rejestracji", - "item.edit.metadata.edit.buttons.confirm":"Zatwierdź", - "item.edit.metadata.edit.buttons.drag":"Przeciągnij, aby zmienić kolejność", - "item.edit.metadata.edit.buttons.virtual":"To pole przechowuje wirutalne wartości metadanych, np. wartość pobraną z encji, z którą jest połączona ta pozycja. Dodaj lub usuń relację w zakładce 'Relacje' ", - "item.edit.metadata.metadatafield.error":"Wystąpił błąd podczas walidcji pól metadanych", - "item.edit.metadata.reset-order-button":"Cofnij zamianę kolejności", - "item.edit.curate.title":"Zarządzaj pozycją: {{item}}", - "item.edit.tabs.access-control.head":"Dostęp", - "item.edit.tabs.access-control.title":"Edycja pozycji - dostęp", - "workflow-item.search.result.delete-supervision.modal.header":"Usuń zadanie dla recenzenta", - "workflow-item.search.result.delete-supervision.modal.info":"Czy na pewno usunąć zadanie dla recenzenta", - "workflow-item.search.result.delete-supervision.modal.cancel":"Anuluj", - "workflow-item.search.result.delete-supervision.modal.confirm":"Usuń", - "workflow-item.search.result.notification.deleted.success":"Usunięto zadanie dla recenzenta \"{{name}}\"", - "workflow-item.search.result.notification.deleted.failure":"Nie usunięto zadania dla recenzenta \"{{name}}\"", - "workflow-item.search.result.list.element.supervised-by":"Recenzja:", - "workflow-item.search.result.list.element.supervised.remove-tooltip":"Usuń grupę recenzencką", - "item.preview.dc.subject":"Słowo kluczowe:", - "item.preview.dc.publisher":"Wydawca:", - "itemtemplate.edit.metadata.add-button":"Dodaj", - "itemtemplate.edit.metadata.discard-button":"Cofnij", - "itemtemplate.edit.metadata.edit.buttons.confirm":"Zatwierdź", - "itemtemplate.edit.metadata.edit.buttons.drag":"Przeciągnij, aby zmienić kolejność", - "itemtemplate.edit.metadata.edit.buttons.edit":"Edytuj", - "itemtemplate.edit.metadata.edit.buttons.remove":"Usuń", - "itemtemplate.edit.metadata.edit.buttons.undo":"Cofnij zmiany", - "itemtemplate.edit.metadata.edit.buttons.unedit":"Nie edytuj", - "itemtemplate.edit.metadata.empty":"To pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby je wprowadzić.", - "itemtemplate.edit.metadata.headers.edit":"Edytuj", - "itemtemplate.edit.metadata.headers.field":"Pole", - "itemtemplate.edit.metadata.headers.language":"Język", - "itemtemplate.edit.metadata.headers.value":"Wartość", - "itemtemplate.edit.metadata.metadatafield.error":"Wystąpił błąd podczas walidowania pola metadanych", - "itemtemplate.edit.metadata.metadatafield.invalid":"Wybierz odpowiednie pole metadanych", - "itemtemplate.edit.metadata.notifications.discarded.content":"Twoje zmiany nie zostały zachowane. Aby spróbować wprowadzić je ponownie wybierz Cofnij", - "itemtemplate.edit.metadata.notifications.discarded.title":"Zmiany nie zostały zachowane", - "itemtemplate.edit.metadata.notifications.error.title":"Wystąpił błąd", - "itemtemplate.edit.metadata.notifications.invalid.content":"Twoje zmiany nie zostały zapisane. Upewnij się, że wszystkie pola zostały wypełnione prawidłowo.", - "itemtemplate.edit.metadata.notifications.invalid.title":"Nieprawidłowe metadan", - "itemtemplate.edit.metadata.notifications.outdated.content":"Wzór dla pozycji, na którą w tym momencie pracujesz, został zmodyfikowany przez innego użytkownika. Twoje zmiany zostały odrzucone, aby uniknąć konfliktów pomiędzy wersjami.", - "itemtemplate.edit.metadata.notifications.outdated.title":"Zmiany zostały odrzucone", - "itemtemplate.edit.metadata.notifications.saved.content":"Zmiany w metadanych wzoru pozycji zostały zapisane.", - "itemtemplate.edit.metadata.notifications.saved.title":"Metadane zostały zapisane", - "itemtemplate.edit.metadata.reinstate-button":"Cofnij", - "itemtemplate.edit.metadata.reset-order-button":"Cofnij zmianę kolejności", - "itemtemplate.edit.metadata.save-button":"Zapisz", - "menu.section.access_control_bulk":"Zbiorowe zarządzanie dostępem", - "menu.section.browse_global_by_srsc":"Wg słów kluczowych", - "mydspace.show.supervisedWorkspace":"Pozycje recenzowane", - "mydspace.status.mydspaceArchived":"Opublikowano", - "mydspace.status.mydspaceValidation":"Walidacja", - "mydspace.status.mydspaceWaitingController":"Oczekiwanie na redakctora", - "mydspace.status.mydspaceWorkflow":"Redakcja", - "mydspace.status.mydspaceWorkspace":"Przestrzeń robocza", - "nav.context-help-toggle":"Przełącz pomoc kontekstową", - "nav.search.button":"Wpisz wyszukiwaną frazę", - "nav.subscriptions":"Subksrypcje", - "process.new.notification.error.max-upload.content":"Plik jest większy niż maksymalny dozwolony rozmiar pliku", - "register-page.registration.email.error.not-email-form":"Wprowadź poprawny adres e-mail", - "register-page.registration.email.error.not-valid-domain":"Użyj adresu e-mail z domeny: {{ domains }}", - "register-page.registration.error.maildomain":"Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", - "register-page.registration.info.maildomain":"Konta mogą być założone dla adresów e-mail z domeną", - "repository.title":"Repozytorium DSpace", - "search.filters.applied.f.supervisedBy":"Recenzent", - "search.filters.filter.show-tree":"Przeglądaj {{ name }} strukturę recenzentów", - "search.filters.filter.supervisedBy.head":"Recenzent", - "search.filters.filter.supervisedBy.placeholder":"Recenzent", - "search.filters.filter.supervisedBy.label":"Wyszukaj recenzenta", - "statistics.table.no-name":"(nazwa obiektu nie może zostać załadowana)", - "submission.import-external.source.datacite":"DataCite", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor":"Publikacje autora", - "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor":"Publikacje", - "submission.sections.identifiers.info":"Te identyfikatory zostaną utworzone dla pozycji:", - "submission.sections.identifiers.no_handle":"Do tej pozycji nie zostały przypisane żadne Handle", - "submission.sections.identifiers.no_doi":"Do tej pozycji nie zostały przypisane żadne DOI", - "submission.sections.identifiers.handle_label":"Handle: ", - "submission.sections.identifiers.doi_label":"DOI: ", - "submission.sections.identifiers.otherIdentifiers_label":"Inne identyfikatory: ", - "submission.sections.submit.progressbar.identifiers":"Identyfikatory", - "submission.workflow.generic.submit_select_reviewer":"Wybierz recenzenta", - "submission.workflow.generic.submit_select_reviewer-help":"", - "submission.workflow.generic.submit_score":"Wynik", - "submission.workflow.generic.submit_score-help":"", - "submission.workflow.tasks.claimed.decline":"Odrzuć", - "submission.workflow.tasks.claimed.decline_help":"", - "submitter.empty":"n.d.", - "subscriptions.title":"Subskrypcje", - "subscriptions.item":"Subskrypcje pozycji", - "subscriptions.collection":"Subskrypcje kolekcji", - "subscriptions.community":"Subskrypcje zbiorów", - "subscriptions.subscription_type":"Typ subksrypcji", - "subscriptions.frequency":"Częstotliwość subskrypcji", - "subscriptions.frequency.D":"Codziennie", - "subscriptions.frequency.M":"Co miesiąc", - "subscriptions.frequency.W":"Co tydzień", - "subscriptions.tooltip":"Subskrybuj", - "subscriptions.modal.title":"Subksrypcje", - "subscriptions.modal.type-frequency":"Rodzaj i częstotliwość subksrypcji", - "subscriptions.modal.close":"Zamknij", - "subscriptions.modal.delete-info":"Aby usunąć tę subksrypcję przejdź do strony 'Subskrypcje', która znajduje się w profilu użytkownika", - "subscriptions.modal.new-subscription-form.type.content":"Zawartość", - "subscriptions.modal.new-subscription-form.frequency.D":"Codziennie", - "subscriptions.modal.new-subscription-form.frequency.W":"Co tydzień", - "subscriptions.modal.new-subscription-form.frequency.M":"Co miesiąc", - "subscriptions.modal.new-subscription-form.submit":"Zapisz", - "subscriptions.modal.new-subscription-form.processing":"Ładowanie...", - "subscriptions.modal.create.success":"Zasubskrybowano {{ type }}", - "subscriptions.modal.delete.success":"Subskrypcja została anulowana", - "subscriptions.modal.update.success":"Twoja subskrypcja {{ type }} została zaktualizowana", - "subscriptions.modal.create.error":"Wystąpił bład podczas tworzenia subskrypcji", - "subscriptions.modal.delete.error":"Wystąpił bład podczas usuwania subskrypcji", - "subscriptions.modal.update.error":"Wystąpił bład podczas aktualizacji subskrypcji", - "subscriptions.table.dso":"Słowo kluczowe", - "subscriptions.table.subscription_type":"Typ subskrypcji", - "subscriptions.table.subscription_frequency":"Częstotliwość subskrypcji", - "subscriptions.table.action":"Akcja", - "subscriptions.table.edit":"Edytuj", - "subscriptions.table.delete":"Usuń", - "subscriptions.table.not-available":"Niedostępne", - "subscriptions.table.not-available-message":"Ta pozycja została usunięta lun nie masz do niej dostępu, aby ją wyswietlić", - "subscriptions.table.empty.message":"Ta pozycja nie ma w tym momencie żadnych subksrypcji. Aby zasubkrybować i otrzymywać aktualizacje o tym zbiorze lub kolekcji, wybierz przycisk subskrypcji na stronie pozycji.", - "vocabulary-treeview.info":"Wybierz słowo kluczowe, aby dodać je do filtra", - "supervisedWorkspace.search.results.head":"Pozycje recenzowane", - "supervision.search.results.head":"Status zadań: Szkic i redakcja", - "workspace-item.delete.breadcrumbs":"Usunięto wersję roboczą", - "workspace-item.delete.header":"Usuń wersję roboczą", - "workspace-item.delete.button.confirm":"Usuń", - "workspace-item.delete.button.cancel":"Anuluj", - "workspace-item.delete.notification.success.title":"Usunięto", - "workspace-item.delete.title":"Wersja robocza została usunieta", - "workspace-item.delete.notification.error.title":"Coś poszło nie tak", - "workspace-item.delete.notification.error.content":"Wersja robocza nie może zostać usunieta", - "workflow-item.advanced.title":"Zaawansowane workflow", - "workflow-item.selectrevieweraction.notification.success.title":"Wybrany recenzent", - "workflow-item.selectrevieweraction.notification.success.content":"Recenzent został przypisany", - "workflow-item.selectrevieweraction.notification.error.title":"Coś poszło nie tak", - "workflow-item.selectrevieweraction.notification.error.content":"Nie udało się wybrać recenzenta dla pozycji", - "workflow-item.selectrevieweraction.title":"Wybierz recenzenta", - "workflow-item.selectrevieweraction.header":"Wybierz recenzenta", - "workflow-item.selectrevieweraction.button.cancel":"Anuluj", - "workflow-item.selectrevieweraction.button.confirm":"Zatwierdź", - "workflow-item.scorereviewaction.notification.success.title":"Ocena recenzji", - "workflow-item.scorereviewaction.notification.success.content":"Ocena tej pozycji została zapisana", - "workflow-item.scorereviewaction.notification.error.title":"Coś poszło nie tak", - "workflow-item.scorereviewaction.notification.error.content":"Nie można ocenić tej pozycji", - "workflow-item.scorereviewaction.title":"Oceń pozycję", - "workflow-item.scorereviewaction.header":"Oceń pozycję", - "workflow-item.scorereviewaction.button.cancel":"Anuluj", - "workflow-item.scorereviewaction.button.confirm":"Potwierdź", - "listable-notification-object.default-message":"Ta pozycja nie może być odzyskana", - "system-wide-alert-banner.retrieval.error":"Coś poszło nie tak podczas odzyskiwania alertu systemowego", - "system-wide-alert-banner.countdown.prefix":"W", - "system-wide-alert-banner.countdown.days":"{{days}} dni,", - "system-wide-alert-banner.countdown.hours":"{{hours}} godziny", - "system-wide-alert-banner.countdown.minutes":"{{minutes}} minut:", - "menu.section.system-wide-alert":"Alert systemowy", - "system-wide-alert.form.header":"Alert systemowy", - "system-wide-alert-form.retrieval.error":"Coś poszło nie tak podczas odzyskiwania alertu systemowego", - "system-wide-alert.form.cancel":"Anuluj", - "system-wide-alert.form.save":"Zapisz", - "system-wide-alert.form.label.active":"AKTYWNE", - "system-wide-alert.form.label.inactive":"NIEAKTYWNE", - "system-wide-alert.form.error.message":"Alert systemowy musi zawierać wiadomość", - "system-wide-alert.form.label.message":"Alert systemowy", - "system-wide-alert.form.label.countdownTo.enable":"Wprowadź licznik czasowy", - "system-wide-alert.form.label.countdownTo.hint":"Wskazówka: Wpisz wartość licznika czasu. Kiedy licznik jest włączony, alert systemowy zostanie wyświetlony o wybranym czasie. Kiedy odliczanie zostanie zakończone, alert systemowy zostanie wyłączony. Serwer NIE zostanie zatrzymany automatycznie.", - "system-wide-alert.form.label.preview":"Podgląd alertu systemowego", - "system-wide-alert.form.update.success":"Alert systemowy został zaktualizowany", - "system-wide-alert.form.update.error":"Coś poszło nie tak podczas aktualizacji alertu systemowego", - "system-wide-alert.form.create.success":"Alert systemowy został utworzony", - "system-wide-alert.form.create.error":"Coś poszło nie tak podczas tworzenia alertu systemowego", - "admin.system-wide-alert.breadcrumbs":"Alerty systemowe", - "admin.system-wide-alert.title":"Alerty systemowe", - "item-access-control-title":"Ta strona pozwala na zmianę dostępów metadanych pozycji i plików do nich dołączonych.", - "collection-access-control-title":"Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w tej kolekcji. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", - "community-access-control-title":"Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w każdej kolekcji w tym zbiorze. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", - "access-control-item-header-toggle":"Metadane pozycji", - "access-control-bitstream-header-toggle":"Pliki", - "access-control-mode":"Tryb", - "access-control-access-conditions":"Warunki dostępu", - "access-control-no-access-conditions-warning-message":"W tym momencie żadne warunki dostępu nie zostały określone. Jeśli zadanie zostanie rozpoczęte, obecne warunki dostępu zostaną zastąpione domyślnymi warunkami dostępu z nadrzędnej kolekcji.", - "access-control-replace-all":"Zastąp warunki dostępu", - "access-control-add-to-existing":"Dodaj do już istniejących", - "access-control-limit-to-specific":"Ogranicz zmiany do wybranych plików", - "access-control-process-all-bitstreams":"Zaktualizuj wszystkie pliki dla tej pozycji", - "access-control-bitstreams-selected":"wybrane pliki", - "access-control-cancel":"Anuluj", - "access-control-execute":"Wykonaj", - "access-control-add-more":"Dodaj więcej", - "access-control-select-bitstreams-modal.title":"Wybierz pliki", - "access-control-select-bitstreams-modal.no-items":"Brak pozycji do wyświetlenia.", - "access-control-select-bitstreams-modal.close":"Zamknij", - "access-control-option-label":"Typ warunków dostępu", - "access-control-option-note":"Wybierz warunki dostępu, które chcesz przypisać do zaznaczonych pozycji.", - "access-control-option-start-date":"Dostęp od", - "access-control-option-start-date-note":"Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", - "access-control-option-end-date":"Dostęp do", - "access-control-option-end-date-note":"Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać" + "401.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", + "401.link.home-page": "Zabierz mnie na stronę główną", + "401.unauthorized": "nieautoryzowany", + "403.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "403.link.home-page": "Zabierz mnie na stronę główną", + "403.forbidden": "zabroniony", + "404.help": "Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", + "404.link.home-page": "Zabierz mnie na stronę główną", + "404.page-not-found": "strona nie została znaleziona", + "admin.curation-tasks.breadcrumbs": "Systemowe zadania administracyjne", + "admin.curation-tasks.title": "Systemowe zadania administracyjne", + "admin.curation-tasks.header": "Systemowe zadania administracyjne", + "admin.registries.bitstream-formats.breadcrumbs": "Rejestr formatów", + "admin.registries.bitstream-formats.create.breadcrumbs": "Format strumienia bitów", + "admin.registries.bitstream-formats.create.failure.content": "Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", + "admin.registries.bitstream-formats.create.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.create.head": "Utwórz nowy format", + "admin.registries.bitstream-formats.create.new": "Dodaj nowy format", + "admin.registries.bitstream-formats.create.success.content": "Nowy format strumienia bitów został pomyślnie utworzony.", + "admin.registries.bitstream-formats.create.success.head": "Udało się", + "admin.registries.bitstream-formats.delete.failure.amount": "Nie udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.delete.success.amount": "Udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.success.head": "Udało się", + "admin.registries.bitstream-formats.description": "Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", + "admin.registries.bitstream-formats.edit.breadcrumbs": "Format strumienia bitów", + "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.label": "Opis", + "admin.registries.bitstream-formats.edit.extensions.hint": "Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", + "admin.registries.bitstream-formats.edit.extensions.label": "Rozszerzenia plików", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Wprowadź rozszerzenie pliku bez kropki", + "admin.registries.bitstream-formats.edit.failure.content": "Wystąpił błąd podczas edycji formatu pliku.", + "admin.registries.bitstream-formats.edit.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.edit.head": "Format plików: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint": "Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", + "admin.registries.bitstream-formats.edit.internal.label": "Wewnętrzny", + "admin.registries.bitstream-formats.edit.mimetype.hint": "Typ MIME powiązany z tym formatem, nie musi być unikalny.", + "admin.registries.bitstream-formats.edit.mimetype.label": "Typ MIME", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Nazwa", + "admin.registries.bitstream-formats.edit.success.content": "Format strumienia bitów został pomyślnie edytowany.", + "admin.registries.bitstream-formats.edit.success.head": "Udało się", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Obsługiwany format", + "admin.registries.bitstream-formats.head": "Rejestr formatów", + "admin.registries.bitstream-formats.no-items": "Brak formatów plików do wyświetlenia.", + "admin.registries.bitstream-formats.table.delete": "Usuń zaznaczone", + "admin.registries.bitstream-formats.table.deselect-all": "Odznacz wszystkie", + "admin.registries.bitstream-formats.table.internal": "wewnętrzne", + "admin.registries.bitstream-formats.table.mimetype": "Typ MIME", + "admin.registries.bitstream-formats.table.name": "Nazwa", + "admin.registries.bitstream-formats.table.return": "Powrót", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Znane", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Wspierane", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Nieznane", + "admin.registries.bitstream-formats.table.supportLevel.head": "Obsługiwany format", + "admin.registries.bitstream-formats.title": "Rejestr formatów plików", + "admin.registries.metadata.breadcrumbs": "Rejestr metadanych", + "admin.registries.metadata.description": "W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", + "admin.registries.metadata.form.create": "Utwórz schemat metadanych", + "admin.registries.metadata.form.edit": "Edytuj schemat metadanych", + "admin.registries.metadata.form.name": "Nazwa", + "admin.registries.metadata.form.namespace": "Nazwa schematu", + "admin.registries.metadata.head": "Rejestr metadanych", + "admin.registries.metadata.schemas.no-items": "Brak rejestrów metadanych do pokazania.", + "admin.registries.metadata.schemas.table.delete": "Usuń zaznaczone", + "admin.registries.metadata.schemas.table.id": "ID", + "admin.registries.metadata.schemas.table.name": "Nazwa", + "admin.registries.metadata.schemas.table.namespace": "Nazwa schematu", + "admin.registries.metadata.title": "Rejestr metadanych", + "admin.registries.schema.breadcrumbs": "Schemat metadanych", + "admin.registries.schema.description": "Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", + "admin.registries.schema.fields.head": "Pola schematu metadanych", + "admin.registries.schema.fields.no-items": "Brak pól metadanych do pokazania.", + "admin.registries.schema.fields.table.delete": "Usuń zaznaczone", + "admin.registries.schema.fields.table.field": "Pole", + "admin.registries.schema.fields.table.scopenote": "Uwagi", + "admin.registries.schema.form.create": "Stwórz pole metadanych", + "admin.registries.schema.form.edit": "Edytuj pole metadanych", + "admin.registries.schema.form.element": "Element", + "admin.registries.schema.form.qualifier": "Kwalifikator", + "admin.registries.schema.form.scopenote": "Uwagi", + "admin.registries.schema.head": "Schemat metadanych", + "admin.registries.schema.notification.created": "Udało się utworzyć schemat metdanych \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure": "Nie udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.deleted.success": "Udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.edited": "Udało się edytować schemat metadanych \"{{prefix}}\"", + "admin.registries.schema.notification.failure": "Błąd", + "admin.registries.schema.notification.field.created": "Udało się utworzyć pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure": "Nie udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.deleted.success": "Udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.edited": "SUdało się edytować pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.success": "Udało się", + "admin.registries.schema.return": "Powrót", + "admin.registries.schema.title": "Rejestr schematów metadanych", + "admin.access-control.epeople.actions.delete": "Usuń użytkownika", + "admin.access-control.epeople.actions.impersonate": "Personifikuj użytkownika", + "admin.access-control.epeople.actions.reset": "Zresetuj hasło", + "admin.access-control.epeople.actions.stop-impersonating": "Przestań personifikować użytkownika", + "admin.access-control.epeople.breadcrumbs": "Użytkownicy", + "admin.access-control.epeople.title": "Użytkownicy", + "admin.access-control.epeople.head": "Użytkownicy", + "admin.access-control.epeople.search.head": "Wyszukaj", + "admin.access-control.epeople.button.see-all": "Przeglądaj wszystko", + "admin.access-control.epeople.search.scope.metadata": "Metadane", + "admin.access-control.epeople.search.scope.email": "E-mail", + "admin.access-control.epeople.search.button": "Wyszukaj", + "admin.access-control.epeople.search.placeholder": "Wyszukaj użytkownika...", + "admin.access-control.epeople.button.add": "Dodaj użytkownika", + "admin.access-control.epeople.table.id": "ID", + "admin.access-control.epeople.table.name": "Nazwa", + "admin.access-control.epeople.table.email": "E-mail", + "admin.access-control.epeople.table.edit": "Edytuj", + "admin.access-control.epeople.table.edit.buttons.edit": "Edytuj \"{{name}}\"", + "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Brak uprawnień do edycji wybranej grupy", + "admin.access-control.epeople.table.edit.buttons.remove": "Usuń \"{{name}}\"", + "admin.access-control.epeople.no-items": "Brak użytkowników do wyświetlenia.", + "admin.access-control.epeople.form.create": "Utwórz użytkownika", + "admin.access-control.epeople.form.edit": "Edytuj użytkownika", + "admin.access-control.epeople.form.firstName": "Imię", + "admin.access-control.epeople.form.lastName": "Nazwisko", + "admin.access-control.epeople.form.email": "E-mail", + "admin.access-control.epeople.form.emailHint": "Adres e-mail musi być poprawny", + "admin.access-control.epeople.form.canLogIn": "Możliwość zalogowania", + "admin.access-control.epeople.form.requireCertificate": "Wymagany certyfikat", + "admin.access-control.epeople.form.return": "Powrót", + "admin.access-control.epeople.form.notification.created.success": "Udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure": "Nie udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.success": "Udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.edited.failure": "Nie udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.success": "Udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.failure": "Nie udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Członek grup:", + "admin.access-control.epeople.form.table.id": "ID", + "admin.access-control.epeople.form.table.name": "Nazwa", + "admin.access-control.epeople.form.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.epeople.form.memberOfNoGroups": "Ten użytkownik nie jest członkiem żadnej grupy", + "admin.access-control.epeople.form.goToGroups": "Dodaj do grup", + "admin.access-control.epeople.notification.deleted.failure": "Nie udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.success": "Udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.groups.title": "Grupy", + "admin.access-control.groups.breadcrumbs": "Grupy", + "admin.access-control.groups.singleGroup.breadcrumbs": "Edytuj grupę", + "admin.access-control.groups.title.singleGroup": "Edytuj grupę", + "admin.access-control.groups.title.addGroup": "Nowa grupa", + "admin.access-control.groups.addGroup.breadcrumbs": "Nowa grupa", + "admin.access-control.groups.head": "Grupy/role", + "admin.access-control.groups.button.add": "Dodaj grupę", + "admin.access-control.groups.search.head": "Szukaj grup", + "admin.access-control.groups.button.see-all": "Przeszukaj wszystko", + "admin.access-control.groups.search.button": "Wyszukaj", + "admin.access-control.groups.search.placeholder": "Wyszukaj grupy...", + "admin.access-control.groups.table.id": "ID", + "admin.access-control.groups.table.name": "Nazwa", + "admin.access-control.groups.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.groups.table.members": "Członkowie", + "admin.access-control.groups.table.edit": "Edytuj", + "admin.access-control.groups.table.edit.buttons.edit": "Edytuj \"{{name}}\"", + "admin.access-control.groups.no-items": "Nie znaleziono grup z podaną frazą lub podanym UUID", + "admin.access-control.groups.notification.deleted.success": "Udało się usunąć grupę \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content": "Powód: \"{{cause}}\"", + "admin.access-control.groups.form.alert.permanent": "Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", + "admin.access-control.groups.form.alert.workflowGroup": "Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", + "admin.access-control.groups.form.head.create": "Utwórz grupę", + "admin.access-control.groups.form.head.edit": "Edytuj grupę", + "admin.access-control.groups.form.groupName": "Nazwa grupy", + "admin.access-control.groups.form.groupCommunity": "Zbiór lub kolekcja", + "admin.access-control.groups.form.groupDescription": "Opis", + "admin.access-control.groups.form.notification.created.success": "Udało się utworzyć grupę \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure": "Nie udało się utworzyć grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", + "admin.access-control.groups.form.notification.edited.failure": "Nie udało się edytować grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Nazwa \"{{name}}\" już w użyciu!", + "admin.access-control.groups.form.notification.edited.success": "Udało się edytować grupę \"{{name}}\"", + "admin.access-control.groups.form.actions.delete": "Usuń grupę", + "admin.access-control.groups.form.delete-group.modal.header": "Usuń grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.info": "Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.cancel": "Anuluj", + "admin.access-control.groups.form.delete-group.modal.confirm": "Usuń", + "admin.access-control.groups.form.notification.deleted.success": "Udało się usunąć grupę \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.content": "Powód: \"{{ cause }}\"", + "admin.access-control.groups.form.members-list.head": "Użytkownik", + "admin.access-control.groups.form.members-list.search.head": "Dodaj użytkownika", + "admin.access-control.groups.form.members-list.button.see-all": "Pokaż wszystkich", + "admin.access-control.groups.form.members-list.headMembers": "Aktualni członkowie", + "admin.access-control.groups.form.members-list.search.scope.metadata": "Metadane", + "admin.access-control.groups.form.members-list.search.scope.email": "E-mail", + "admin.access-control.groups.form.members-list.search.button": "Wyszukaj", + "admin.access-control.groups.form.members-list.table.id": "ID", + "admin.access-control.groups.form.members-list.table.name": "Nazwa", + "admin.access-control.groups.form.members-list.table.identity": "Tożsamość", + "admin.access-control.groups.form.members-list.table.email": "E-mail", + "admin.access-control.groups.form.members-list.table.netid": "NetID", + "admin.access-control.groups.form.members-list.table.edit": "Usuń / Dodaj", + "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Usuń użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.addMember": "Udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.addMember": "Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Dodaj użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.members-list.no-members-yet": "Brak użytkowników w grupie, wyszukaj ich i dodaj.", + "admin.access-control.groups.form.members-list.no-items": "Nie znaleziono użytkowników podczas wyszukiwania", + "admin.access-control.groups.form.subgroups-list.notification.failure": "Coś poszło nie tak: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head": "Grupy", + "admin.access-control.groups.form.subgroups-list.search.head": "Dodaj podgrupę", + "admin.access-control.groups.form.subgroups-list.button.see-all": "Przeglądaj wszystkie", + "admin.access-control.groups.form.subgroups-list.headSubgroups": "Aktualne podgrupy", + "admin.access-control.groups.form.subgroups-list.search.button": "Wyszukaj", + "admin.access-control.groups.form.subgroups-list.table.id": "ID", + "admin.access-control.groups.form.subgroups-list.table.name": "Nazwa", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.groups.form.subgroups-list.table.edit": "Usuń / Dodaj", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Usuń podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Dodaj podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Aktualna grupa", + "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Udało się dodać podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Nie udało się dodać podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Udało się usunąć podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Nie udało się usunąć podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ta grupa jest już stworzona i nie może zostać dodana pononwie.", + "admin.access-control.groups.form.subgroups-list.no-items": "Nie znaleziono grup z tą nazwą lub UUID", + "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Brak podgrup w grupie.", + "admin.access-control.groups.form.return": "Powrót", + "admin.search.breadcrumbs": "Wyszukiwanie administracyjne", + "admin.search.collection.edit": "Edytuj", + "admin.search.community.edit": "Edytuj", + "admin.search.item.delete": "Usuń", + "admin.search.item.edit": "Edytuj", + "admin.search.item.make-private": "Ukryj", + "admin.search.item.make-public": "Upublicznij", + "admin.search.item.move": "Przenieś", + "admin.search.item.reinstate": "Zmień instancję", + "admin.search.item.withdraw": "Wycofane", + "admin.search.title": "Wyszukiwanie administracyjne", + "administrativeView.search.results.head": "Wyszukiwanie administracyjne", + "admin.workflow.breadcrumbs": "Zarządzaj procesem", + "admin.workflow.title": "Zarządzaj procesem", + "admin.workflow.item.workflow": "Proces", + "admin.workflow.item.delete": "Usuń", + "admin.workflow.item.send-back": "Odeślij z powrotem", + "admin.metadata-import.breadcrumbs": "Importuj metadane", + "admin.metadata-import.title": "Importuj metadane", + "admin.metadata-import.page.header": "Importuj metadane", + "admin.metadata-import.page.help": "Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", + "admin.metadata-import.page.dropMsg": "Upuść plik w formacie CSV", + "admin.metadata-import.page.dropMsgReplace": "Upuść, aby zastąpić metadane w formacie CSV do importu", + "admin.metadata-import.page.button.return": "Powrót", + "admin.metadata-import.page.button.proceed": "Zastosuj", + "admin.metadata-import.page.error.addFile": "Najpierw wybierz plik!", + "auth.errors.invalid-user": "Niewłaściwy adres e-mail lub hasło.", + "auth.messages.expired": "Twoja sesja wygasła. Zaloguj się ponownie.", + "auth.messages.token-refresh-failed": "Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", + "bitstream.download.page": "Pobieranie {{bitstream}}...", + "bitstream.download.page.back": "Powrót", + "bitstream.edit.authorizations.link": "Edytuj polityki plików", + "bitstream.edit.authorizations.title": "Edytuj polityki plików", + "bitstream.edit.return": "Powrót", + "bitstream.edit.bitstream": "Pliki: ", + "bitstream.edit.form.description.hint": "Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", + "bitstream.edit.form.description.label": "Opis", + "bitstream.edit.form.embargo.hint": "Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", + "bitstream.edit.form.embargo.label": "Embargo do wybranej daty", + "bitstream.edit.form.fileName.hint": "Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", + "bitstream.edit.form.fileName.label": "Nazwa pliku", + "bitstream.edit.form.newFormat.label": "Opisz nowy format", + "bitstream.edit.form.newFormat.hint": "Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", + "bitstream.edit.form.primaryBitstream.label": "Pierwotny plik", + "bitstream.edit.form.selectedFormat.hint": "Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", + "bitstream.edit.form.selectedFormat.label": "Wybrany format", + "bitstream.edit.form.selectedFormat.unknown": "Tego formatu nie ma na liście", + "bitstream.edit.notifications.error.format.title": "Wystąpił błąd podczas zapisu formatu pliku", + "bitstream.edit.notifications.saved.content": "Zmiany w pliku zostały zapisane.", + "bitstream.edit.notifications.saved.title": "Plik został zapisany", + "bitstream.edit.title": "Edytuj plik", + "bitstream-request-a-copy.alert.canDownload1": "Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", + "bitstream-request-a-copy.alert.canDownload2": "tutaj", + "bitstream-request-a-copy.header": "Wystąp o kopię wybranego pliku", + "bitstream-request-a-copy.intro": "Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", + "bitstream-request-a-copy.intro.bitstream.one": "Wystąpienie o dostęp do następujących plików: ", + "bitstream-request-a-copy.intro.bitstream.all": "Wystąpienie o dostęp do wszystkich plików. ", + "bitstream-request-a-copy.name.label": "Imię *", + "bitstream-request-a-copy.name.error": "Imię jest wymagane", + "bitstream-request-a-copy.email.label": "Adres e-mail *", + "bitstream-request-a-copy.email.hint": "Plik zostanie przesłany na podany adres e-mail", + "bitstream-request-a-copy.email.error": "Proszę wprowadzić prawidłowy adres e-mail", + "bitstream-request-a-copy.allfiles.label": "Pliki", + "bitstream-request-a-copy.files-all-false.label": "Tylko plik, dla którego wystąpiono o dostęp", + "bitstream-request-a-copy.files-all-true.label": "Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", + "bitstream-request-a-copy.message.label": "Wiadomość", + "bitstream-request-a-copy.return": "Powrót", + "bitstream-request-a-copy.submit": "Wystąp o kopię", + "bitstream-request-a-copy.submit.success": "Wystąpienie o dostęp do pliku zostało przesłane.", + "bitstream-request-a-copy.submit.error": "Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", + "browse.comcol.by.author": "wg autorów", + "browse.comcol.by.dateissued": "wg daty wydania", + "browse.comcol.by.subject": "wg tematu", + "browse.comcol.by.title": "wg tytułu", + "browse.comcol.head": "Przeglądaj", + "browse.empty": "Brak rekordów do wyświetlenia.", + "browse.metadata.author": "Autor", + "browse.metadata.dateissued": "Data wydania", + "browse.metadata.subject": "Temat", + "browse.metadata.title": "Tytuł", + "browse.metadata.author.breadcrumbs": "Przeglądaj wg autorów", + "browse.metadata.dateissued.breadcrumbs": "Przeglądaj wg daty wydania", + "browse.metadata.subject.breadcrumbs": "Przeglądaj wg tematów", + "browse.metadata.title.breadcrumbs": "Przeglądaj wg tytułów", + "browse.startsWith.choose_start": "(Wybierz start)", + "browse.startsWith.choose_year": "(Wybierz rok)", + "browse.startsWith.choose_year.label": "Wybierz rok wydania", + "browse.startsWith.jump": "Przejdź do miejsca w indeksie:", + "browse.startsWith.months.april": "kwiecień", + "browse.startsWith.months.august": "sierpień", + "browse.startsWith.months.december": "grudzień", + "browse.startsWith.months.february": "luty", + "browse.startsWith.months.january": "styczeń", + "browse.startsWith.months.july": "lipiec", + "browse.startsWith.months.june": "czerwiec", + "browse.startsWith.months.march": "marzec", + "browse.startsWith.months.may": "maj", + "browse.startsWith.months.none": "(wybierz miesiąc)", + "browse.startsWith.months.none.label": "Wybierz miesiąc wydania", + "browse.startsWith.months.november": "listopad", + "browse.startsWith.months.october": "październik", + "browse.startsWith.months.september": "wrzesień", + "browse.startsWith.submit": "Zastosuj", + "browse.startsWith.type_date": "Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", + "browse.startsWith.type_date.label": "Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", + "browse.startsWith.type_text": "Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", + "browse.title": "Przeglądaj {{ collection }} wg {{ field }} {{ value }}", + "chips.remove": "Usuń chip", + "collection.create.head": "Utwórz kolekcję", + "collection.create.notifications.success": "Udało się utworzyć kolekcję", + "collection.create.sub-head": "Udało się utworzyć kolekcję dla zbioru {{ parent }}", + "collection.curate.header": "Administrator kolekcji: {{collection}}", + "collection.delete.cancel": "Anuluj", + "collection.delete.confirm": "Zatwierdź", + "collection.delete.processing": "Usuwanie", + "collection.delete.head": "Usuń kolekcję", + "collection.delete.notification.fail": "Kolekcja nie może być usunięt", + "collection.delete.notification.success": "Udało się usunąć kolekcję", + "collection.delete.text": "Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", + "collection.edit.delete": "Usuń kolekcję", + "collection.edit.head": "Edytuj kolekcję", + "collection.edit.breadcrumbs": "Edytuj kolekcję", + "collection.edit.tabs.mapper.head": "Item Mapper", + "collection.edit.tabs.item-mapper.title": "Edytuj kolekcję - Item Mapper", + "collection.edit.item-mapper.cancel": "Anuluj", + "collection.edit.item-mapper.collection": "Kolekcja: \"<b>{{name}}</b>\"", + "collection.edit.item-mapper.confirm": "Mapuj wybrane elementy", + "collection.edit.item-mapper.description": "To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", + "collection.edit.item-mapper.head": "Item Mapper - Mapuj pozycje z innych kolekcji", + "collection.edit.item-mapper.no-search": "Wpisz co chcesz wyszukać", + "collection.edit.item-mapper.notifications.map.error.content": "Wystąpiły błędy podczas mapowania {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.error.head": "Mapowanie błędów", + "collection.edit.item-mapper.notifications.map.success.content": "Udało się zmapować {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.success.head": "Mapowanie zakończone", + "collection.edit.item-mapper.notifications.unmap.error.content": "Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.error.head": "Usuń błędy mapowania", + "collection.edit.item-mapper.notifications.unmap.success.content": "Udało się usunąć błędy mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.success.head": "Usuwanie mapowania zakończone", + "collection.edit.item-mapper.remove": "Usuń wybrane mapowanie elementów", + "collection.edit.item-mapper.search-form.placeholder": "Wyszukaj pozycje...", + "collection.edit.item-mapper.tabs.browse": "Wyszukaj mapowane elementy", + "collection.edit.item-mapper.tabs.map": "Mapuj nowe elementy", + "collection.edit.logo.delete.title": "Usuń", + "collection.edit.logo.delete-undo.title": "Cofnij usunięcie", + "collection.edit.logo.label": "Logo kolekcji", + "collection.edit.logo.notifications.add.error": "Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", + "collection.edit.logo.notifications.add.success": "Udało się przesłać logo kolekcji.", + "collection.edit.logo.notifications.delete.success.title": "Logo usunięte", + "collection.edit.logo.notifications.delete.success.content": "Udało się usunąć logo kolekcji", + "collection.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", + "collection.edit.logo.upload": "Upuść logo kolekcji, aby je wgrać", + "collection.edit.notifications.success": "Udało się edytować kolekcję", + "collection.edit.return": "Powrót", + "collection.edit.tabs.curate.head": "Kurator", + "collection.edit.tabs.curate.title": "Edytowanie kolekcji - kurator", + "collection.edit.tabs.authorizations.head": "Autoryzacje", + "collection.edit.tabs.authorizations.title": "Edytowanie kolekcji - autoryzacje", + "collection.edit.tabs.metadata.head": "Edytuj metadane", + "collection.edit.tabs.metadata.title": "Edytowanie kolekcji - metadane", + "collection.edit.tabs.roles.head": "Przypisz role", + "collection.edit.tabs.roles.title": "Edytowanie kolekcji - role", + "collection.edit.tabs.source.external": "Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", + "collection.edit.tabs.source.form.errors.oaiSource.required": "Musisz wskazać id docelowej kolekcji.", + "collection.edit.tabs.source.form.harvestType": "Odczytywanie zawartości", + "collection.edit.tabs.source.form.head": "Skonfiguruj zewnętrzne źródło", + "collection.edit.tabs.source.form.metadataConfigId": "Format metadanych", + "collection.edit.tabs.source.form.oaiSetId": "Określony zestaw ID OAI", + "collection.edit.tabs.source.form.oaiSource": "Dostawca OAI", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Odczytaj metadane i pliki (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Odczytaj tylko metadane", + "collection.edit.tabs.source.head": "Źródło treści", + "collection.edit.tabs.source.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", + "collection.edit.tabs.source.notifications.discarded.title": "Zmiany odrzucone", + "collection.edit.tabs.source.notifications.invalid.content": "Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", + "collection.edit.tabs.source.notifications.invalid.title": "Nieprawidłowe metadane", + "collection.edit.tabs.source.notifications.saved.content": "Zmiany wprowadzone w kolekcji zostały zapisane.", + "collection.edit.tabs.source.notifications.saved.title": "Źródło treści zapisane", + "collection.edit.tabs.source.title": "Collection Edit - Źródło treści", + "collection.edit.template.add-button": "Dodaj", + "collection.edit.template.breadcrumbs": "Szablon pozycji", + "collection.edit.template.cancel": "Anuluj", + "collection.edit.template.delete-button": "Usuń", + "collection.edit.template.edit-button": "Edytuj", + "collection.edit.template.error": "Wystąpił błąd podczas odzyskiwania szablonu pozycji", + "collection.edit.template.head": "Edytuj szablon dla kolekcji \"{{ collection }}\"", + "collection.edit.template.label": "Szablon pozycji", + "collection.edit.template.loading": "ładowanie szablonu pozycji...", + "collection.edit.template.notifications.delete.error": "Nie udało się usunąć szablonu pozycji", + "collection.edit.template.notifications.delete.success": "Udało się usunąć szablon pozycji", + "collection.edit.template.title": "Edytuj szablon pozycji", + "collection.form.abstract": "Opis skrócony", + "collection.form.description": "Tekst powitalny (HTML)", + "collection.form.errors.title.required": "Wpisz nazwę kolekcji", + "collection.form.license": "Licencja", + "collection.form.provenance": "Pochodzenie", + "collection.form.rights": "Tekst praw autorskich (HTML)", + "collection.form.tableofcontents": "Wiadomości (HTML)", + "collection.form.title": "Nazwa", + "collection.form.entityType": "Typ danych", + "collection.page.browse.recent.head": "Ostatnie zgłoszenia", + "collection.page.browse.recent.empty": "Brak pozycji do wyświetlenia", + "collection.page.edit": "Edytuj kolekcję", + "collection.page.handle": "Stały URI dla kolekcji", + "collection.page.license": "Licencja", + "collection.page.news": "Wiadomości", + "collection.select.confirm": "Zaakceptuj zaznaczone", + "collection.select.empty": "Brak kolekcji do wyświetlenia", + "collection.select.table.title": "Tytuł", + "collection.source.controls.head": "Kontrolki odczytywania", + "collection.source.controls.test.submit.error": "Coś poszło nie tak podczas rozpoczynania testów ustawień", + "collection.source.controls.test.failed": "Scenariusz testowy ustawień nie zadziałał", + "collection.source.controls.test.completed": "Scenariusz testowy ustawień został zakończony", + "collection.source.controls.test.submit": "Konfiguracja testowa", + "collection.source.controls.test.running": "Testowanie konfiguracji...", + "collection.source.controls.import.submit.success": "Import został rozpoczęty", + "collection.source.controls.import.submit.error": "Coś poszło nie tak podczas rozpoczynania importu", + "collection.source.controls.import.submit": "Importuj teraz", + "collection.source.controls.import.running": "Importowanie...", + "collection.source.controls.import.failed": "Wystąpił błąd podczas importu", + "collection.source.controls.import.completed": "Import zakończony", + "collection.source.controls.reset.submit.success": "Reset ustawień i powtórny import zostały rozpoczęte poprawnie", + "collection.source.controls.reset.submit.error": "Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", + "collection.source.controls.reset.failed": "Wystąpił błąd podczas resetowania ustawień i ponownego importu", + "collection.source.controls.reset.completed": "Reset ustawień i powtórny import zostały zakończone", + "collection.source.controls.reset.submit": "Resetowanie i powtórny import", + "collection.source.controls.reset.running": "Resetowanie i powtórny import...", + "collection.source.controls.harvest.status": "Status odczytywania:", + "collection.source.controls.harvest.start": "Czas rozpoczęcia odczytywania:", + "collection.source.controls.harvest.last": "Czas ostatniego odczytywania:", + "collection.source.controls.harvest.message": "Informacje nt. odczytywania:", + "collection.source.controls.harvest.no-information": "bd.", + "collection.source.update.notifications.error.content": "Te ustawienia zostały przetestowane i nie działają.", + "collection.source.update.notifications.error.title": "Błąd serwera", + "communityList.breadcrumbs": "Lista zbiorów", + "communityList.tabTitle": "Lista zbiorów", + "communityList.title": "Lista zbiorów", + "communityList.showMore": "Pokaż więcej", + "community.create.head": "Utwórz zbiór", + "community.create.notifications.success": "Udało się utworzyć zbiór", + "community.create.sub-head": "Utwórz podzbiór dla zbioru {{ parent }}", + "community.curate.header": "Zarządzaj zbiorem: {{community}}", + "community.delete.cancel": "Anuluj", + "community.delete.confirm": "Potwierdź", + "community.delete.processing": "Usuwanie...", + "community.delete.head": "Usuń zbiór", + "community.delete.notification.fail": "Zbiór nie może być usunięty", + "community.delete.notification.success": "Udało się usunąć zbiór", + "community.delete.text": "Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", + "community.edit.delete": "Usuń ten zbiór", + "community.edit.head": "Edytuj zbiór", + "community.edit.breadcrumbs": "Edytuj zbiór", + "community.edit.logo.delete.title": "Usuń logo", + "community.edit.logo.delete-undo.title": "Cofnij usunięcie", + "community.edit.logo.label": "Logo zbioru", + "community.edit.logo.notifications.add.error": "Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", + "community.edit.logo.notifications.add.success": "Przesłanie loga powiodło się.", + "community.edit.logo.notifications.delete.success.title": "Logo usunięte", + "community.edit.logo.notifications.delete.success.content": "Usunięcie loga zbioru powiodło się", + "community.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", + "community.edit.logo.upload": "Upuść logo zbioru, aby je przesłać", + "community.edit.notifications.success": "Udało się edytować zbiór", + "community.edit.notifications.unauthorized": "Nie masz uprawnień, aby wykonać te zmiany", + "community.edit.notifications.error": "Wystąpił błąd podczas edycji zbioru", + "community.edit.return": "Cofnij", + "community.edit.tabs.curate.head": "Administruj", + "community.edit.tabs.curate.title": "Edycja zbioru - administrator", + "community.edit.tabs.metadata.head": "Edytuj metadane", + "community.edit.tabs.metadata.title": "Edycja zbioru - metadane", + "community.edit.tabs.roles.head": "Przypisz role", + "community.edit.tabs.roles.title": "Edycja zbioru - role", + "community.edit.tabs.authorizations.head": "Uprawnienia", + "community.edit.tabs.authorizations.title": "Edycja zbioru - uprawnienia", + "community.listelement.badge": "Zbiór", + "comcol-role.edit.no-group": "Brak", + "comcol-role.edit.create": "Utwórz", + "comcol-role.edit.restrict": "Ogranicz", + "comcol-role.edit.delete": "Usuń", + "comcol-role.edit.community-admin.name": "Administratorzy", + "comcol-role.edit.collection-admin.name": "Administratorzy", + "comcol-role.edit.community-admin.description": "Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", + "comcol-role.edit.collection-admin.description": "Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", + "comcol-role.edit.submitters.name": "Zgłaszający", + "comcol-role.edit.submitters.description": "Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", + "comcol-role.edit.item_read.name": "Domyślny dostęp do odczytu pozycji", + "comcol-role.edit.item_read.description": "Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", + "comcol-role.edit.item_read.anonymous-group": "Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", + "comcol-role.edit.bitstream_read.name": "Domyślny dostęp do oczytu plików", + "comcol-role.edit.bitstream_read.description": "Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", + "comcol-role.edit.bitstream_read.anonymous-group": "Domyślny status odczytu dla nowych plików to Anonimowy.", + "comcol-role.edit.editor.name": "Redaktorzy", + "comcol-role.edit.editor.description": "Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", + "comcol-role.edit.finaleditor.name": "Redaktorzy końcowi", + "comcol-role.edit.finaleditor.description": "Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", + "comcol-role.edit.reviewer.name": "Recenzenci", + "comcol-role.edit.reviewer.description": "Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", + "community.form.abstract": "Opis skrócony", + "community.form.description": "Wstęp (HTML)", + "community.form.errors.title.required": "Wprowadź nazwę zbioru", + "community.form.rights": "Prawa autoskie (HTML)", + "community.form.tableofcontents": "Wiadomości (HTML)", + "community.form.title": "Nazwa", + "community.page.edit": "Edytuj ten zbiór", + "community.page.handle": "Stały URI zbioru", + "community.page.license": "Licencja", + "community.page.news": "Wiadomości", + "community.all-lists.head": "Podzbiory i kolekcje", + "community.sub-collection-list.head": "Kolekcje w tym zbiorze", + "community.sub-community-list.head": "Kolekcje w tym zbiorze", + "cookies.consent.accept-all": "Zaakceptuj wszystko", + "cookies.consent.accept-selected": "Zaakceptuj wybrane", + "cookies.consent.app.opt-out.description": "Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", + "cookies.consent.app.opt-out.title": "(możesz ją wyłaczyć)", + "cookies.consent.app.purpose": "cel", + "cookies.consent.app.required.description": "Ta aplikacja jest zawsze wymagana", + "cookies.consent.app.required.title": "(zawsze wymagana)", + "cookies.consent.update": "Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", + "cookies.consent.close": "Zamknij", + "cookies.consent.decline": "Odrzuć", + "cookies.consent.content-notice.description": "Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", + "cookies.consent.content-notice.learnMore": "Dostosuj", + "cookies.consent.content-modal.description": "Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", + "cookies.consent.content-modal.privacy-policy.name": "polityka prywatności", + "cookies.consent.content-modal.privacy-policy.text": "Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", + "cookies.consent.content-modal.title": "Informacje, które zbieramy", + "cookies.consent.app.title.authentication": "Logowanie", + "cookies.consent.app.description.authentication": "Musisz się zalogować", + "cookies.consent.app.title.preferences": "Preferencje", + "cookies.consent.app.description.preferences": "Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.acknowledgement": "Zgody", + "cookies.consent.app.description.acknowledgement": "Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.google-analytics": "Google Analytics", + "cookies.consent.app.description.google-analytics": "Pozwól na śledzenie do celów statystycznych", + "cookies.consent.purpose.functional": "Funkcjonalne", + "cookies.consent.purpose.statistical": "Statystyczne", + "curation-task.task.checklinks.label": "Sprawdź odnośniki w metadanych", + "curation-task.task.noop.label": "NOOP", + "curation-task.task.profileformats.label": "Profil formatów plików", + "curation-task.task.requiredmetadata.label": "Sprawdź poprawność wymaganych metadanych", + "curation-task.task.translate.label": "Microsoft Translator", + "curation-task.task.vscan.label": "Skan antywirusowy", + "curation.form.task-select.label": "Zadanie:", + "curation.form.submit": "Start", + "curation.form.submit.success.head": "Udało się rozpocząć zadanie administratora", + "curation.form.submit.success.content": "Zostaniesz przeniesiony na stronę procesu.", + "curation.form.submit.error.head": "Nie udało się się zakończyć zadania administratora", + "curation.form.submit.error.content": "Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", + "curation.form.handle.label": "Automatyzacja:", + "curation.form.handle.hint": "Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", + "deny-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.subject": "Wystąp o kopię dokumentu", + "deny-request-copy.error": "Wystąpił błąd", + "deny-request-copy.header": "Odrzuć prośbę o przesłanie kopii dokumentu", + "deny-request-copy.intro": "Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", + "deny-request-copy.success": "Z powodzeniem odrzucono prośbę o udostępnienie pozycji", + "dso.name.untitled": "Brak tytułu", + "dso-selector.claim.item.head": "Wskazówki profilu", + "dso-selector.claim.item.body": "Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", + "dso-selector.claim.item.create-from-scratch": "Utwórz nowy", + "dso-selector.claim.item.not-mine-label": "Żaden nie jest mój", + "dso-selector.create.collection.head": "Nowa kolekcja", + "dso-selector.create.collection.sub-level": "Utwórz nową kolekcję w", + "dso-selector.create.community.head": "Nowy zbiór", + "dso-selector.create.community.sub-level": "Utwórz nowy zbiór", + "dso-selector.create.community.top-level": "Utwórz nowy nadrzędny zbiór", + "dso-selector.create.item.head": "Nowa pozycja", + "dso-selector.create.item.sub-level": "Utwórz nową pozycję w", + "dso-selector.create.submission.head": "Nowe zgłoszenie", + "dso-selector.edit.collection.head": "Edytuj kolekcję", + "dso-selector.edit.community.head": "Edytuj zbiór", + "dso-selector.edit.item.head": "Edytuj pozycję", + "dso-selector.error.title": "Wystąpił błąd podczas wyszukiwania typu {{ type }}", + "dso-selector.export-metadata.dspaceobject.head": "Eksportuj metadane z", + "dso-selector.no-results": "Nie znaleziono {{ type }}", + "dso-selector.placeholder": "Wyszukaj {{ type }}", + "dso-selector.select.collection.head": "Wybierz kolekcję", + "dso-selector.set-scope.community.head": "Wybierz wyszukiwanie zakresu", + "dso-selector.set-scope.community.button": "Wyszukaj w całym DSpace", + "dso-selector.set-scope.community.input-header": "Wyszukaj zbiór lub kolekcję", + "confirmation-modal.export-metadata.header": "Eksportuj metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.info": "Czy na pewno chcesz eksportować metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.cancel": "Anuluj", + "confirmation-modal.export-metadata.confirm": "Eksportuj", + "confirmation-modal.delete-eperson.header": "Usuń użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.cancel": "Anuluj", + "confirmation-modal.delete-eperson.confirm": "Usuń", + "error.bitstream": "Wystąpił błąd podczas tworzenia plików", + "error.browse-by": "Wystąpił błąd podczas tworzenia pozycji", + "error.collection": "Wystąpił błąd podczas tworzenia kolekcji", + "error.collections": "Wystąpił błąd podczas tworzenia kolekcji", + "error.community": "Wystąpił błąd podczas tworzenia ziboru", + "error.identifier": "Nie znaleziono pozycji z podanym identyfikatorem", + "error.default": "Błąd", + "error.item": "Wystąpił błąd podczas tworzenia pozycji", + "error.items": "Wystąpił błąd podczas tworzenia pozycji", + "error.objects": "Wystąpił błąd podczas tworzenia obiektów", + "error.recent-submissions": "Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", + "error.search-results": "Wystąpił błąd podczas tworzenia wyników wyszukiwania", + "error.sub-collections": "Wystąpił błąd podczas tworzenia podkolekcji", + "error.sub-communities": "Wystąpił błąd podczas tworzenia podzbiorów", + "error.submission.sections.init-form-error": "Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", + "error.top-level-communities": "Błąd podczas pobierania nadrzędnego zbioru", + "error.validation.license.notgranted": "Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", + "error.validation.pattern": "Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", + "error.validation.filerequired": "Przesłanie pliku jest obowiązkowe", + "error.validation.required": "Pole jest wymagane", + "error.validation.NotValidEmail": "E-mail nie jest poprawny", + "error.validation.emailTaken": "E-mail jest już zarejestrowany", + "error.validation.groupExists": "Ta grupa już istnieje", + "file-section.error.header": "Błąd podczas uzyskiwania plików dla tej pozycji", + "footer.copyright": "copyright © 2002-{{ year }}", + "footer.link.dspace": "oprogramowanie DSpace", + "footer.link.lyrasis": "LYRASIS", + "footer.link.cookies": "Ustawienia plików cookies", + "footer.link.privacy-policy": "Polityka prywatności", + "footer.link.end-user-agreement": "Umowa użytkownika", + "forgot-email.form.header": "Nie pamiętam hasła", + "forgot-email.form.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "forgot-email.form.email": "Adres e-mail *", + "forgot-email.form.email.error.required": "Uzupełnij adres e-mail", + "forgot-email.form.email.error.pattern": "Uzupełnij prawidłowy adres e-mail", + "forgot-email.form.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "forgot-email.form.submit": "Wyślij", + "forgot-email.form.success.head": "Wysłano wiadomość weryfikacyjną", + "forgot-email.form.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "forgot-email.form.error.head": "Błąd podczas rejestracji adresu e-mail", + "forgot-email.form.error.content": "Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", + "forgot-password.title": "Nie pamiętam hasła", + "forgot-password.form.head": "Nie pamiętam hasła", + "forgot-password.form.info": "Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", + "forgot-password.form.card.security": "Bezpieczeństwo", + "forgot-password.form.identification.header": "Identifikacja", + "forgot-password.form.identification.email": "Adres e-mail: ", + "forgot-password.form.label.password": "Hasło", + "forgot-password.form.label.passwordrepeat": "Potwierdź hasło", + "forgot-password.form.error.empty-password": "Wpisz hasło poniżej.", + "forgot-password.form.error.matching-passwords": "Hasła nie są identyczne.", + "forgot-password.form.notification.error.title": "Błąd podczas próby ustawienia nowego hasła", + "forgot-password.form.notification.success.content": "Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", + "forgot-password.form.notification.success.title": "Resetowanie hasła udane", + "forgot-password.form.submit": "Wpisz hasło", + "form.add": "Dodaj", + "form.add-help": "Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", + "form.cancel": "Anuluj", + "form.clear": "Wyczyść", + "form.clear-help": "Kliknij tutaj, aby usunąć wybraną wartość", + "form.discard": "Odrzuć", + "form.drag": "Przeciągnij", + "form.edit": "Edytuj", + "form.edit-help": "Kliknij tutaj, aby edytować wybraną wartość", + "form.first-name": "Imię", + "form.last-name": "Nazwisko", + "form.loading": "Ładowanie...", + "form.lookup": "Przeglądaj", + "form.lookup-help": "Kliknij tutaj, aby zobaczyć istniejące powiązania", + "form.no-results": "Nie znaleziono rezultatów", + "form.no-value": "Nie wprowadzono wartości", + "form.remove": "Usuń", + "form.save": "Zapisz", + "form.save-help": "Zapisz zmiany", + "form.search": "Wyszukaj", + "form.search-help": "Kliknij tutaj, aby wyszukać w istniejących komentarzach", + "form.submit": "Zapisz", + "form.repeatable.sort.tip": "Upuść nową pozycję w nowym miejscu", + "grant-deny-request-copy.deny": "Nie przesyłaj kopii", + "grant-deny-request-copy.email.back": "Cofnij", + "grant-deny-request-copy.email.message": "Wiadomości", + "grant-deny-request-copy.email.message.empty": "Proszę wprowadzić wiadomość", + "grant-deny-request-copy.email.permissions.info": "W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", + "grant-deny-request-copy.email.permissions.label": "Ustaw jako otwarty dostęp", + "grant-deny-request-copy.email.send": "Wyślij", + "grant-deny-request-copy.email.subject": "Temat", + "grant-deny-request-copy.email.subject.empty": "Wpisz temat", + "grant-deny-request-copy.grant": "Wyślij kopię", + "grant-deny-request-copy.header": "Prośba o przesłanie kopii dokumentu", + "grant-deny-request-copy.home-page": "Zabierz mnie na stronę główną", + "grant-deny-request-copy.intro1": "Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", + "grant-deny-request-copy.intro2": "Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", + "grant-deny-request-copy.processed": "Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "grant-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "grant-request-copy.email.subject": "Prośba o kopię dokumentu", + "grant-request-copy.error": "Wystąpił błąd", + "grant-request-copy.header": "Zezwól na wysłanie kopii dokumentu", + "grant-request-copy.intro": "To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", + "grant-request-copy.success": "Prośba o dostęp do dokumentu została przyjęta", + "home.description": "", + "home.breadcrumbs": "Strona główna", + "home.search-form.placeholder": "Przeszukaj repozytorium...", + "home.title": "Strona główna", + "home.top-level-communities.head": "Zbiory w DSpace", + "home.top-level-communities.help": "Przeszukaj kolekcje", + "info.end-user-agreement.accept": "Przeczytałem/am i akceptuję umowę użytkownika", + "info.end-user-agreement.accept.error": "Błąd wystąpił podczas akceptowania umowy użytkownika", + "info.end-user-agreement.accept.success": "Udało się zaktualizować umowę użytkownika", + "info.end-user-agreement.breadcrumbs": "Umowa użytkownika", + "info.end-user-agreement.buttons.cancel": "Anuluj", + "info.end-user-agreement.buttons.save": "Zapisz", + "info.end-user-agreement.head": "Umowa użytkownika", + "info.end-user-agreement.title": "Umowa użytkownika", + "info.privacy.breadcrumbs": "Oświadczenie polityki prywatności", + "info.privacy.head": "Oświadczenie polityki prywatności", + "info.privacy.title": "Oświadczenie polityki prywatności", + "item.alerts.private": "Ta pozycja jest prywatna", + "item.alerts.withdrawn": "Ta pozycja została wycofana", + "item.edit.authorizations.heading": "Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", + "item.edit.authorizations.title": "Edytuj politykę tej pozycji", + "item.badge.private": "Prywatny status publikacji", + "item.badge.withdrawn": "Wycofane publikacje", + "item.bitstreams.upload.bundle": "Pakiet", + "item.bitstreams.upload.bundle.placeholder": "Wybierz pakiet", + "item.bitstreams.upload.bundle.new": "Utworz pakiet", + "item.bitstreams.upload.bundles.empty": "Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", + "item.bitstreams.upload.cancel": "Anuluj", + "item.bitstreams.upload.drop-message": "Upuść plik, aby przesłać", + "item.bitstreams.upload.item": "Pozycja: ", + "item.bitstreams.upload.notifications.bundle.created.content": "Udało się utworzyć nowy pakiet.", + "item.bitstreams.upload.notifications.bundle.created.title": "Utwórz pakiet", + "item.bitstreams.upload.notifications.upload.failed": "Zweryfikuj pliki przed spróbowaniem ponownie.", + "item.bitstreams.upload.title": "Prześlij strumień bitów", + "item.edit.bitstreams.bundle.edit.buttons.upload": "Prześlij", + "item.edit.bitstreams.bundle.displaying": "Obecnie wyświetlono {{ amount }} plików z {{ total }}.", + "item.edit.bitstreams.bundle.load.all": "Załaduj wszystkie ({{ total }})", + "item.edit.bitstreams.bundle.load.more": "Załaduj więcej", + "item.edit.bitstreams.bundle.name": "PACZKA: {{ name }}", + "item.edit.bitstreams.discard-button": "Odrzuć", + "item.edit.bitstreams.edit.buttons.download": "Pobierz", + "item.edit.bitstreams.edit.buttons.drag": "Przeciągnij", + "item.edit.bitstreams.edit.buttons.edit": "Edytuj", + "item.edit.bitstreams.edit.buttons.remove": "Usuń", + "item.edit.bitstreams.edit.buttons.undo": "Cofnij zmiany", + "item.edit.bitstreams.empty": "Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", + "item.edit.bitstreams.headers.actions": "Akcje", + "item.edit.bitstreams.headers.bundle": "Paczka", + "item.edit.bitstreams.headers.description": "Opis", + "item.edit.bitstreams.headers.format": "Format", + "item.edit.bitstreams.headers.name": "Nazwa", + "item.edit.bitstreams.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", + "item.edit.bitstreams.notifications.discarded.title": "Zmiany odrzucone", + "item.edit.bitstreams.notifications.move.failed.title": "Błąd podczas przenoszenia plików", + "item.edit.bitstreams.notifications.move.saved.content": "Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", + "item.edit.bitstreams.notifications.move.saved.title": "Zmiana pozycji została zapisana", + "item.edit.bitstreams.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", + "item.edit.bitstreams.notifications.outdated.title": "Zmiany nieaktualne", + "item.edit.bitstreams.notifications.remove.failed.title": "Błąd podczas usuwania pliku", + "item.edit.bitstreams.notifications.remove.saved.content": "Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", + "item.edit.bitstreams.notifications.remove.saved.title": "Zmiany dotyczące usunięcia zapisane", + "item.edit.bitstreams.reinstate-button": "Cofnij", + "item.edit.bitstreams.save-button": "Zapisz", + "item.edit.bitstreams.upload-button": "Prześlij", + "item.edit.delete.cancel": "Anuluj", + "item.edit.delete.confirm": "Usuń", + "item.edit.delete.description": "Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", + "item.edit.delete.error": "Błąd wystąpił podczas usuwania pozycji", + "item.edit.delete.header": "Usuń pozycję: {{ id }}", + "item.edit.delete.success": "Ta pozycja została usunięta", + "item.edit.head": "Edytuj pozycję", + "item.edit.breadcrumbs": "Edytuj pozycję", + "item.edit.tabs.disabled.tooltip": "Nie masz dostępu do tej strony", + "item.edit.tabs.mapper.head": "Mapper kolekcji", + "item.edit.tabs.item-mapper.title": "Edytowanie pozycji - Mapper kolekcji", + "item.edit.item-mapper.buttons.add": "Mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.buttons.remove": "Usuń mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.cancel": "Anuluj", + "item.edit.item-mapper.description": "To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", + "item.edit.item-mapper.head": "Mapper pozycji - Mapowanie pozycji do kolekcji", + "item.edit.item-mapper.item": "Pozycja: \"<b>{{name}}</b>\"", + "item.edit.item-mapper.no-search": "Wpisz zapytanie, które chcesz wyszukać", + "item.edit.item-mapper.notifications.add.error.content": "Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.add.error.head": "Błędy mapowania", + "item.edit.item-mapper.notifications.add.success.content": "Udało się zmapować elementy dla {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.add.success.head": "Mapowanie zakończone", + "item.edit.item-mapper.notifications.remove.error.content": "Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.remove.error.head": "Usunięcie mapowania błędów", + "item.edit.item-mapper.notifications.remove.success.content": "Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.remove.success.head": "Usuwanie mapowania zakończone", + "item.edit.item-mapper.search-form.placeholder": "Przeszukaj kolekcje...", + "item.edit.item-mapper.tabs.browse": "Przeglądaj zmapowane kolekcje", + "item.edit.item-mapper.tabs.map": "Mapuj nowe kolekcje", + "item.edit.metadata.add-button": "Dodaj", + "item.edit.metadata.discard-button": "Odrzuć", + "item.edit.metadata.edit.buttons.edit": "Edytuj", + "item.edit.metadata.edit.buttons.remove": "Usuń", + "item.edit.metadata.edit.buttons.undo": "Cofnij zmiany", + "item.edit.metadata.edit.buttons.unedit": "Zatrzymaj edycję", + "item.edit.metadata.empty": "Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", + "item.edit.metadata.headers.edit": "Edytuj", + "item.edit.metadata.headers.field": "Pole", + "item.edit.metadata.headers.language": "Język", + "item.edit.metadata.headers.value": "Wartość", + "item.edit.metadata.metadatafield.invalid": "Wybierz aktualne pole metadanych", + "item.edit.metadata.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", + "item.edit.metadata.notifications.discarded.title": "Zmiany odrzucone", + "item.edit.metadata.notifications.error.title": "Wystąpił błąd", + "item.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", + "item.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadane", + "item.edit.metadata.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", + "item.edit.metadata.notifications.outdated.title": "Zmiany nieaktualne", + "item.edit.metadata.notifications.saved.content": "Twoje zmiany metadanych tej pozycji zostały zapisane.", + "item.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", + "item.edit.metadata.reinstate-button": "Cofnij", + "item.edit.metadata.save-button": "Zapisz", + "item.edit.modify.overview.field": "Pole", + "item.edit.modify.overview.language": "Język", + "item.edit.modify.overview.value": "Wartość", + "item.edit.move.cancel": "Anuluj", + "item.edit.move.save-button": "Zapisz", + "item.edit.move.discard-button": "Odrzuć", + "item.edit.move.description": "Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", + "item.edit.move.error": "Wystąpił błąd podczas przenoszenia pozycji", + "item.edit.move.head": "Przenieś pozycję: {{id}}", + "item.edit.move.inheritpolicies.checkbox": "Dziedziczenie polityk", + "item.edit.move.inheritpolicies.description": "Dziedzczenie domyślnych polityk z kolekcji docelowej", + "item.edit.move.move": "Przenieś", + "item.edit.move.processing": "Przenoszenie...", + "item.edit.move.search.placeholder": "Wpisz zapytanie, aby wyszukać w kolekcjach", + "item.edit.move.success": "Pozycja została przeniesiona", + "item.edit.move.title": "Przenieś pozycję", + "item.edit.private.cancel": "Anuluj", + "item.edit.private.confirm": "Ukryj", + "item.edit.private.description": "Czy chcesz ukryć tę pozycję?", + "item.edit.private.error": "Wystąpił błąd podczas ukrywania pozycji", + "item.edit.private.header": "Ukryj pozycję: {{ id }}", + "item.edit.private.success": "Pozycja jest teraz ukryta", + "item.edit.public.cancel": "Anuluj", + "item.edit.public.confirm": "Upublicznij", + "item.edit.public.description": "Czy chcesz upublicznić tę pozycję?", + "item.edit.public.error": "Wystąpił błąd podczas upubliczniania pozycji", + "item.edit.public.header": "Upublicznij pozycję: {{ id }}", + "item.edit.public.success": "Pozycja jest teraz publiczna", + "item.edit.reinstate.cancel": "Anuluj", + "item.edit.reinstate.confirm": "Przywróć", + "item.edit.reinstate.description": "Czy chcesz przywrócić tę pozycję?", + "item.edit.reinstate.error": "Wystąpił błąd podczas przywracania pozycji", + "item.edit.reinstate.header": "Przywróć pozycję: {{ id }}", + "item.edit.reinstate.success": "Pozycja została przywrócona", + "item.edit.relationships.discard-button": "Odrzuć", + "item.edit.relationships.edit.buttons.add": "Dodaj", + "item.edit.relationships.edit.buttons.remove": "Usuń", + "item.edit.relationships.edit.buttons.undo": "Cofnij zmiany", + "item.edit.relationships.no-relationships": "Brak relacji", + "item.edit.relationships.notifications.discarded.content": "Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", + "item.edit.relationships.notifications.discarded.title": "Zmiany zostały cofnięte", + "item.edit.relationships.notifications.failed.title": "Wystąpił błąd podczas edytowania relacji", + "item.edit.relationships.notifications.outdated.content": "Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", + "item.edit.relationships.notifications.outdated.title": "Zmiany są nieaktualne", + "item.edit.relationships.notifications.saved.content": "Twoje zmiany w relacjach tej pozycji zostały zapisane.", + "item.edit.relationships.notifications.saved.title": "Relacje zostały zapisane", + "item.edit.relationships.reinstate-button": "Cofnij", + "item.edit.relationships.save-button": "Zapisz", + "item.edit.relationships.no-entity-type": "Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", + "item.edit.return": "Cofnij", + "item.edit.tabs.bitstreams.head": "Pliki", + "item.edit.tabs.bitstreams.title": "Edycja pozycji - pliki", + "item.edit.tabs.curate.head": "Administruj", + "item.edit.tabs.curate.title": "Edytowanie pozycji - administruj", + "item.edit.tabs.metadata.head": "Metadane", + "item.edit.tabs.metadata.title": "Edycja pozycji - metadane", + "item.edit.tabs.relationships.head": "Relacje", + "item.edit.tabs.relationships.title": "Edycja pozycja - relacje", + "item.edit.tabs.status.buttons.authorizations.button": "Dostępy...", + "item.edit.tabs.status.buttons.authorizations.label": "Określu dostęp do pozycji", + "item.edit.tabs.status.buttons.delete.button": "Usuń permanentnie", + "item.edit.tabs.status.buttons.delete.label": "Usuń pozycję permanentnie", + "item.edit.tabs.status.buttons.mappedCollections.button": "Zmapowane kolekcje", + "item.edit.tabs.status.buttons.mappedCollections.label": "Zarządzaj mapowanymi kolekcjami", + "item.edit.tabs.status.buttons.move.button": "Przenieś...", + "item.edit.tabs.status.buttons.move.label": "Przenieś pozycję do innej kolekcji", + "item.edit.tabs.status.buttons.private.button": "Ukryj...", + "item.edit.tabs.status.buttons.private.label": "Ukry pozycję", + "item.edit.tabs.status.buttons.public.button": "Upublicznij...", + "item.edit.tabs.status.buttons.public.label": "Upublicznij pozycję", + "item.edit.tabs.status.buttons.reinstate.button": "Przywróć...", + "item.edit.tabs.status.buttons.reinstate.label": "Przywróć pozycję", + "item.edit.tabs.status.buttons.unauthorized": "You're not authorized to perform this action", + "item.edit.tabs.status.buttons.withdraw.button": "Wycofaj...", + "item.edit.tabs.status.buttons.withdraw.label": "Wycofaj z repozytorium", + "item.edit.tabs.status.description": "Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", + "item.edit.tabs.status.head": "Status", + "item.edit.tabs.status.labels.handle": "Identyfikator", + "item.edit.tabs.status.labels.id": "ID pozycji", + "item.edit.tabs.status.labels.itemPage": "Strona pozycji", + "item.edit.tabs.status.labels.lastModified": "Ostatnia modyfikacja", + "item.edit.tabs.status.title": "Edycja pozycji - Status", + "item.edit.tabs.versionhistory.head": "Historia wersji", + "item.edit.tabs.versionhistory.title": "Edycja pozycji - historia wersji", + "item.edit.tabs.versionhistory.under-construction": "Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", + "item.edit.tabs.view.head": "Widok pozycji", + "item.edit.tabs.view.title": "Edycja pozycji - widok", + "item.edit.withdraw.cancel": "Anuluj", + "item.edit.withdraw.confirm": "Wycofaj", + "item.edit.withdraw.description": "Czy na pewno chcesz wycofać pozycję?", + "item.edit.withdraw.error": "Wystąpił błąd podczas wycofywania pozycji", + "item.edit.withdraw.header": "Wycofaj pozycję: {{ id }}", + "item.edit.withdraw.success": "Pozycja została wycofana", + "item.listelement.badge": "Pozycja", + "item.page.description": "Opis", + "item.page.journal-issn": "ISSN czasopisma", + "item.page.journal-title": "Tytuł czasopisma", + "item.page.publisher": "Wydawca", + "item.page.titleprefix": "Pozycja: ", + "item.page.volume-title": "Tytuł tomu", + "item.search.results.head": "Wyniki wyszukiwania pozycji", + "item.search.title": "Wyszukiwanie pozycji", + "item.page.abstract": "Abstrakt", + "item.page.author": "Autorzy", + "item.page.citation": "Cytowanie", + "item.page.collections": "Kolekcje", + "item.page.collections.loading": "Ładowanie...", + "item.page.collections.load-more": "Załaduj więcej", + "item.page.date": "Data", + "item.page.edit": "Edytuj pozycję", + "item.page.files": "Pliki", + "item.page.filesection.description": "Opis:", + "item.page.filesection.download": "Pobierz", + "item.page.filesection.format": "Format:", + "item.page.filesection.name": "Nazwa:", + "item.page.filesection.size": "Rozmiar:", + "item.page.journal.search.title": "Artykuły w czasopiśmie", + "item.page.link.full": "Zobacz szczegóły", + "item.page.link.simple": "Uproszczony widok", + "item.page.person.search.title": "Artykuły tego autora", + "item.page.related-items.view-more": "Pokaż o {{ amount }} więcej", + "item.page.related-items.view-less": "Ukryj {{ amount }}", + "item.page.relationships.isAuthorOfPublication": "Publikacje", + "item.page.relationships.isJournalOfPublication": "Publikacje", + "item.page.relationships.isOrgUnitOfPerson": "Autorzy", + "item.page.relationships.isOrgUnitOfProject": "Projekty naukowe", + "item.page.subject": "Słowa kluczowe", + "item.page.uri": "URI", + "item.page.bitstreams.view-more": "Pokaż więcej", + "item.page.bitstreams.collapse": "Pokaż mniej", + "item.page.filesection.original.bundle": "Oryginalne pliki", + "item.page.filesection.license.bundle": "Licencja", + "item.page.return": "Powrót", + "item.page.version.create": "Utwórz nową wersję", + "item.page.version.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.preview.dc.identifier.doi": "DOI", + "item.preview.dc.relation.ispartof": "Czasopismo lub seria", + "item.preview.dc.identifier.isbn": "ISBN", + "item.preview.dc.identifier.uri": "Identyfikator:", + "item.preview.dc.contributor.author": "Autorzy:", + "item.preview.dc.date.issued": "Data publikacji:", + "item.preview.dc.description.abstract": "Abstrakt:", + "item.preview.dc.identifier.other": "Inny identyfikator:", + "item.preview.dc.language.iso": "Język:", + "item.preview.dc.title": "Tytuł:", + "item.preview.dc.title.alternative": "Tytuł alternatywny", + "item.preview.dc.type": "Typ:", + "item.preview.dc.identifier": "Identyfikator:", + "item.preview.dc.relation.issn": "ISSN", + "item.preview.oaire.citation.issue": "Numer wydania", + "item.preview.oaire.citation.volume": "Numer tomu", + "item.preview.person.familyName": "Nazwisko:", + "item.preview.person.givenName": "Nazwa:", + "item.preview.person.identifier.orcid": "ORCID:", + "item.preview.project.funder.name": "Fundator:", + "item.preview.project.funder.identifier": "Identyfikator fundatora:", + "item.preview.oaire.awardNumber": "ID finansowania:", + "item.preview.dc.coverage.spatial": "Jurysdykcja:", + "item.preview.oaire.fundingStream": "Źródło finansowania:", + "item.select.confirm": "Potwierdź zaznaczone", + "item.select.empty": "Brak pozycji do wyświetlenia", + "item.select.table.author": "Autor", + "item.select.table.collection": "Kolekcja", + "item.select.table.title": "Tytuł", + "item.version.history.empty": "Jeszcze nie ma innych wersji tej pozycji.", + "item.version.history.head": "Poprzednie wersje", + "item.version.history.return": "Powrót", + "item.version.history.selected": "Wybrane wersje", + "item.version.history.selected.alert": "W tym momencie wyświetlono wersję {{version}} pozycji.", + "item.version.history.table.version": "Wersja", + "item.version.history.table.item": "Pozycja", + "item.version.history.table.editor": "Redaktor", + "item.version.history.table.date": "Data", + "item.version.history.table.summary": "Podsumowanie", + "item.version.history.table.workspaceItem": "Wersja robocza", + "item.version.history.table.workflowItem": "Pozycja workflow", + "item.version.history.table.actions": "Akcja", + "item.version.history.table.action.editWorkspaceItem": "Edytuj wersję roboczą pozycji", + "item.version.history.table.action.editSummary": "Edytuj podsumowanie", + "item.version.history.table.action.saveSummary": "Zapisz edycje podsumowania", + "item.version.history.table.action.discardSummary": "Odrzuć edycje podsumowania", + "item.version.history.table.action.newVersion": "Utwórz nową wersję z tej wersji", + "item.version.history.table.action.deleteVersion": "Wersja usunięta", + "item.version.history.table.action.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.version.notice": "To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", + "item.version.create.modal.header": "Nowa wersja", + "item.version.create.modal.text": "Utwórz nową wersję tej pozycji", + "item.version.create.modal.text.startingFrom": "zaczynając od wersji {{version}}", + "item.version.create.modal.button.confirm": "Utwórz", + "item.version.create.modal.button.confirm.tooltip": "Utwórz nową wersję", + "item.version.create.modal.button.cancel": "Anuluj", + "item.version.create.modal.button.cancel.tooltip": "Nie stwarzaj nowej wersji", + "item.version.create.modal.form.summary.label": "Podsumowanie", + "item.version.create.modal.form.summary.placeholder": "Wprowadź podsumowanie nowej wersji", + "item.version.create.notification.success": "Nowa wersja została utworzona z numerem {{version}}", + "item.version.create.notification.failure": "Nowa wersja nie została utworzona", + "item.version.create.notification.inProgress": "Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", + "item.version.delete.modal.header": "Usuń wersję", + "item.version.delete.modal.text": "Czy chcesz usunąć wersję {{version}}?", + "item.version.delete.modal.button.confirm": "Usuń", + "item.version.delete.modal.button.confirm.tooltip": "Usuń wersję", + "item.version.delete.modal.button.cancel": "Anuluj", + "item.version.delete.modal.button.cancel.tooltip": "Nie usuwaj tej wersji", + "item.version.delete.notification.success": "Wersja {{version}} została usunięta", + "item.version.delete.notification.failure": "Wersja {{version}} nie została usunięta", + "item.version.edit.notification.success": "Podsumowanie wersji {{version}} zostało zmienione", + "item.version.edit.notification.failure": "Podsumowanie wersji {{version}} nie zostało zmienione", + "journal.listelement.badge": "Czasopismo", + "journal.page.description": "Opis", + "journal.page.edit": "Edytuj tę pozycję", + "journal.page.editor": "Redaktor naczelny", + "journal.page.issn": "ISSN", + "journal.page.publisher": "Wydawca", + "journal.page.titleprefix": "Czasopismo: ", + "journal.search.results.head": "Wyniki wyszukiwania czasopism", + "journal.search.title": "Wyszukiwanie czasopism", + "journalissue.listelement.badge": "Numer czasopisma", + "journalissue.page.description": "Opis", + "journalissue.page.edit": "Edytuj pozycję", + "journalissue.page.issuedate": "Data wydania", + "journalissue.page.journal-issn": "ISSN czasopisma", + "journalissue.page.journal-title": "Tytuł czasopisma", + "journalissue.page.keyword": "Słowa kluczowe", + "journalissue.page.number": "Numer", + "journalissue.page.titleprefix": "Wydanie czasopisma: ", + "journalvolume.listelement.badge": "Numer tomu czasopisma", + "journalvolume.page.description": "Opis", + "journalvolume.page.edit": "Edytuj pozycję", + "journalvolume.page.issuedate": "Data wydania", + "journalvolume.page.titleprefix": "Numer tomu czasopisma: ", + "journalvolume.page.volume": "Numer wydania", + "iiifsearchable.listelement.badge": "Multimedia dokumentu", + "iiifsearchable.page.titleprefix": "Dokument: ", + "iiifsearchable.page.doi": "Stały link: ", + "iiifsearchable.page.issue": "Wydanie: ", + "iiifsearchable.page.description": "Opis: ", + "iiifviewer.fullscreen.notice": "Wyświetl na pełnym ekranie dla lepszego widoku.", + "iiif.listelement.badge": "Multimedia obrazu", + "iiif.page.titleprefix": "Obraz: ", + "iiif.page.doi": "Stały link: ", + "iiif.page.issue": "Numer wydania: ", + "iiif.page.description": "Opis: ", + "loading.bitstream": "Ładowanie pliku...", + "loading.bitstreams": "Ładowanie plików...", + "loading.browse-by": "Ładowanie pozycji...", + "loading.browse-by-page": "Ładowanie strony...", + "loading.collection": "Ładowanie kolekcji...", + "loading.collections": "Ładowanie kolekcji...", + "loading.content-source": "Ładowanie źródła treści...", + "loading.community": "Ładowanie zbioru...", + "loading.default": "Ładowanie...", + "loading.item": "Ładowanie pozycji...", + "loading.items": "Ładowanie pozycji...", + "loading.mydspace-results": "Ładowanie pozycji...", + "loading.objects": "Ładowanie...", + "loading.recent-submissions": "Ładowanie ostatnich zgłoszeń...", + "loading.search-results": "Ładowanie wyników wyszukiwania...", + "loading.sub-collections": "Ładowanie podkolekcji...", + "loading.sub-communities": "Ładowanie podzbioru...", + "loading.top-level-communities": "Ładowanie zbioru wyszego szczebla...", + "login.form.email": "Adres e-mail", + "login.form.forgot-password": "Nie pamiętasz hasła?", + "login.form.header": "Zaloguj się do DSpace", + "login.form.new-user": "Nie masz konta? Zarejestruj się.", + "login.form.or-divider": "lub", + "login.form.orcid": "Zaloguj za pomocą ORCID", + "login.form.oidc": "Zaloguj za pomocą OIDC", + "login.form.password": "Hasło", + "login.form.shibboleth": "Zaloguj za pomocą Shibboleth", + "login.form.submit": "Zaloguj się", + "login.title": "Zaloguj", + "login.breadcrumbs": "Zaloguj", + "logout.form.header": "Wyloguj się z DSpace", + "logout.form.submit": "Wyloguj się", + "logout.title": "Wylogowywanie", + "menu.header.admin": "Panel administracyjny", + "menu.header.image.logo": "Logo repozytorium", + "menu.header.admin.description": "Menu administratora", + "menu.section.access_control": "Uprawnienia", + "menu.section.access_control_authorizations": "Dostępy", + "menu.section.access_control_groups": "Grupy", + "menu.section.access_control_people": "Użytkownicy", + "menu.section.admin_search": "Wyszukiwanie administracyjne", + "menu.section.browse_community": "Ten zbiór", + "menu.section.browse_community_by_author": "Wg autorów", + "menu.section.browse_community_by_issue_date": "Wg daty wydania", + "menu.section.browse_community_by_title": "Wg tytułów", + "menu.section.browse_global": "Wszystko na DSpace", + "menu.section.browse_global_by_author": "Wg autorów", + "menu.section.browse_global_by_dateissued": "Wg daty wydania", + "menu.section.browse_global_by_subject": "Wg tematu", + "menu.section.browse_global_by_title": "Wg tytułu", + "menu.section.browse_global_communities_and_collections": "Zbiory i kolekcje", + "menu.section.control_panel": "Panel sterowania", + "menu.section.curation_task": "Zadanie administracyjne", + "menu.section.edit": "Edytuj", + "menu.section.edit_collection": "Kolekcja", + "menu.section.edit_community": "Zbiór", + "menu.section.edit_item": "Pozycja", + "menu.section.export": "Eksport", + "menu.section.export_collection": "Kolekcja", + "menu.section.export_community": "Zbiór", + "menu.section.export_item": "Pozycja", + "menu.section.export_metadata": "Metadane", + "menu.section.icon.access_control": "Sekcja menu Uprawnienia", + "menu.section.icon.admin_search": "Sekcja menu Wyszukiwanie administracyjne", + "menu.section.icon.control_panel": "Sekcja menu Panel sterowania", + "menu.section.icon.curation_tasks": "Sekcja menu Zadanie administracyjne", + "menu.section.icon.edit": "Sekcja menu Edycja", + "menu.section.icon.export": "Sekcja menu Eksport", + "menu.section.icon.find": "Sekcja menu Wyszukiwanie", + "menu.section.icon.import": "Sekcja menu Import", + "menu.section.icon.new": "Sekcja menu Dodaj", + "menu.section.icon.pin": "Przypnij boczny pasek", + "menu.section.icon.processes": "Sekcja menu Procesy", + "menu.section.icon.registries": "Sekcja menu Rejestry", + "menu.section.icon.statistics_task": "Sekcja menu Zadanie statystyczne", + "menu.section.icon.workflow": "Sekcja menu Zarządzanie workflow", + "menu.section.icon.unpin": "Odepnij boczny pasek", + "menu.section.import": "Import", + "menu.section.import_batch": "Import masowy (ZIP)", + "menu.section.import_metadata": "Metadane", + "menu.section.new": "Dodaj", + "menu.section.new_collection": "Kolekcja", + "menu.section.new_community": "Zbiór", + "menu.section.new_item": "Pozycja", + "menu.section.new_item_version": "Wersja pozycji", + "menu.section.new_process": "Proces", + "menu.section.pin": "Przypnij pasek boczny", + "menu.section.unpin": "Odepnij pasek boczny", + "menu.section.processes": "Procesy", + "menu.section.registries": "Rejestry", + "menu.section.registries_format": "Formaty", + "menu.section.registries_metadata": "Metadane", + "menu.section.statistics": "Statystyki", + "menu.section.statistics_task": "Zadanie statystyczne", + "menu.section.toggle.access_control": "Przełącz sekcję Uprawnienia", + "menu.section.toggle.control_panel": "Przełącz sekcję Panel sterowania", + "menu.section.toggle.curation_task": "Przełącz sekcję Zadanie kuratora", + "menu.section.toggle.edit": "Przełącz sekcję Edytuj", + "menu.section.toggle.export": "Przełącz sekcję Eksport", + "menu.section.toggle.find": "Przełącz sekcję Wyszukiwanie", + "menu.section.toggle.import": "Przełącz sekcję Import", + "menu.section.toggle.new": "Przełącz nową sekcję", + "menu.section.toggle.registries": "Przełącz sekcję Rejestry", + "menu.section.toggle.statistics_task": "Przełącz sekcję Zadanie statystyczne", + "menu.section.workflow": "Zarządzaj Workflow", + "mydspace.breadcrumbs": "Mój DSpace", + "mydspace.description": "", + "mydspace.messages.controller-help": "Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", + "mydspace.messages.description-placeholder": "Wpisz swoją wiadomość tutaj...", + "mydspace.messages.hide-msg": "Ukryj wiadomość", + "mydspace.messages.mark-as-read": "Oznacz jako przeczytane", + "mydspace.messages.mark-as-unread": "Oznacz jako nieprzeczytane", + "mydspace.messages.no-content": "Brak treści.", + "mydspace.messages.no-messages": "Brak wiadomości.", + "mydspace.messages.send-btn": "Wysłano", + "mydspace.messages.show-msg": "Pokaż wiadomość", + "mydspace.messages.subject-placeholder": "Temat...", + "mydspace.messages.submitter-help": "Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", + "mydspace.messages.title": "Wiadomości", + "mydspace.messages.to": "Do", + "mydspace.new-submission": "Nowe zgłoszenie", + "mydspace.new-submission-external": "Import medatanych z zewnętrznego źródła", + "mydspace.new-submission-external-short": "Import metadanych", + "mydspace.results.head": "Twoje zadania", + "mydspace.results.no-abstract": "Brak abstraktu", + "mydspace.results.no-authors": "Brak autorów", + "mydspace.results.no-collections": "Brak kolekcji", + "mydspace.results.no-date": "Brak daty", + "mydspace.results.no-files": "Brak plików", + "mydspace.results.no-results": "Brak pozycji do wyświetlenia", + "mydspace.results.no-title": "Brak tytułu", + "mydspace.results.no-uri": "Brak Uri", + "mydspace.search-form.placeholder": "Wyszukaj w mydspace...", + "mydspace.show.workflow": "Wszystkie zadania", + "mydspace.show.workspace": "Twoje zadania", + "mydspace.status.mydspaceArchived": "Zarchiwizowano", + "mydspace.status.mydspaceValidation": "Walidacja", + "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redaktora", + "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkspace": "Wersja robocza", + "mydspace.title": "Mój DSpace", + "mydspace.upload.upload-failed": "Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", + "mydspace.upload.upload-failed-manyentries": "Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", + "mydspace.upload.upload-failed-moreonefile": "Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", + "mydspace.upload.upload-multiple-successful": "Utworzono {{qty}} przestrzeni roboczych.", + "mydspace.view-btn": "Widok", + "nav.browse.header": "Cały DSpace", + "nav.community-browse.header": "Wg zbiorów", + "nav.language": "Zmień język", + "nav.login": "Zaloguj", + "nav.logout": "Menu profilu użytkownika i wylogowywanie", + "nav.main.description": "Główny pasek nawigacji", + "nav.mydspace": "Mój DSpace", + "nav.profile": "Profil", + "nav.search": "Wyszukiwanie", + "nav.statistics.header": "Statystyki", + "nav.stop-impersonating": "Przestań impersonifikować użytkownika", + "nav.toggle": "Przełącz nawigację", + "nav.user.description": "Pasek profilu użytkownika", + "none.listelement.badge": "Pozycja", + "person.listelement.badge": "Osoba", + "person.listelement.no-title": "Nie znaleziono imienia", + "person.page.birthdate": "Data urodzenia", + "person.page.edit": "Edytuj pozycję", + "person.page.email": "Adres e-mail", + "person.page.firstname": "Imię", + "person.page.jobtitle": "Stanowisko", + "person.page.lastname": "Nazwisko", + "person.page.link.full": "Pokaż wszystkie metadane", + "person.page.orcid": "ORCID", + "person.page.orcid.create": "Utwórz ORCID ID", + "person.page.orcid.granted-authorizations": "Udzielone dostępy", + "person.page.orcid.grant-authorizations": "Udziel dostępu", + "person.page.orcid.link": "Połącz z ORCID ID", + "person.page.orcid.orcid-not-linked-message": "ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", + "person.page.orcid.unlink": "Odepnij z ORCID", + "person.page.orcid.unlink.processing": "Procesowanie...", + "person.page.orcid.missing-authorizations": "Brak dostępów", + "person.page.orcid.missing-authorizations-message": "Brakuj następujących dostępów:", + "person.page.orcid.no-missing-authorizations-message": "Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", + "person.page.orcid.no-orcid-message": "Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", + "person.page.orcid.profile-preferences": "Preferencje profilu", + "person.page.orcid.funding-preferences": "Preferencje finansowania", + "person.page.orcid.publications-preferences": "Preferencje publikacji", + "person.page.orcid.remove-orcid-message": "Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", + "person.page.orcid.save.preference.changes": "Aktualizuj ustawienia", + "person.page.orcid.sync-profile.affiliation": "Afiliacja", + "person.page.orcid.sync-profile.biographical": "Biografia", + "person.page.orcid.sync-profile.education": "Edukacja", + "person.page.orcid.sync-profile.identifiers": "Identyfikatory", + "person.page.orcid.sync-fundings.all": "Wszystkie źrodła finansowania", + "person.page.orcid.sync-fundings.mine": "Moje źrodła finansowania", + "person.page.orcid.sync-fundings.my_selected": "Wybrane źródła finansowania", + "person.page.orcid.sync-fundings.disabled": "Nieaktywne", + "person.page.orcid.sync-publications.all": "Wszystkie publikacje", + "person.page.orcid.sync-publications.mine": "Moje publikacje", + "person.page.orcid.sync-publications.my_selected": "Wybrane publikacje", + "person.page.orcid.sync-publications.disabled": "Nieaktywne", + "person.page.orcid.sync-queue.discard": "Odrzuć zmianę i nie synchronizuj z ORCID", + "person.page.orcid.sync-queue.discard.error": "Rekord kolejki ORCID nie został odrzucony", + "person.page.orcid.sync-queue.discard.success": "Rekord kolejki ORCID został odrzucony", + "person.page.orcid.sync-queue.empty-message": "Rejestr kolejki w ORCID jest pusty", + "person.page.orcid.sync-queue.description.affiliation": "Afiliacje", + "person.page.orcid.sync-queue.description.country": "Kraj", + "person.page.orcid.sync-queue.description.education": "Edukacja", + "person.page.orcid.sync-queue.description.external_ids": "Zewnętrzne identyfikatory", + "person.page.orcid.sync-queue.description.other_names": "Inne imiona", + "person.page.orcid.sync-queue.description.qualification": "Kwalifikacje", + "person.page.orcid.sync-queue.description.researcher_urls": "URL naukowca", + "person.page.orcid.sync-queue.description.keywords": "Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.insert": "Dodaj nowy wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.update": "Aktualizuj ten wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.delete": "Usuń ten wpis z rejestru ORCID", + "person.page.orcid.sync-queue.tooltip.publication": "Publikacja", + "person.page.orcid.sync-queue.tooltip.affiliation": "Afiliacja", + "person.page.orcid.sync-queue.tooltip.education": "Edukacja", + "person.page.orcid.sync-queue.tooltip.qualification": "Kwalifikacje", + "person.page.orcid.sync-queue.tooltip.other_names": "Inna nazwa", + "person.page.orcid.sync-queue.tooltip.country": "Kraj", + "person.page.orcid.sync-queue.tooltip.keywords": "Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.external_ids": "Zewnętrzny identyfikator", + "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL naukowca", + "person.page.orcid.sync-queue.send": "Synchronizuj z rejestrem ORCID", + "person.page.orcid.sync-queue.send.unauthorized-error.title": "Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", + "person.page.orcid.sync-queue.send.unauthorized-error.content": "Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", + "person.page.orcid.sync-queue.send.bad-request-error": "Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", + "person.page.orcid.sync-queue.send.error": "Wysłanie zgłoszenia do ORCID nie powiodło się", + "person.page.orcid.sync-queue.send.conflict-error": "Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", + "person.page.orcid.sync-queue.send.not-found-warning": "Pozycja nie istnieje już w rejestrze ORCID.", + "person.page.orcid.sync-queue.send.success": "Zgłoszenie do ORCID zostało zakończone pomyślnie", + "person.page.orcid.sync-queue.send.validation-error": "Dane, które chcesz zsynchronizować z ORCID nie są poprawne", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Waluta jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", + "person.page.orcid.sync-queue.send.validation-error.title.required": "Tytuł jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.type.required": "Typ jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Data początkowa jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.funder.required": "Instytucja finansująca jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.required": "Instytucja jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Nazwa instytucji jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Aby wysłać instytucję, należy podać adres", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Aby wysłać adres, należy podać miasto", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Aby wysłać adres, należy podać kraj", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Należy uzupełnić wartość w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Należy uzupełnić źródło w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", + "person.page.orcid.synchronization-mode": "Tryb synchronizacji", + "person.page.orcid.synchronization-mode.batch": "Wsad", + "person.page.orcid.synchronization-mode.label": "Tryb synchronizacji", + "person.page.orcid.synchronization-mode-message": "Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", + "person.page.orcid.synchronization-settings-update.success": "Opcje synchronizacji zostały zaktualizowane", + "person.page.orcid.synchronization-settings-update.error": "Opcje synchronizacji nie zostały zaktualizowane", + "person.page.orcid.synchronization-mode.manual": "Ręczna", + "person.page.orcid.scope.authenticate": "Uzyskaj swój ORCID iD", + "person.page.orcid.scope.read-limited": "Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", + "person.page.orcid.scope.activities-update": "Dodaj/aktualizuj swoje aktywności naukowe", + "person.page.orcid.scope.person-update": "Dodaj/aktualizuj inne informacje o Tobie", + "person.page.orcid.unlink.success": "Odłączenie Twojego profilu od rejestru ORCID powiodło się", + "person.page.orcid.unlink.error": "Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", + "person.page.staffid": "ID pracownika", + "person.page.titleprefix": "Osoba: ", + "person.search.results.head": "Wyniki wyszukiwania użytkowników", + "person.search.title": "Wyniki wyszukiwania użytkowników", + "process.new.select-parameters": "Parametry", + "process.new.cancel": "Anuluj", + "process.new.submit": "Zapisz", + "process.new.select-script": "Skrypt", + "process.new.select-script.placeholder": "Wybierz skrypt...", + "process.new.select-script.required": "Skrypt jest wymagany", + "process.new.parameter.file.upload-button": "Wybierz plik...", + "process.new.parameter.file.required": "Proszę wybrać plik", + "process.new.parameter.string.required": "Wartość parametru jest wymagana", + "process.new.parameter.type.value": "wartość", + "process.new.parameter.type.file": "plik", + "process.new.parameter.required.missing": "Te parametry są wymagane, ale nie zostały uzupełnione:", + "process.new.notification.success.title": "Udało się", + "process.new.notification.success.content": "Udało się stworzyć proces", + "process.new.notification.error.title": "Błąd", + "process.new.notification.error.content": "Wystąpił błąd podczas tworzenia procesu", + "process.new.header": "Utwórz nowy proces", + "process.new.title": "Utwórz nowy proces", + "process.new.breadcrumbs": "Utwórz nowy proces", + "process.detail.arguments": "Argumenty", + "process.detail.arguments.empty": "Do tego procesu nie zostały przypisane żadne argumenty", + "process.detail.back": "Cofnij", + "process.detail.output": "Dane wyjściowe procesu", + "process.detail.logs.button": "Odzyskaj dane wyjściowe procesu", + "process.detail.logs.loading": "Odzyskiwanie", + "process.detail.logs.none": "Ten proces nie ma danych wyjściowych", + "process.detail.output-files": "Pliki", + "process.detail.output-files.empty": "Ten proces nie ma żadnych plików danych wyjściowych", + "process.detail.script": "Skrypt", + "process.detail.title": "Proces: {{ id }} - {{ name }}", + "process.detail.start-time": "Czas rozpoczęcia procesu", + "process.detail.end-time": "Czas zakończenia procesu", + "process.detail.status": "Status", + "process.detail.create": "Stwórz podobny proces", + "process.overview.table.finish": "Czas zakończenia (UTC)", + "process.overview.table.id": "Identyfikator procesu", + "process.overview.table.name": "Nazwa", + "process.overview.table.start": "Czas rozpoczęcia (UTC)", + "process.overview.table.status": "Status", + "process.overview.table.user": "Użytkownik", + "process.overview.title": "Przegląd procesów", + "process.overview.breadcrumbs": "Przegląd procesów", + "process.overview.new": "Nowy", + "profile.breadcrumbs": "Zaktualizuj profil", + "profile.card.identify": "Dane", + "profile.card.security": "Bezpieczeństwo", + "profile.form.submit": "Zaktualizuj profil", + "profile.groups.head": "Posiadane uprawnienia do kolekcji", + "profile.head": "Zaktualizuj profil", + "profile.metadata.form.error.firstname.required": "Imię jest wymagane", + "profile.metadata.form.error.lastname.required": "Nazwisko jest wymagane", + "profile.metadata.form.label.email": "Adres e-mail", + "profile.metadata.form.label.firstname": "Imię", + "profile.metadata.form.label.language": "Język", + "profile.metadata.form.label.lastname": "Nazwisko", + "profile.metadata.form.label.phone": "Telefon kontaktowy", + "profile.metadata.form.notifications.success.content": "Zmiany w profilu zostały zapisane.", + "profile.metadata.form.notifications.success.title": "Profil zapisany", + "profile.notifications.warning.no-changes.content": "Nie dokonano żadnych zmian w profilu.", + "profile.notifications.warning.no-changes.title": "Brak zmian", + "profile.security.form.error.matching-passwords": "Hasła nie są identyczne.", + "profile.security.form.info": "Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", + "profile.security.form.label.password": "Hasło", + "profile.security.form.label.passwordrepeat": "Potwierdź hasło", + "profile.security.form.notifications.success.content": "Twoje zmiany w haśle zostały zapisane.", + "profile.security.form.notifications.success.title": "Hasło zapisane", + "profile.security.form.notifications.error.title": "Błąd podczas próby zmiany hasła", + "profile.security.form.notifications.error.not-same": "Hasła nie są identyczne.", + "profile.title": "Zaktualizuj profil", + "profile.card.researcher": "Profil naukowca", + "project.listelement.badge": "Projekt badawczy", + "project.page.contributor": "Autorzy", + "project.page.description": "Opis", + "project.page.edit": "Edytuj pozycję", + "project.page.expectedcompletion": "Spodziewany termin zakończenia", + "project.page.funder": "Instytucje finansujące", + "project.page.id": "ID", + "project.page.keyword": "Słowa kluczowe", + "project.page.status": "Status", + "project.page.titleprefix": "Projekt badawczy: ", + "project.search.results.head": "Wyniki wyszukiwania projektów", + "publication.listelement.badge": "Publikacja", + "publication.page.description": "Opis", + "publication.page.edit": "Edytuj pozycję", + "publication.page.journal-issn": "ISSN czasopisma", + "publication.page.journal-title": "Tytuł czasopisma", + "publication.page.publisher": "Wydawca", + "publication.page.titleprefix": "Publikacja: ", + "publication.page.volume-title": "Tytuł tomu", + "publication.search.results.head": "Wyniki wyszukiwania publikacji", + "publication.search.title": "Wyszukiwanie publikacji", + "media-viewer.next": "Nowy", + "media-viewer.previous": "Poprzedni", + "media-viewer.playlist": "Playlista", + "register-email.title": "Rejestracja nowego użytkownika", + "register-page.create-profile.header": "Stwórz profil", + "register-page.create-profile.identification.header": "Dane", + "register-page.create-profile.identification.email": "Adres e-mail", + "register-page.create-profile.identification.first-name": "Imię *", + "register-page.create-profile.identification.first-name.error": "Wpisz imię", + "register-page.create-profile.identification.last-name": "Nazwisko *", + "register-page.create-profile.identification.last-name.error": "Wpisz nazwisko", + "register-page.create-profile.identification.contact": "Telefon kontaktowy", + "register-page.create-profile.identification.language": "Język", + "register-page.create-profile.security.header": "Bezpieczeństwo", + "register-page.create-profile.security.info": "Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", + "register-page.create-profile.security.label.password": "Hasło *", + "register-page.create-profile.security.label.passwordrepeat": "Potwierdź hasło *", + "register-page.create-profile.security.error.empty-password": "Wprowadź hasło w polu poniżej.", + "register-page.create-profile.security.error.matching-passwords": "Hasła nie są identyczne.", + "register-page.create-profile.submit": "Rejestracja zakończona", + "register-page.create-profile.submit.error.content": "Coś się nie udało podczas rejestracji nowego użytkownika.", + "register-page.create-profile.submit.error.head": "Rejestracja nie powiodła się", + "register-page.create-profile.submit.success.content": "Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", + "register-page.create-profile.submit.success.head": "Rejestracja zakończona", + "register-page.registration.header": "Rejestracja nowego użytkownika", + "register-page.registration.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "register-page.registration.email": "Adres e-mail *", + "register-page.registration.email.error.required": "Wypełnij adres e-mail", + "register-page.registration.email.error.pattern": "Wypełnij poprawny adres e-mail", + "register-page.registration.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "register-page.registration.submit": "Zarejestruj się", + "register-page.registration.success.head": "Wiadomość weryfikacyjna zostałą wysłana", + "register-page.registration.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "register-page.registration.error.head": "Błąd podczas próby rejestracji adresu e-mail", + "register-page.registration.error.content": "Błąd podczas próby rejestracji adresu e-mail: {{ email }}", + "relationships.add.error.relationship-type.content": "Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", + "relationships.add.error.server.content": "Błąd serwera", + "relationships.add.error.title": "Nie można dodać relacji", + "relationships.isAuthorOf": "Autorzy", + "relationships.isAuthorOf.Person": "Autorzy (osoby)", + "relationships.isAuthorOf.OrgUnit": "Autorzy (jednostki organizacyjne)", + "relationships.isIssueOf": "Numery czasopisma", + "relationships.isJournalIssueOf": "Numer czasopisma", + "relationships.isJournalOf": "Czasopisma", + "relationships.isOrgUnitOf": "Jednostki organizacyjne", + "relationships.isPersonOf": "Autorzy", + "relationships.isProjectOf": "Projekty badawcze", + "relationships.isPublicationOf": "Publikacje", + "relationships.isPublicationOfJournalIssue": "Artykuły", + "relationships.isSingleJournalOf": "Czasopismo", + "relationships.isSingleVolumeOf": "Tom czasopisma", + "relationships.isVolumeOf": "Tomy czasopisma", + "relationships.isContributorOf": "Autorzy", + "relationships.isContributorOf.OrgUnit": "Autor (Jednostka organizacyjna)", + "relationships.isContributorOf.Person": "Autor", + "relationships.isFundingAgencyOf.OrgUnit": "Instytucja finansująca", + "repository.image.logo": "Logo repozytorium", + "repository.title.prefix": "DSpace Angular :: ", + "researcher.profile.action.processing": "Procesowanie...", + "researcher.profile.associated": "Przypisanie profilu badacza", + "researcher.profile.create.new": "Utwórz nowy", + "researcher.profile.create.success": "Profil badacza został utworzony", + "researcher.profile.create.fail": "Wystąpił błąd poczas tworzenia profilu badacza.", + "researcher.profile.delete": "Usuń", + "researcher.profile.expose": "Ujawnij", + "researcher.profile.hide": "Ukryj", + "researcher.profile.not.associated": "Profil badacza nie został jeszcze przypisany", + "researcher.profile.view": "Widok", + "researcher.profile.private.visibility": "PRYWATNY", + "researcher.profile.public.visibility": "PUBLICZNY", + "researcher.profile.status": "Status:", + "researcherprofile.claim.not-authorized": "Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", + "researcherprofile.error.claim.body": "Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", + "researcherprofile.error.claim.title": "Błąd", + "researcherprofile.success.claim.body": "Wystąpienie z prośbą o przypisanie profilu udane", + "researcherprofile.success.claim.title": "Sukces", + "repository.title.prefixDSpace": "DSpace Angular ::", + "resource-policies.add.button": "Dodaj", + "resource-policies.add.for.": "Dodaj nową politykę", + "resource-policies.add.for.bitstream": "Dodaj nową politykę dla plików", + "resource-policies.add.for.bundle": "Dodaj nową politykę paczek", + "resource-policies.add.for.item": "Dodaj nową politykę pozycji", + "resource-policies.add.for.community": "Dodaj nową politykę zbioru", + "resource-policies.add.for.collection": "Dodaj nową politykę kolekcji", + "resource-policies.create.page.heading": "Utwórz nową politykę zasobu dla ", + "resource-policies.create.page.failure.content": "Wystąpił błąd podczas dodawania polityki zasobów.", + "resource-policies.create.page.success.content": "Działanie powiodło się", + "resource-policies.create.page.title": "Utwórz nową politykę zasobu", + "resource-policies.delete.btn": "Usuń zaznaczone", + "resource-policies.delete.btn.title": "Usuń zaznaczone polityki zasobów", + "resource-policies.delete.failure.content": "Wystąpił błąd podczas usuwania wybranych polityk zasobów.", + "resource-policies.delete.success.content": "Działanie powiodło się", + "resource-policies.edit.page.heading": "Edytuj politykę zasobu ", + "resource-policies.edit.page.failure.content": "Wystąpił błąd poczas edytowania polityki zasobu.", + "resource-policies.edit.page.success.content": "Działanie udało się", + "resource-policies.edit.page.title": "Edytuj politykę zasobu", + "resource-policies.form.action-type.label": "Wybierz ten typ akcji", + "resource-policies.form.action-type.required": "Musisz wybrać akcję polityki zasobu.", + "resource-policies.form.eperson-group-list.label": "Użytkownik lub grupa, która otrzyma uprawnienia.", + "resource-policies.form.eperson-group-list.select.btn": "Wybierz", + "resource-policies.form.eperson-group-list.tab.eperson": "Wyszukaj użytkownika", + "resource-policies.form.eperson-group-list.tab.group": "Wyszukaj grupę", + "resource-policies.form.eperson-group-list.table.headers.action": "Akcja", + "resource-policies.form.eperson-group-list.table.headers.id": "ID", + "resource-policies.form.eperson-group-list.table.headers.name": "Nazwa", + "resource-policies.form.date.end.label": "Data zakończenia", + "resource-policies.form.date.start.label": "Data rozpoczęcia", + "resource-policies.form.description.label": "Opis", + "resource-policies.form.name.label": "Nazwa", + "resource-policies.form.policy-type.label": "Wybierz typ polityki", + "resource-policies.form.policy-type.required": "Musisz wybrać typ polityki zasobu.", + "resource-policies.table.headers.action": "Akcja", + "resource-policies.table.headers.date.end": "Data zakończenia", + "resource-policies.table.headers.date.start": "Data rozpoczęcia", + "resource-policies.table.headers.edit": "Edytuj", + "resource-policies.table.headers.edit.group": "Edytuj grupę", + "resource-policies.table.headers.edit.policy": "Edytuj politykę", + "resource-policies.table.headers.eperson": "Użytkownik", + "resource-policies.table.headers.group": "Grupa", + "resource-policies.table.headers.id": "ID", + "resource-policies.table.headers.name": "Nazwa", + "resource-policies.table.headers.policyType": "typ", + "resource-policies.table.headers.title.for.bitstream": "Polityki dla plików", + "resource-policies.table.headers.title.for.bundle": "Polityki dla paczek", + "resource-policies.table.headers.title.for.item": "Polityki dla pozycji", + "resource-policies.table.headers.title.for.community": "Polityki dla zbioru", + "resource-policies.table.headers.title.for.collection": "Polityki dla kolekcji", + "search.description": "", + "search.switch-configuration.title": "Pokaż", + "search.title": "Szukaj", + "search.breadcrumbs": "Szukaj", + "search.search-form.placeholder": "Szukaj w repozytorium...", + "search.filters.applied.f.author": "Autor", + "search.filters.applied.f.dateIssued.max": "Data zakończenia", + "search.filters.applied.f.dateIssued.min": "Data rozpoczęcia", + "search.filters.applied.f.dateSubmitted": "Data zgłoszenia", + "search.filters.applied.f.discoverable": "Ukryty", + "search.filters.applied.f.entityType": "Typ pozycji", + "search.filters.applied.f.has_content_in_original_bundle": "Ma przypisane pliki", + "search.filters.applied.f.itemtype": "Typ", + "search.filters.applied.f.namedresourcetype": "Status", + "search.filters.applied.f.subject": "Temat", + "search.filters.applied.f.submitter": "Zgłaszający", + "search.filters.applied.f.jobTitle": "Stanowisko", + "search.filters.applied.f.birthDate.max": "Data zakończenia tworzenia", + "search.filters.applied.f.birthDate.min": "Data rozpoczęcia tworzenia", + "search.filters.applied.f.withdrawn": "Wycofane", + "search.filters.filter.author.head": "Autor", + "search.filters.filter.author.placeholder": "Autor", + "search.filters.filter.author.label": "Wyszukaj autora", + "search.filters.filter.birthDate.head": "Data urodzenia", + "search.filters.filter.birthDate.placeholder": "Data urodzenia", + "search.filters.filter.birthDate.label": "Wyszukaj datę urodzenia", + "search.filters.filter.collapse": "Ukryj filtr", + "search.filters.filter.creativeDatePublished.head": "Data opublikowania", + "search.filters.filter.creativeDatePublished.placeholder": "Data opublikowania", + "search.filters.filter.creativeDatePublished.label": "Wyszukaj datę opublikowania", + "search.filters.filter.creativeWorkEditor.head": "Redaktor", + "search.filters.filter.creativeWorkEditor.placeholder": "Redaktor", + "search.filters.filter.creativeWorkEditor.label": "Wyszukaj redaktora", + "search.filters.filter.creativeWorkKeywords.head": "Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.placeholder": "Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.label": "Wyszukaj temat", + "search.filters.filter.creativeWorkPublisher.head": "Wydawca", + "search.filters.filter.creativeWorkPublisher.placeholder": "Wydawca", + "search.filters.filter.creativeWorkPublisher.label": "Wyszukaj wydawcę", + "search.filters.filter.dateIssued.head": "Data", + "search.filters.filter.dateIssued.max.placeholder": "Data maksymalna", + "search.filters.filter.dateIssued.max.label": "Koniec", + "search.filters.filter.dateIssued.min.placeholder": "Data minimalna", + "search.filters.filter.dateIssued.min.label": "Start", + "search.filters.filter.dateSubmitted.head": "Data zgłoszenia", + "search.filters.filter.dateSubmitted.placeholder": "Data zgłoszenia", + "search.filters.filter.dateSubmitted.label": "Wyszukaj datę zgłoszenia", + "search.filters.filter.discoverable.head": "Ukryty", + "search.filters.filter.withdrawn.head": "Wycofane", + "search.filters.filter.entityType.head": "Typ pozycji", + "search.filters.filter.entityType.placeholder": "Typ pozycji", + "search.filters.filter.entityType.label": "Wyszukaj typ pozycji", + "search.filters.filter.expand": "Rozwiń filtr", + "search.filters.filter.has_content_in_original_bundle.head": "Ma przypisane pliki", + "search.filters.filter.itemtype.head": "Typ", + "search.filters.filter.itemtype.placeholder": "Typ", + "search.filters.filter.itemtype.label": "Wyszukaj typ", + "search.filters.filter.jobTitle.head": "Stanowisko", + "search.filters.filter.jobTitle.placeholder": "Stanowisko", + "search.filters.filter.jobTitle.label": "Wyszukaj stanowisko", + "search.filters.filter.knowsLanguage.head": "Znajomość języka", + "search.filters.filter.knowsLanguage.placeholder": "Znajomość języka", + "search.filters.filter.knowsLanguage.label": "Wyszukaj wg znajomości języka", + "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.namedresourcetype.label": "Wyszukaj status", + "search.filters.filter.objectpeople.head": "Osoby", + "search.filters.filter.objectpeople.placeholder": "Osoby", + "search.filters.filter.objectpeople.label": "Wyszukaj użytkowników", + "search.filters.filter.organizationAddressCountry.head": "Kraj", + "search.filters.filter.organizationAddressCountry.placeholder": "Kraj", + "search.filters.filter.organizationAddressCountry.label": "Wyszukaj kraj", + "search.filters.filter.organizationAddressLocality.head": "Miasto", + "search.filters.filter.organizationAddressLocality.placeholder": "Miasto", + "search.filters.filter.organizationAddressLocality.label": "Wyszukaj miasto", + "search.filters.filter.organizationFoundingDate.head": "Data założenia", + "search.filters.filter.organizationFoundingDate.placeholder": "Data założenia", + "search.filters.filter.organizationFoundingDate.label": "Wyszukaj datę założenia", + "search.filters.filter.scope.head": "Zakres", + "search.filters.filter.scope.placeholder": "Filtr zakresu", + "search.filters.filter.scope.label": "Wyszukaj filtr zakresu", + "search.filters.filter.show-less": "Pokaż mniej", + "search.filters.filter.show-more": "Pokaż więcej", + "search.filters.filter.subject.head": "Temat", + "search.filters.filter.subject.placeholder": "Temat", + "search.filters.filter.subject.label": "Wyszukaj temat", + "search.filters.filter.submitter.head": "Zgłaszający", + "search.filters.filter.submitter.placeholder": "Zgłaszający", + "search.filters.filter.submitter.label": "Wyszukaj zgłaszającego", + "search.filters.entityType.JournalIssue": "Numer czasopisma", + "search.filters.entityType.JournalVolume": "Tom czasopisma", + "search.filters.entityType.OrgUnit": "Jednostka organizacyjna", + "search.filters.has_content_in_original_bundle.true": "Tak", + "search.filters.has_content_in_original_bundle.false": "Nie", + "search.filters.discoverable.true": "Nie", + "search.filters.discoverable.false": "Tak", + "search.filters.withdrawn.true": "Tak", + "search.filters.withdrawn.false": "Nie", + "search.filters.head": "Filtry", + "search.filters.reset": "Resetuj filtry", + "search.filters.search.submit": "Zastosuj", + "search.form.search": "Wyszukaj", + "search.form.search_dspace": "W repozytorium", + "search.form.scope.all": "W całym DSpace", + "search.results.head": "Wyniki wyszukiwania", + "default.search.results.head": "Wyniki wyszukiwania", + "search.results.no-results": "Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", + "search.results.no-results-link": "fraz podobnych do Twojego wyszukiwania", + "search.results.empty": "Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", + "search.sidebar.close": "Wróć do wyników wyszukiwania", + "search.sidebar.filters.title": "Filtry", + "search.sidebar.open": "Narzędzia wyszukiwania", + "search.sidebar.results": "wyniki", + "search.sidebar.settings.rpp": "Wyników na stronie", + "search.sidebar.settings.sort-by": "Sortuj według", + "search.sidebar.settings.title": "Ustawienia", + "search.view-switch.show-detail": "Wyświetl widok szczegółowy", + "search.view-switch.show-grid": "Wyświetl jako siatkę", + "search.view-switch.show-list": "Wyświetl jako listę", + "sorting.ASC": "Rosnąco", + "sorting.DESC": "Malejąco", + "sorting.dc.title.ASC": "Tytułami rosnąco", + "sorting.dc.title.DESC": "Tytułami malejąco", + "sorting.score.ASC": "Najmniej trafne", + "sorting.score.DESC": "Najbardziej trafne", + "sorting.dc.date.issued.ASC": "Data wydania rosnąco", + "sorting.dc.date.issued.DESC": "Data wydania malejąco", + "sorting.dc.date.accessioned.ASC": "Data dostępu rosnąco", + "sorting.dc.date.accessioned.DESC": "Data dostępu malejąco", + "sorting.lastModified.ASC": "Ostatnia modyfikacja rosnąco", + "sorting.lastModified.DESC": "Ostatnia modyfikacja malejąco", + "statistics.title": "Statystyki", + "statistics.header": "Statystyki dla {{ scope }}", + "statistics.breadcrumbs": "Statystyki", + "statistics.page.no-data": "Brak dostępnych danych", + "statistics.table.no-data": "Brak dostępnych danych", + "statistics.table.header.views": "Wyświetlenia", + "submission.edit.breadcrumbs": "Edytuj zgłoszenie", + "submission.edit.title": "Edytuj zgłoszenie", + "submission.general.cancel": "Anuluj", + "submission.general.cannot_submit": "Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", + "submission.general.deposit": "Deponuj", + "submission.general.discard.confirm.cancel": "Anuluj", + "submission.general.discard.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.general.discard.confirm.submit": "Tak, na pewno", + "submission.general.discard.confirm.title": "Odrzuć zgłoszenie", + "submission.general.discard.submit": "Odrzuć", + "submission.general.info.saved": "Zapisane", + "submission.general.info.pending-changes": "Niezapisane zmiany", + "submission.general.save": "Zapisz", + "submission.general.save-later": "Zapisz wersję roboczą", + "submission.import-external.page.title": "Importuj metdane z zewnętrznego źródła", + "submission.import-external.title": "Importuj metadane z zewnętrznego źródła", + "submission.import-external.title.Journal": "Importuj czasopismo z zewnętrznego źródła", + "submission.import-external.title.JournalIssue": "Importuj numer czasopisma z zewnętrznego źródła", + "submission.import-external.title.JournalVolume": "Importuj tom czasopisma z zewnętrznego źródła", + "submission.import-external.title.OrgUnit": "Importuj wydawcę z zewnętrznego źródła", + "submission.import-external.title.Person": "Importuj osobę z zewnętrznego źródła", + "submission.import-external.title.Project": "Importuj projekt z zewnętrznego źródła", + "submission.import-external.title.Publication": "Importuj publikację z zewnętrznego źródła", + "submission.import-external.title.none": "Importuj metadane z zewnętrznego źródła", + "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", + "submission.import-external.back-to-my-dspace": "Powrót do MyDSpace", + "submission.import-external.search.placeholder": "Wyszukaj zewnętrzne źródła danych", + "submission.import-external.search.button": "Szukaj", + "submission.import-external.search.button.hint": "Zacznij wpisywać frazę, aby wyszukać", + "submission.import-external.search.source.hint": "Wybierz zewnętrzne źródło", + "submission.import-external.source.ads": "NASA/ADS", + "submission.import-external.source.arxiv": "arXiv", + "submission.import-external.source.cinii": "CiNii", + "submission.import-external.source.crossref": "CrossRef", + "submission.import-external.source.loading": "ładowanie...", + "submission.import-external.source.sherpaJournal": "Czasopisma w SHERPA", + "submission.import-external.source.sherpaJournalIssn": "Czasopisma w SHERPA wg ISSN", + "submission.import-external.source.sherpaPublisher": "Wydawcy w SHERPA", + "submission.import-external.source.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.import-external.source.orcid": "ORCID", + "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.pubmed": "Pubmed", + "submission.import-external.source.pubmedeu": "Pubmed Europe", + "submission.import-external.source.lcname": "Nazwy Biblioteki Kongresu", + "submission.import-external.source.scielo": "SciELO", + "submission.import-external.source.scopus": "Scopus", + "submission.import-external.source.vufind": "VuFind", + "submission.import-external.source.wos": "Web Of Science", + "submission.import-external.source.epo": "Europejski Urząd Patentowy (EPO)", + "submission.import-external.preview.title.Journal": "Podgląd czasopisma", + "submission.import-external.preview.title.OrgUnit": "Podgląd organizacji", + "submission.import-external.preview.title.Person": "Podgląd osoby", + "submission.import-external.preview.title.Project": "Podgląd projektu", + "submission.import-external.preview.title.Publication": "Podgląd publikacji", + "submission.import-external.preview.subtitle": "Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", + "submission.import-external.preview.button.import": "Rozpocznij zgłoszenie", + "submission.import-external.preview.error.import.title": "Błąd zgłoszenia", + "submission.import-external.preview.error.import.body": "Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", + "submission.sections.describe.relationship-lookup.close": "Zamknij", + "submission.sections.describe.relationship-lookup.external-source.added": "Udało się dodać wpis do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importuj zdalny tom czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Nowy typ danych dodany!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Importuj zdalną osobę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Importuj zdalny produkt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importuj zdalną aparaturę badawczą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Importuj zdalne wydarzenie", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Importuj zdalną instytucję finansującą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importuj zdalnego wydawcę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Importuj zdalnie patent", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Importuj zdalnie projekt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Importuj zdalnie publikację", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Udało się dodać autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Udało się zaimportować i dodać zewnętrznego autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Nadrzędność", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Importuj jako nową, lokalną, nadrzędną pozycję", + "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Anuluj", + "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Wybierz kolekcję do zaimportowania nowych pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Importuj jako nowy lokalny typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Importuj z LC Name", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Importuj z ORCID", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Importuj z Sherpa Journal", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Importuj z Sherpa Publisher", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Importuj z PubMed", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Importuj z arXiv", + "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Import", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Successfully added local journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Successfully imported and added external journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Udało się dodać lokalne czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Udało się dodać lokalny numer czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Wybierz lokalne powiązanie:", + "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Odznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Odznacz stronę", + "submission.sections.describe.relationship-lookup.search-tab.loading": "Ładowanie...", + "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Wyszukaj zapytanie", + "submission.sections.describe.relationship-lookup.search-tab.search": "Zastosuj", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Wyszukaj...", + "submission.sections.describe.relationship-lookup.search-tab.select-all": "Zaznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.select-page": "Zaznacz stronę", + "submission.sections.describe.relationship-lookup.selected": "Zaznacz {{ size }} pozycji", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Czasopisma lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Projekty lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Publikacje lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Lokalne jednostki organizacyjne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Lokalne paczki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Lokalne pliki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Lokalne czasopisma ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa Publishers ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC Names ({{ 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": "Wyszukaj instytucje finansujące", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Wyszukaj finansowanie", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Wyszukaj jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projekty", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekt", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projekty", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Wyszukaj...", + "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Aktualne zaznaczenie ({{ count }})", + "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalIssue": "Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalVolume": "Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Czasopisma", + "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Autorzy", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.Project": "Projekty", + "submission.sections.describe.relationship-lookup.title.Publication": "Publikacje", + "submission.sections.describe.relationship-lookup.title.Person": "Autorzy", + "submission.sections.describe.relationship-lookup.title.OrgUnit": "Jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.title.DataPackage": "Paczki danych", + "submission.sections.describe.relationship-lookup.title.DataFile": "Pliki danych", + "submission.sections.describe.relationship-lookup.title.Funding Agency": "Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Finansowanie", + "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Nadrzędna jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Przełącz na listę rozwijaną", + "submission.sections.describe.relationship-lookup.selection-tab.settings": "Ustawienia", + "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Twoje zaznaczenie jest puste.", + "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Wybrane tomy czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Wybrane projekty", + "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Wybrane publikacje", + "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Wybrane jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Wybrane pakiety danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Wybrane pliki danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Wybrany tom czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Wybrane instytucje finansujące", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Wybrane finansowanie", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Wybrana jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", + "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Zapisz nowy wariant imienia", + "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Użyj tylko w tym zgłoszeniu", + "submission.sections.ccLicense.type": "Typ licencji", + "submission.sections.ccLicense.select": "Wybierz typ licencji…", + "submission.sections.ccLicense.change": "Zmień typ licencji…", + "submission.sections.ccLicense.none": "Brak dostępnych licencji", + "submission.sections.ccLicense.option.select": "Wybierz opcję…", + "submission.sections.ccLicense.link": "Wybrano licencję:", + "submission.sections.ccLicense.confirmation": "Udzielam powyższej licencji", + "submission.sections.general.add-more": "Dodaj więcej", + "submission.sections.general.collection": "Kolekcja", + "submission.sections.general.deposit_error_notice": "Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", + "submission.sections.general.deposit_success_notice": "Udało się wprowadzić pozycję.", + "submission.sections.general.discard_error_notice": "Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", + "submission.sections.general.discard_success_notice": "Udało się odrzucić pozycję.", + "submission.sections.general.metadata-extracted": "Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", + "submission.sections.general.metadata-extracted-new-section": "Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", + "submission.sections.general.no-collection": "Nie znaleziono kolekcji", + "submission.sections.general.no-sections": "Opcje niedostępne", + "submission.sections.general.save_error_notice": "Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", + "submission.sections.general.save_success_notice": "Udało się zapisać zgłoszenie.", + "submission.sections.general.search-collection": "Szukaj kolekcji", + "submission.sections.general.sections_not_valid": "Niektóre sekcje są niekompletne.", + "submission.sections.submit.progressbar.CClicense": "Licencja Creative Commons", + "submission.sections.submit.progressbar.describe.recycle": "Odzyskaj", + "submission.sections.submit.progressbar.describe.stepcustom": "Opisz", + "submission.sections.submit.progressbar.describe.stepone": "Opisz", + "submission.sections.submit.progressbar.describe.steptwo": "Opisz", + "submission.sections.submit.progressbar.detect-duplicate": "Potencjalne duplikaty", + "submission.sections.submit.progressbar.license": "Zdeponuj licencję", + "submission.sections.submit.progressbar.upload": "Prześlij pliki", + "submission.sections.status.errors.title": "Błędy", + "submission.sections.status.valid.title": "Poprawność", + "submission.sections.status.warnings.title": "Ostrzeżenia", + "submission.sections.status.errors.aria": "ma błędy", + "submission.sections.status.valid.aria": "jest poprawne", + "submission.sections.status.warnings.aria": "ma ostrzeżenia", + "submission.sections.toggle.open": "Otwórz sekcję", + "submission.sections.toggle.close": "Zamknij sekcję", + "submission.sections.toggle.aria.open": "Rozwiń sekcję {{sectionHeader}}", + "submission.sections.toggle.aria.close": "Zwiń sekcję {{sectionHeader}}", + "submission.sections.upload.delete.confirm.cancel": "Anuluj", + "submission.sections.upload.delete.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.sections.upload.delete.confirm.submit": "Tak, na pewno", + "submission.sections.upload.delete.confirm.title": "Usuń plik", + "submission.sections.upload.delete.submit": "Usuń", + "submission.sections.upload.download.title": "Pobierz plik", + "submission.sections.upload.drop-message": "Upuść pliki, aby załączyć je do tej pozycji", + "submission.sections.upload.edit.title": "Edytuj plik", + "submission.sections.upload.form.access-condition-label": "Typ dostępu", + "submission.sections.upload.form.date-required": "Data jest wymagana.", + "submission.sections.upload.form.date-required-from": "Data przyznania dostępu od jest wymagana.", + "submission.sections.upload.form.date-required-until": "Data przyznania dostępu do jest wymagana.", + "submission.sections.upload.form.from-label": "Pozwól na dostęp od", + "submission.sections.upload.form.from-placeholder": "Od", + "submission.sections.upload.form.group-label": "Grupa", + "submission.sections.upload.form.group-required": "Grupa jest wymagana", + "submission.sections.upload.form.until-label": "Pozwól na dostęp do", + "submission.sections.upload.form.until-placeholder": "Do", + "submission.sections.upload.header.policy.default.nolist": "Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", + "submission.sections.upload.header.policy.default.withlist": "Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", + "submission.sections.upload.info": "Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", + "submission.sections.upload.no-entry": "Nie", + "submission.sections.upload.no-file-uploaded": "Pliki nie zostały jeszcze wgrane.", + "submission.sections.upload.save-metadata": "Zapisz metadane", + "submission.sections.upload.undo": "Anuluj", + "submission.sections.upload.upload-failed": "Przesyłanie nieudane", + "submission.sections.upload.upload-successful": "Przesyłanie udane", + "submission.submit.breadcrumbs": "Nowe zgłoszenie", + "submission.submit.title": "Nowe zgłoszenie", + "submission.workflow.generic.delete": "Usuń", + "submission.workflow.generic.delete-help": "Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", + "submission.workflow.generic.edit": "Edytuj", + "submission.workflow.generic.edit-help": "Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.generic.view": "Podgląd", + "submission.workflow.generic.view-help": "Wybierz tę opcję, aby wyświetlić metadane pozycji.", + "submission.workflow.tasks.claimed.approve": "Zatwierdź", + "submission.workflow.tasks.claimed.approve_help": "Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", + "submission.workflow.tasks.claimed.edit": "Edytuj", + "submission.workflow.tasks.claimed.edit_help": "Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.tasks.claimed.reject.reason.info": "Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Opisz powód odrzucenia zgłoszenia", + "submission.workflow.tasks.claimed.reject.reason.submit": "Odrzuć pozycję", + "submission.workflow.tasks.claimed.reject.reason.title": "Powód", + "submission.workflow.tasks.claimed.reject.submit": "Odrzuć", + "submission.workflow.tasks.claimed.reject_help": "Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", + "submission.workflow.tasks.claimed.return": "Cofnij do puli zadań", + "submission.workflow.tasks.claimed.return_help": "Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", + "submission.workflow.tasks.generic.error": "Podczas działania wystąpił błąd...", + "submission.workflow.tasks.generic.processing": "Procesowanie...", + "submission.workflow.tasks.generic.submitter": "Zgłaszający", + "submission.workflow.tasks.generic.success": "Udało się", + "submission.workflow.tasks.pool.claim": "Podejmij pracę", + "submission.workflow.tasks.pool.claim_help": "Przypisz to zadanie do siebie.", + "submission.workflow.tasks.pool.hide-detail": "Ukryj szczegóły", + "submission.workflow.tasks.pool.show-detail": "Pokaż szczegóły", + "thumbnail.default.alt": "Miniatura", + "thumbnail.default.placeholder": "Brak miniatury", + "thumbnail.project.alt": "Logo projektu", + "thumbnail.project.placeholder": "Obraz zastępczy projketu", + "thumbnail.orgunit.alt": "Logo jednostki organizacyjnej", + "thumbnail.orgunit.placeholder": "Obraz zastępczy jednostki organizacyjnej", + "thumbnail.person.alt": "Zdjęcie profilowe", + "thumbnail.person.placeholder": "Brak zdjęcia profilowego", + "title": "DSpace", + "vocabulary-treeview.header": "Widok drzewka", + "vocabulary-treeview.load-more": "Pokaż więcej", + "vocabulary-treeview.search.form.reset": "Resetuj", + "vocabulary-treeview.search.form.search": "Szukaj", + "vocabulary-treeview.search.no-result": "Brak pozycji do wyświetlenia", + "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", + "vocabulary-treeview.tree.description.srsc": "Kategorie tematów badań", + "uploader.browse": "wyszukaj na swoim urządzeniu", + "uploader.drag-message": "Przeciągnij i upuść pliki tutaj", + "uploader.delete.btn-title": "Usuń", + "uploader.or": ", lub ", + "uploader.processing": "Procesowanie", + "uploader.queue-length": "Długość kolejki", + "virtual-metadata.delete-item.info": "Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "virtual-metadata.delete-item.modal-head": "Wirtualne metadane tego powiązania", + "virtual-metadata.delete-relationship.modal-head": "Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "workflowAdmin.search.results.head": "Zarządzaj procesami", + "workflow-item.edit.breadcrumbs": "Edytuj pozycję procesu", + "workflow-item.edit.title": "Edytuj pozycję procesu", + "workflow-item.delete.notification.success.title": "Usunięte", + "workflow-item.delete.notification.success.content": "Ten element procesu został usunięty", + "workflow-item.delete.notification.error.title": "Coś poszło nie tak", + "workflow-item.delete.notification.error.content": "Ten element procesu nie mógł zostać usunięty", + "workflow-item.delete.title": "Usuń element procesu", + "workflow-item.delete.header": "Usuń element procesu", + "workflow-item.delete.button.cancel": "Anuluj", + "workflow-item.delete.button.confirm": "Usuń", + "workflow-item.send-back.notification.success.title": "SOdeślij do zgłaszającego", + "workflow-item.send-back.notification.success.content": "Ten element procesu został odesłany do zgłaszającego", + "workflow-item.send-back.notification.error.title": "Coś poszło nie tak", + "workflow-item.send-back.notification.error.content": "Ten element procesu nie mógł zostać odesłany do zgłaszającego", + "workflow-item.send-back.title": "Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.header": "Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.button.cancel": "Anuluj", + "workflow-item.send-back.button.confirm": "Odeślij", + "workflow-item.view.breadcrumbs": "Widok procesu", + "idle-modal.header": "Sesja wkrótce wygaśnie", + "idle-modal.info": "Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", + "idle-modal.log-out": "Wyloguj", + "idle-modal.extend-session": "Wydłuż sesję", + "workspace.search.results.head": "Twoje zadania", + "orgunit.listelement.badge": "Jednostka organizacyjna", + "orgunit.page.city": "Miasto", + "orgunit.page.country": "Kraj", + "orgunit.page.dateestablished": "Data założenia", + "orgunit.page.description": "Opis", + "orgunit.page.edit": "Edytuj pozycję", + "orgunit.page.id": "ID", + "orgunit.page.titleprefix": "Jednostka organizacyjna: ", + "pagination.options.description": "Opcje strony", + "pagination.results-per-page": "Wyników na stronę", + "pagination.showing.detail": "{{ range }} z {{ total }}", + "pagination.showing.label": "Teraz wyświetlane ", + "pagination.sort-direction": "Opcje sortowania", + "cookies.consent.purpose.sharing": "Udostępnianie", + "item.preview.dc.identifier.issn": "ISSN", + "500.page-internal-server-error": "Usługa niedostępna", + "500.help": "Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", + "500.link.home-page": "Zabierz mnie na stronę główną", + "error-page.description.401": "brak autoryzacji", + "error-page.description.403": "brak dostępu", + "error-page.description.500": "usługa niedostępna", + "error-page.description.404": "nie znaleziono strony", + "error-page.orcid.generic-error": "Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", + "access-status.embargo.listelement.badge": "Embargo", + "access-status.metadata.only.listelement.badge": "Tylko metadane", + "access-status.open.access.listelement.badge": "Open Access", + "access-status.restricted.listelement.badge": "Brak dostępu", + "access-status.unknown.listelement.badge": "Nieznane", + "admin.access-control.groups.table.edit.buttons.remove": "Usuń \"{{name}}\"", + "admin.metadata-import.page.validateOnly": "Tylko waliduj", + "admin.metadata-import.page.validateOnly.hint": "Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", + "bitstream.edit.form.iiifLabel.label": "Etykieta canvyIIIF", + "bitstream.edit.form.iiifLabel.hint": "Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", + "bitstream.edit.form.iiifToc.label": "Spis treści IIIF", + "bitstream.edit.form.iiifToc.hint": "Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", + "bitstream.edit.form.iiifWidth.label": "Szerokość canvy IIIF", + "bitstream.edit.form.iiifWidth.hint": "Szerokość canvy jest zwykle równa szerokości obrazu.", + "bitstream.edit.form.iiifHeight.label": "Wysokość canvy IIIF", + "bitstream.edit.form.iiifHeight.hint": "Wysokość canvy jest zwykle równa szerokości obrazu.", + "browse.back.all-results": "Wszystkie wyniki wyszukiwania", + "pagination.next.button": "Następny", + "pagination.previous.button": "Poprzedni", + "pagination.next.button.disabled.tooltip": "Brak więcej stron z wynikami wyszukiwania", + "browse.startsWith": ", zaczyna się od {{ startsWith }}", + "browse.title.page": "Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", + "collection.edit.item.authorizations.load-bundle-button": "Załaduj więcej paczek", + "collection.edit.item.authorizations.load-more-button": "Załaduj więcej", + "collection.edit.item.authorizations.show-bitstreams-button": "Pokaż polityki plików dla paczek", + "comcol-role.edit.create.error.title": "Nie udało się utworzyć grupy dla roli '{{ role }}'", + "curation.form.submit.error.invalid-handle": "Nie ustalono identyfikatora dla tego obiektu", + "confirmation-modal.delete-profile.header": "Usuń profil", + "confirmation-modal.delete-profile.info": "Czy na pewno chcesz usunąć profil", + "confirmation-modal.delete-profile.cancel": "Anuluj", + "confirmation-modal.delete-profile.confirm": "Usuń", + "error.invalid-search-query": "Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", + "feed.description": "Aktualności", + "footer.link.feedback": "Prześlij uwagi", + "form.group-collapse": "Zwiń", + "form.group-collapse-help": "Kliknij tutaj, aby zwinąć", + "form.group-expand": "Rozwiń", + "form.group-expand-help": "Kliknij tutaj, aby rozwinąć", + "health.breadcrumbs": "Stan systemu", + "health-page.heading": "Stan systemu", + "health-page.info-tab": "Informacje", + "health-page.status-tab": "Status", + "health-page.error.msg": "Serwis stanu systemu jest tymczasowo niedostępny", + "health-page.property.status": "Kod statusu", + "health-page.section.db.title": "Baza danych", + "health-page.section.geoIp.title": "GeoIp", + "health-page.section.solrAuthorityCore.title": "Autentykacja", + "health-page.section.solrOaiCore.title": "OAI", + "health-page.section.solrSearchCore.title": "Wyszukiwarka", + "health-page.section.solrStatisticsCore.title": "Statystyki", + "health-page.section-info.app.title": "Backend aplikacji", + "health-page.section-info.java.title": "Java", + "health-page.status": "Status", + "health-page.status.ok.info": "operacyjny", + "health-page.status.error.info": "Wykryte problemy", + "health-page.status.warning.info": "Wykryte potencjalne problemy", + "health-page.title": "Stan systemu", + "health-page.section.no-issues": "Nie wykryto żadnych problemów", + "info.feedback.breadcrumbs": "Uwagi", + "info.feedback.head": "Uwagi", + "info.feedback.title": "Uwagi", + "info.feedback.info": "Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", + "info.feedback.email_help": "Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", + "info.feedback.send": "Prześlij uwagi", + "info.feedback.comments": "Komentarz", + "info.feedback.email-label": "Twoj adres e-mail", + "info.feedback.create.success": "Uwagi przesłane!", + "info.feedback.error.email.required": "Poprawny adres e-mail jest wymagany", + "info.feedback.error.message.required": "Treść komentarza jest wymagana", + "info.feedback.page-label": "Strona", + "info.feedback.page_help": "Ta strona odnosi się do uwag.", + "item.orcid.return": "Powrót", + "item.truncatable-part.show-more": "Pokaż więcej", + "item.truncatable-part.show-less": "Pokaż mniej", + "item.page.orcid.title": "ORCID", + "item.page.orcid.tooltip": "Otwórz ustawienia ORCID", + "item.page.claim.button": "Podejmij pracę", + "item.page.claim.tooltip": "Podejmij pracę jako profil", + "item.version.create.modal.submitted.header": "Tworzenie nowej wersji...", + "item.version.create.modal.submitted.text": "Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", + "journal-relationships.search.results.head": "Wyniki wyszukiwania czasopism", + "menu.section.icon.health": "Sekcja menu Stan systemu", + "menu.section.health": "Stan systemu", + "metadata-export-search.tooltip": "Eksportuj wyniki wyszukiwania w formacie CSV", + "metadata-export-search.submit.success": "Eksport rozpoczął się", + "metadata-export-search.submit.error": "Eksport nie rozpoczął się", + "person.page.name": "Nazwa", + "person-relationships.search.results.head": "Wyniki wyszukiwania osób", + "profile.special.groups.head": "Autoryzacja do specjalnych grup, do których należysz", + "project-relationships.search.results.head": "Wyniki wyszukiwania projektów", + "publication-relationships.search.results.head": "Wyniki wyszukiwania publikacji", + "resource-policies.edit.page.target-failure.content": "Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", + "resource-policies.edit.page.other-failure.content": "Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", + "resource-policies.form.eperson-group-list.modal.header": "Nie można zmienić typu", + "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Nie można zastąpić użytkownika grupą.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Nie można zastąpić grupy użytkownikiem.", + "resource-policies.form.eperson-group-list.modal.text2": "Usuń obecną polityke zasobu i stwórz nową o określonym typie.", + "resource-policies.form.eperson-group-list.modal.close": "Ok", + "search.results.view-result": "Widok", + "default-relationships.search.results.head": "Wyniki wyszukiwania", + "statistics.table.title.TotalVisits": "Wyświetlnia ogółem", + "statistics.table.title.TotalVisitsPerMonth": "Wyświetlenia w miesiącu", + "statistics.table.title.TotalDownloads": "Pobrania", + "statistics.table.title.TopCountries": "Wyświetlenia wg krajów", + "statistics.table.title.TopCities": "Wyświetlenia wg miast", + "submission.import-external.preview.title": "Podgląd pozycji", + "submission.import-external.preview.title.none": "Podgląd pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import pozycji zdalnie", + "submission.sections.general.cannot_deposit": "Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", + "submission.sections.submit.progressbar.accessCondition": "Warunki dostępu do pozycji", + "submission.sections.submit.progressbar.sherpapolicy": "Polityki Sherpa", + "submission.sections.submit.progressbar.sherpaPolicies": "Informacje o polityce open access wydawcy.", + "submission.sections.status.info.title": "Dodatkowe informacje", + "submission.sections.status.info.aria": "Dodatkowe informacje", + "submission.sections.upload.form.access-condition-hint": "Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", + "submission.sections.upload.form.from-hint": "Wybierz datę, od której ma zostać zastosowany warunek dostępu", + "submission.sections.upload.form.until-hint": "Wybierz datę, do której ma zostać zastosowany warunek dostępu", + "submission.sections.accesses.form.discoverable-description": "Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", + "submission.sections.accesses.form.discoverable-label": "Niemożliwe do wyszukania", + "submission.sections.accesses.form.access-condition-label": "Typ warunku dostępu", + "submission.sections.accesses.form.access-condition-hint": "Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", + "submission.sections.accesses.form.date-required": "Data jest wymagana.", + "submission.sections.accesses.form.date-required-from": "Początkowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.date-required-until": "Końcowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.from-label": "Udziel dostępu od", + "submission.sections.accesses.form.from-hint": "Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.from-placeholder": "Od", + "submission.sections.accesses.form.group-label": "Grupa", + "submission.sections.accesses.form.group-required": "Grupa jest wymagana.", + "submission.sections.accesses.form.until-label": "Udziel dostępu do", + "submission.sections.accesses.form.until-hint": "Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.until-placeholder": "Do", + "submission.sections.sherpa.publication.information": "Informacje o publikacji", + "submission.sections.sherpa.publication.information.title": "Tytuł", + "submission.sections.sherpa.publication.information.issns": "Numery ISSN", + "submission.sections.sherpa.publication.information.url": "URL", + "submission.sections.sherpa.publication.information.publishers": "Wydawca", + "submission.sections.sherpa.publication.information.romeoPub": "Wydawca Romeo", + "submission.sections.sherpa.publication.information.zetoPub": "Wydawca Zeto", + "submission.sections.sherpa.publisher.policy": "Polityka wydawnicza", + "submission.sections.sherpa.publisher.policy.description": "Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", + "submission.sections.sherpa.publisher.policy.openaccess": "Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", + "submission.sections.sherpa.publisher.policy.more.information": "Aby uzuyskać więcej informacji, kliknij tutaj:", + "submission.sections.sherpa.publisher.policy.version": "Wersja", + "submission.sections.sherpa.publisher.policy.embargo": "Embargo", + "submission.sections.sherpa.publisher.policy.noembargo": "Brak embargo", + "submission.sections.sherpa.publisher.policy.nolocation": "Brak", + "submission.sections.sherpa.publisher.policy.license": "Licencja", + "submission.sections.sherpa.publisher.policy.prerequisites": "Wymagania wstępne", + "submission.sections.sherpa.publisher.policy.location": "Lokalizacja", + "submission.sections.sherpa.publisher.policy.conditions": "Wymagania", + "submission.sections.sherpa.publisher.policy.refresh": "Odśwież", + "submission.sections.sherpa.record.information": "Informacje o rekordzie", + "submission.sections.sherpa.record.information.id": "ID", + "submission.sections.sherpa.record.information.date.created": "Data utworzenia", + "submission.sections.sherpa.record.information.date.modified": "Ostatnia modyfikacja", + "submission.sections.sherpa.record.information.uri": "URI", + "submission.sections.sherpa.error.message": "Wystąpił błąd podczas pobierania informacji z Sherpa", + "submission.workspace.generic.view": "Podgląd", + "submission.workspace.generic.view-help": "Wybierz tę opcje, aby zobaczyć metadane.", + "workflow.search.results.head": "Zadania na workflow", + "workspace-item.view.breadcrumbs": "Widok wersji roboczej", + "workspace-item.view.title": "Widok wersji roboczej", + "researcher.profile.change-visibility.fail": "Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", + "person.page.orcid.link.processing": "Łączenie profilu z ORCID...", + "person.page.orcid.link.error.message": "Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", + "person.page.orcid.sync-queue.table.header.type": "Typ", + "person.page.orcid.sync-queue.table.header.description": "Opis", + "person.page.orcid.sync-queue.table.header.action": "Akcja", + "person.page.orcid.sync-queue.tooltip.project": "Projekt", + "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Niewłaściwy dwuznakowy kod kraju ISO 3166", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Wymagana data publikacji to co najmniej rok po 1900", + "person.page.orcid.synchronization-mode-funding-message": "Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", + "person.page.orcid.synchronization-mode-publication-message": "Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", + "person.page.orcid.synchronization-mode-profile-message": "Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", + "person.orcid.sync.setting": "Ustawienia synchronizacji z ORCID", + "person.orcid.registry.queue": "Kolejka rejestru z ORCID", + "person.orcid.registry.auth": "Autoryzacje z ORCID", + "home.recent-submissions.head": "Najnowsze publikacje", + "submission.sections.sherpa-policy.title-empty": "Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", + "admin.batch-import.breadcrumbs": "Import zbiorczy", + "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", + "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", + "admin.batch-import.page.error.addFile": "Najpierw wybierz plik (ZIP)", + "admin.batch-import.page.header": "Import masowy", + "admin.batch-import.page.help": "Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", + "admin.batch-import.page.remove": "usuń", + "admin.batch-import.page.validateOnly.hint": "Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", + "collection.form.correctionSubmissionDefinition": "Wzór zgłoszenia do prośby o korektę", + "comcol-role.edit.delete.error.title": "Nie udało się usunąć roli '{{ role }}' dla grup", + "confirmation-modal.export-batch.header": "Eksport maasowy (ZIP) {{ dsoName }}", + "confirmation-modal.export-batch.info": "Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", + "dso-selector.export-batch.dspaceobject.head": "Eksport masowy (ZIP) z", + "menu.section.export_batch": "Eksport masowy (ZIP)", + "nav.user-profile-menu-and-logout": "Profil użytkownika i wylogowywanie", + "process.detail.actions": "Akcje", + "process.detail.delete.body": "Czy na pewno chcesz usunąć bieżący proces?", + "process.detail.delete.button": "Usuń proces", + "process.detail.delete.cancel": "Anuluj", + "process.detail.delete.confirm": "Usuń proces", + "process.detail.delete.error": "Nie udało się usunąć procesu", + "process.detail.delete.header": "Usuń proces", + "process.detail.delete.success": "Proces został usunięty.", + "admin.batch-import.title": "Masowy import", + "admin.metadata-import.page.button.select-collection": "Wybierz kolekcję", + "admin.registries.bitstream-formats.table.id": "ID", + "admin.registries.schema.fields.table.id": "ID", + "cookies.consent.app.description.google-recaptcha": "Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", + "cookies.consent.app.disable-all.description": "Przełącz, aby zaakceptować lub odrzucić wszystkie", + "cookies.consent.app.disable-all.title": "Akceptowacja lub odrzucenie wszystkich", + "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + "cookies.consent.content-modal.service": "usługa", + "cookies.consent.content-modal.services": "usługi", + "cookies.consent.content-notice.description.no-privacy": "Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", + "cookies.consent.content-notice.title": "Zgoda na ciasteczka", + "cookies.consent.ok": "Zgadzam się", + "cookies.consent.purpose.registration-password-recovery": "Rejestracja i odzyskiwanie hasła", + "cookies.consent.save": "Zapisz", + "curation-task.task.citationpage.label": "Generuj stronę z cytowaniem", + "dso-selector.import-batch.dspaceobject.head": "Import masowy z", + "orgunit.listelement.no-title": "Brak tytyłu", + "process.bulk.delete.error.body": "Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", + "process.bulk.delete.error.head": "Błąd podczas usuwania procesu", + "process.bulk.delete.success": "{{count}} proces/y został/y usunięte", + "process.overview.delete": "Usuń {{count}} proces/y", + "process.overview.delete.body": "Czy na pewno usunąć {{count}} proces/y?", + "process.overview.delete.clear": "Wyczyść selekcję procesów do usunięcia", + "process.overview.delete.header": "Usuń procesy", + "process.overview.delete.processing": "{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", + "process.overview.table.actions": "Akcje", + "profile.security.form.label.current-password": "Aktualne hasło", + "profile.security.form.notifications.error.change-failed": "Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", + "profile.security.form.notifications.error.general": "Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", + "register-page.registration.error.recaptcha": "Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", + "register-page.registration.google-recaptcha.must-accept-cookies": "Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", + "register-page.registration.google-recaptcha.notification.message.error": "Wystąpił błąd podczas weryfikacji reCaptcha", + "register-page.registration.google-recaptcha.notification.message.expired": "Weryfikacja wygasła. Zweryfikuj ponownie.", + "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + "register-page.registration.google-recaptcha.open-cookie-settings": "Otwórz ustawienia plików cookies", + "search.results.response.500": "Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", + "submission.sections.license.granted-label": "Potwierdzam akceptację powyższej licencji", + "submission.sections.license.notgranted": "Najpierw musisz zaakceptować licencję", + "submission.sections.license.required": "Najpierw musisz zaakceptować licencję", + "confirmation-modal.export-batch.confirm": "Eksportuj", + "confirmation-modal.export-batch.cancel": "Anuluj", + "admin.access-control.bulk-access.breadcrumbs": "Zbiorcza edycja dostępu do osiągnięć", + "administrativeBulkAccess.search.results.head": "Wyniki wyszukiwania", + "admin.access-control.bulk-access": "Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access.title": "Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access-browse.header": "Krok 1: Wybierz pozycje", + "admin.access-control.bulk-access-browse.search.header": "Wyszukaj", + "admin.access-control.bulk-access-browse.selected.header": "Obecny wybór({{number}})", + "admin.access-control.bulk-access-settings.header": "Krok 2: Działanie do wykonania", + "admin.access-control.groups.form.tooltip.editGroupPage": "Na tej stronie można edytować opcje grupy i przypisane do niej osoby. W górnej sekcji można edytować nazwę i opis grupy, chyba że jest to grupa administratorów dla zbioru i kolekcji. W tym przypadku nazwa i opis grupy są generowane automatycznie i nie można ich edytować. W kolejnych sekcjach można edytować przypisanie użytkowników do grupy. Szczegóły na [stronie](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Aby dodać lub usunąć użytkownika do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj paska wyszukiwania poniżej, aby wyszukać użytkowników (użyj listy rozwijanej po lewej stronie paska wyszukiwania, aby wybrać, czy chcesz wyszukiwać według imienia i nazwiska, czy według adresu e-mail). Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może mieć kilka stron: użyj strzałek pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Aby dodać lub usunąć podgrupę do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj wyszukiwarki poniżej, aby wyszukać użytkowników. Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może składać się z kilku stron: użyj przycisków pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.workflow.item.workspace": "Przestrzeń robocza", + "admin.workflow.item.policies": "Polityki", + "admin.workflow.item.supervision": "Recenzja", + "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", + "admin.metadata-import.page.error.addFileUrl": "Najpierw wpisz URL pliku!", + "admin.metadata-import.page.toggle.upload": "Prześlij", + "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.urlMsg": "Wpisz URL pliku ZIP, aby wykonać import masowy", + "advanced-workflow-action.rating.form.rating.label": "Ocena", + "advanced-workflow-action.rating.form.rating.error": "Ta pozycja musi zostać oceniona", + "advanced-workflow-action.rating.form.review.label": "Recenzja", + "advanced-workflow-action.rating.form.review.error": "Musisz wpisać tekst recenzji", + "advanced-workflow-action.rating.description": "Wybierz ocenę poniżej", + "advanced-workflow-action.rating.description-requiredDescription": "Wybierz ocenę poniżej i wpisz uzasadnienie", + "advanced-workflow-action.select-reviewer.description-single": "Wybierz recenzenta przed zdeponowaniem pozycji", + "advanced-workflow-action.select-reviewer.description-multiple": "Wybierz jednego lub więcej recenzentów przed zdeponowaniem pozycji", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "Użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Dodaj użytkownika", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Przeglądaj wszystko", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Aktualni użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadane", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "Adres e-mail (dokładny)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Wyszukaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nazwa", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Tożsamość", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Adres e-mail", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Usuń / Dodaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Usuń użytkownika z nazwę "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Dodano użytkownika o nazwie: "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Nie dodano użytkownika: "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Usunięto użytkownika: "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Nie usunięto użytkownika: "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodano użytkownika "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nie znaleziono żadnych użytkowników", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Recenzent nie jest wybrany.", + "bitstream.edit.notifications.error.primaryBitstream.title": "Wystąpił błąd podczas zapisu pliku.", + "browse.comcol.by.srsc": "Wg słów kluczowych", + "browse.metadata.srsc.breadcrumbs": "Przeglądaj wg słów kluczowych", + "browse.startsWith.input": "Filtr", + "browse.taxonomy.button": "Przeglądaj", + "search.browse.item-back": "Powrót do wyników wyszukiwania", + "claimed-approved-search-result-list-element.title": "Zaakceptowano", + "claimed-declined-search-result-list-element.title": "Odrzucono i przesłano do deponującego", + "claimed-declined-task-search-result-list-element.title": "Odrzucono i przesłano do recenzenta", + "collection.edit.tabs.access-control.head": "Dostępy", + "collection.edit.tabs.access-control.title": "Edycja kolekcji - dostępy", + "collection.listelement.badge": "Kolekcja", + "community.edit.tabs.access-control.head": "Dostępy", + "community.edit.tabs.access-control.title": "Edycja zbioru - dostępy", + "comcol-role.edit.scorereviewers.name": "Ocena recenzenta", + "comcol-role.edit.scorereviewers.description": "Recenzenci mogą oceniać zdeponowane pozycje, co określi, czy pozycja zostanie przyjęta lub odrzucona.", + "curation-task.task.register-doi.label": "Rejestracja DOI", + "dso.name.unnamed": "Bez nazwy", + "dso-selector.create.community.or-divider": "lub", + "dso-selector.set-scope.community.or-divider": "lub", + "dso-selector.results-could-not-be-retrieved": "Wystąpił błąd, proszę odświeżyć stronę", + "supervision-group-selector.header": "Wybór grupy recenzenckiej", + "supervision-group-selector.select.type-of-order.label": "Wybierz typ funkcji", + "supervision-group-selector.select.type-of-order.option.none": "BRAK", + "supervision-group-selector.select.type-of-order.option.editor": "REDAKTOR", + "supervision-group-selector.select.type-of-order.option.observer": "OBSERWATOR", + "supervision-group-selector.select.group.label": "Wybierz grupę", + "supervision-group-selector.button.cancel": "Anuluj", + "supervision-group-selector.button.save": "Zapisz", + "supervision-group-selector.select.type-of-order.error": "Wybierz typ funkcji", + "supervision-group-selector.select.group.error": "Wybierz grupę", + "supervision-group-selector.notification.create.success.title": "Grupa recenzencka został dodana dla grupy {{ name }}", + "supervision-group-selector.notification.create.failure.title": "Błąd", + "supervision-group-selector.notification.create.already-existing": "Funkcja recenzenta już jest przypisana do tej grupy", + "confirmation-modal.delete-subscription.header": "Usuń subksrypcje", + "confirmation-modal.delete-subscription.info": "Czy na pewno chcesz usunąć subskrypcję: "{{ dsoName }}"", + "confirmation-modal.delete-subscription.cancel": "Anuluj", + "confirmation-modal.delete-subscription.confirm": "Usuń", + "error.validation.metadata.name.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.name.max-length": "To pole nie może zawierać więcej niż 32 znaki", + "error.validation.metadata.namespace.max-length": "To pole nie może zawierać więcej niż 256 znaków", + "error.validation.metadata.element.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.element.max-length": "To pole nie może zawierać więcej niż 64 znaki", + "error.validation.metadata.qualifier.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji", + "error.validation.metadata.qualifier.max-length": "To pole nie może zawierać więcej niż 64 znaki", + "forgot-email.form.email.error.not-email-form": "Wpisz prawidłowy adres e-mail", + "form.other-information.email": "Adres e-mail", + "form.other-information.first-name": "Imię", + "form.other-information.insolr": "Solr Index", + "form.other-information.institution": "Instytucja", + "form.other-information.last-name": "Nazwisko", + "form.other-information.orcid": "ORCID", + "form.create": "Utwórz", + "info.end-user-agreement.hosting-country": "Stany Zjednoczone", + "item.edit.identifiers.doi.status.UNKNOWN": "Nieznane", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "W kolejce do rejestracji", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "W kolejce do rezerwacji", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Zarejestrowane", + "item.edit.identifiers.doi.status.IS_RESERVED": "Zarezerwowane", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Zarezerwowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Zarejestrowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "W kolejce do aktualizacji i rejestracji", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "Zakolejkowane do usunięcia", + "item.edit.identifiers.doi.status.DELETED": "Usunięte", + "item.edit.identifiers.doi.status.PENDING": "Oczekujące (niezarejestrowane)", + "item.edit.identifiers.doi.status.MINTED": "Rezerwowanie nazwy (niezarejestrowane)", + "item.edit.tabs.status.buttons.register-doi.label": "Zarejestruj nowe lub oczekujące DOI", + "item.edit.tabs.status.buttons.register-doi.button": "Rejestruj DOI...", + "item.edit.register-doi.header": "Zarejestruj nowe lub oczekujące DOI", + "item.edit.register-doi.description": "Zweryfikuj poniższe identyfikatory i metadane pozycji i rozpocznij rejestrację DOI lub anuluj", + "item.edit.register-doi.confirm": "Zatwierdź", + "item.edit.register-doi.cancel": "Anuluj", + "item.edit.register-doi.success": "DOI jest w kolejce do rejestracji.", + "item.edit.register-doi.error": "Wystąpił błąd poczas rejestracji DOI", + "item.edit.register-doi.to-update": "To DOI zostało zarezerwowane i będzie znajdować się w kolejce do rejestracji", + "item.edit.metadata.edit.buttons.confirm": "Zatwierdź", + "item.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", + "item.edit.metadata.edit.buttons.virtual": "To pole przechowuje wirutalne wartości metadanych, np. wartość pobraną z encji, z którą jest połączona ta pozycja. Dodaj lub usuń relację w zakładce 'Relacje' ", + "item.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidcji pól metadanych", + "item.edit.metadata.reset-order-button": "Cofnij zamianę kolejności", + "item.edit.curate.title": "Zarządzaj pozycją: {{item}}", + "item.edit.tabs.access-control.head": "Dostęp", + "item.edit.tabs.access-control.title": "Edycja pozycji - dostęp", + "workflow-item.search.result.delete-supervision.modal.header": "Usuń zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.info": "Czy na pewno usunąć zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.cancel": "Anuluj", + "workflow-item.search.result.delete-supervision.modal.confirm": "Usuń", + "workflow-item.search.result.notification.deleted.success": "Usunięto zadanie dla recenzenta "{{name}}"", + "workflow-item.search.result.notification.deleted.failure": "Nie usunięto zadania dla recenzenta "{{name}}"", + "workflow-item.search.result.list.element.supervised-by": "Recenzja:", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Usuń grupę recenzencką", + "item.preview.dc.subject": "Słowo kluczowe:", + "item.preview.dc.publisher": "Wydawca:", + "itemtemplate.edit.metadata.add-button": "Dodaj", + "itemtemplate.edit.metadata.discard-button": "Cofnij", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Zatwierdź", + "itemtemplate.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", + "itemtemplate.edit.metadata.edit.buttons.edit": "Edytuj", + "itemtemplate.edit.metadata.edit.buttons.remove": "Usuń", + "itemtemplate.edit.metadata.edit.buttons.undo": "Cofnij zmiany", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Nie edytuj", + "itemtemplate.edit.metadata.empty": "To pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby je wprowadzić.", + "itemtemplate.edit.metadata.headers.edit": "Edytuj", + "itemtemplate.edit.metadata.headers.field": "Pole", + "itemtemplate.edit.metadata.headers.language": "Język", + "itemtemplate.edit.metadata.headers.value": "Wartość", + "itemtemplate.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidowania pola metadanych", + "itemtemplate.edit.metadata.metadatafield.invalid": "Wybierz odpowiednie pole metadanych", + "itemtemplate.edit.metadata.notifications.discarded.content": "Twoje zmiany nie zostały zachowane. Aby spróbować wprowadzić je ponownie wybierz Cofnij", + "itemtemplate.edit.metadata.notifications.discarded.title": "Zmiany nie zostały zachowane", + "itemtemplate.edit.metadata.notifications.error.title": "Wystąpił błąd", + "itemtemplate.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Upewnij się, że wszystkie pola zostały wypełnione prawidłowo.", + "itemtemplate.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadan", + "itemtemplate.edit.metadata.notifications.outdated.content": "Wzór dla pozycji, na którą w tym momencie pracujesz, został zmodyfikowany przez innego użytkownika. Twoje zmiany zostały odrzucone, aby uniknąć konfliktów pomiędzy wersjami.", + "itemtemplate.edit.metadata.notifications.outdated.title": "Zmiany zostały odrzucone", + "itemtemplate.edit.metadata.notifications.saved.content": "Zmiany w metadanych wzoru pozycji zostały zapisane.", + "itemtemplate.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", + "itemtemplate.edit.metadata.reinstate-button": "Cofnij", + "itemtemplate.edit.metadata.reset-order-button": "Cofnij zmianę kolejności", + "itemtemplate.edit.metadata.save-button": "Zapisz", + "menu.section.access_control_bulk": "Zbiorowe zarządzanie dostępem", + "menu.section.browse_global_by_srsc": "Wg słów kluczowych", + "mydspace.show.supervisedWorkspace": "Pozycje recenzowane", + "mydspace.status.mydspaceArchived": "Opublikowano", + "mydspace.status.mydspaceValidation": "Walidacja", + "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redakctora", + "mydspace.status.mydspaceWorkflow": "Redakcja", + "mydspace.status.mydspaceWorkspace": "Przestrzeń robocza", + "nav.context-help-toggle": "Przełącz pomoc kontekstową", + "nav.search.button": "Wpisz wyszukiwaną frazę", + "nav.subscriptions": "Subksrypcje", + "process.new.notification.error.max-upload.content": "Plik jest większy niż maksymalny dozwolony rozmiar pliku", + "register-page.registration.email.error.not-email-form": "Wprowadź poprawny adres e-mail", + "register-page.registration.email.error.not-valid-domain": "Użyj adresu e-mail z domeny: {{ domains }}", + "register-page.registration.error.maildomain": "Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", + "register-page.registration.info.maildomain": "Konta mogą być założone dla adresów e-mail z domeną", + "repository.title": "Repozytorium DSpace" + "search.filters.applied.f.supervisedBy": "Recenzent" + "search.filters.filter.show-tree": "Przeglądaj {{ name }} strukturę recenzentów", + "search.filters.filter.supervisedBy.head": "Recenzent", + "search.filters.filter.supervisedBy.placeholder": "Recenzent", + "search.filters.filter.supervisedBy.label": "Wyszukaj recenzenta", + "statistics.table.no-name": "(nazwa obiektu nie może zostać załadowana)", + "submission.import-external.source.datacite": "DataCite", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publikacje autora", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publikacje", + "submission.sections.identifiers.info": "Te identyfikatory zostaną utworzone dla pozycji:", + "submission.sections.identifiers.no_handle": "Do tej pozycji nie zostały przypisane żadne Handle", + "submission.sections.identifiers.no_doi": "Do tej pozycji nie zostały przypisane żadne DOI", + "submission.sections.identifiers.handle_label": "Handle: ", + "submission.sections.identifiers.doi_label": "DOI: ", + "submission.sections.identifiers.otherIdentifiers_label": "Inne identyfikatory: ", + "submission.sections.submit.progressbar.identifiers": "Identyfikatory", + "submission.workflow.generic.submit_select_reviewer": "Wybierz recenzenta", + "submission.workflow.generic.submit_select_reviewer-help": "", + "submission.workflow.generic.submit_score": "Wynik", + "submission.workflow.generic.submit_score-help": "", + "submission.workflow.tasks.claimed.decline": "Odrzuć", + "submission.workflow.tasks.claimed.decline_help": "", + "submitter.empty": "n.d.", + "subscriptions.title": "Subskrypcje", + "subscriptions.item": "Subskrypcje pozycji", + "subscriptions.collection": "Subskrypcje kolekcji", + "subscriptions.community": "Subskrypcje zbiorów", + "subscriptions.subscription_type": "Typ subksrypcji", + "subscriptions.frequency": "Częstotliwość subskrypcji", + "subscriptions.frequency.D": "Codziennie", + "subscriptions.frequency.M": "Co miesiąc", + "subscriptions.frequency.W": "Co tydzień", + "subscriptions.tooltip": "Subskrybuj", + "subscriptions.modal.title": "Subksrypcje", + "subscriptions.modal.type-frequency": "Rodzaj i częstotliwość subksrypcji", + "subscriptions.modal.close": "Zamknij", + "subscriptions.modal.delete-info": "Aby usunąć tę subksrypcję przejdź do strony 'Subskrypcje', która znajduje się w profilu użytkownika", + "subscriptions.modal.new-subscription-form.type.content": "Zawartość", + "subscriptions.modal.new-subscription-form.frequency.D": "Codziennie", + "subscriptions.modal.new-subscription-form.frequency.W": "Co tydzień", + "subscriptions.modal.new-subscription-form.frequency.M": "Co miesiąc", + "subscriptions.modal.new-subscription-form.submit": "Zapisz", + "subscriptions.modal.new-subscription-form.processing": "Ładowanie...", + "subscriptions.modal.create.success": "Zasubskrybowano {{ type }}", + "subscriptions.modal.delete.success": "Subskrypcja została anulowana", + "subscriptions.modal.update.success": "Twoja subskrypcja {{ type }} została zaktualizowana", + "subscriptions.modal.create.error": "Wystąpił bład podczas tworzenia subskrypcji", + "subscriptions.modal.delete.error": "Wystąpił bład podczas usuwania subskrypcji", + "subscriptions.modal.update.error": "Wystąpił bład podczas aktualizacji subskrypcji", + "subscriptions.table.dso": "Słowo kluczowe", + "subscriptions.table.subscription_type": "Typ subskrypcji", + "subscriptions.table.subscription_frequency": "Częstotliwość subskrypcji", + "subscriptions.table.action": "Akcja", + "subscriptions.table.edit": "Edytuj", + "subscriptions.table.delete": "Usuń", + "subscriptions.table.not-available": "Niedostępne", + "subscriptions.table.not-available-message": "Ta pozycja została usunięta lun nie masz do niej dostępu, aby ją wyswietlić", + "subscriptions.table.empty.message": "Ta pozycja nie ma w tym momencie żadnych subksrypcji. Aby zasubkrybować i otrzymywać aktualizacje o tym zbiorze lub kolekcji, wybierz przycisk subskrypcji na stronie pozycji.", + "vocabulary-treeview.info": "Wybierz słowo kluczowe, aby dodać je do filtra", + "supervisedWorkspace.search.results.head": "Pozycje recenzowane", + "supervision.search.results.head": "Status zadań: Szkic i redakcja", + "workspace-item.delete.breadcrumbs": "Usunięto wersję roboczą", + "workspace-item.delete.header": "Usuń wersję roboczą", + "workspace-item.delete.button.confirm": "Usuń", + "workspace-item.delete.button.cancel": "Anuluj", + "workspace-item.delete.notification.success.title": "Usunięto", + "workspace-item.delete.title": "Wersja robocza została usunieta", + "workspace-item.delete.notification.error.title": "Coś poszło nie tak", + "workspace-item.delete.notification.error.content": "Wersja robocza nie może zostać usunieta", + "workflow-item.advanced.title": "Zaawansowane workflow", + "workflow-item.selectrevieweraction.notification.success.title": "Wybrany recenzent", + "workflow-item.selectrevieweraction.notification.success.content": "Recenzent został przypisany", + "workflow-item.selectrevieweraction.notification.error.title": "Coś poszło nie tak", + "workflow-item.selectrevieweraction.notification.error.content": "Nie udało się wybrać recenzenta dla pozycji", + "workflow-item.selectrevieweraction.title": "Wybierz recenzenta", + "workflow-item.selectrevieweraction.header": "Wybierz recenzenta", + "workflow-item.selectrevieweraction.button.cancel": "Anuluj", + "workflow-item.selectrevieweraction.button.confirm": "Zatwierdź", + "workflow-item.scorereviewaction.notification.success.title": "Ocena recenzji", + "workflow-item.scorereviewaction.notification.success.content": "Ocena tej pozycji została zapisana", + "workflow-item.scorereviewaction.notification.error.title": "Coś poszło nie tak", + "workflow-item.scorereviewaction.notification.error.content": "Nie można ocenić tej pozycji", + "workflow-item.scorereviewaction.title": "Oceń pozycję", + "workflow-item.scorereviewaction.header": "Oceń pozycję", + "workflow-item.scorereviewaction.button.cancel": "Anuluj", + "workflow-item.scorereviewaction.button.confirm": "Potwierdź", + "listable-notification-object.default-message": "Ta pozycja nie może być odzyskana", + "system-wide-alert-banner.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert-banner.countdown.prefix": "W", + "system-wide-alert-banner.countdown.days": "{{days}} dni,", + "system-wide-alert-banner.countdown.hours": "{{hours}} godziny", + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minut:", + "menu.section.system-wide-alert": "Alert systemowy", + "system-wide-alert.form.header": "Alert systemowy", + "system-wide-alert-form.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert.form.cancel": "Anuluj", + "system-wide-alert.form.save": "Zapisz", + "system-wide-alert.form.label.active": "AKTYWNE", + "system-wide-alert.form.label.inactive": "NIEAKTYWNE", + "system-wide-alert.form.error.message": "Alert systemowy musi zawierać wiadomość", + "system-wide-alert.form.label.message": "Alert systemowy", + "system-wide-alert.form.label.countdownTo.enable": "Wprowadź licznik czasowy", + "system-wide-alert.form.label.countdownTo.hint": "Wskazówka: Wpisz wartość licznika czasu. Kiedy licznik jest włączony, alert systemowy zostanie wyświetlony o wybranym czasie. Kiedy odliczanie zostanie zakończone, alert systemowy zostanie wyłączony. Serwer NIE zostanie zatrzymany automatycznie.", + "system-wide-alert.form.label.preview": "Podgląd alertu systemowego", + "system-wide-alert.form.update.success": "Alert systemowy został zaktualizowany", + "system-wide-alert.form.update.error": "Coś poszło nie tak podczas aktualizacji alertu systemowego", + "system-wide-alert.form.create.success": "Alert systemowy został utworzony", + "system-wide-alert.form.create.error": "Coś poszło nie tak podczas tworzenia alertu systemowego", + "admin.system-wide-alert.breadcrumbs": "Alerty systemowe", + "admin.system-wide-alert.title": "Alerty systemowe", + "item-access-control-title": "Ta strona pozwala na zmianę dostępów metadanych pozycji i plików do nich dołączonych.", + "collection-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w tej kolekcji. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "community-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w każdej kolekcji w tym zbiorze. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "access-control-item-header-toggle": "Metadane pozycji", + "access-control-bitstream-header-toggle": "Pliki", + "access-control-mode": "Tryb", + "access-control-access-conditions": "Warunki dostępu", + "access-control-no-access-conditions-warning-message": "W tym momencie żadne warunki dostępu nie zostały określone. Jeśli zadanie zostanie rozpoczęte, obecne warunki dostępu zostaną zastąpione domyślnymi warunkami dostępu z nadrzędnej kolekcji.", + "access-control-replace-all": "Zastąp warunki dostępu", + "access-control-add-to-existing": "Dodaj do już istniejących", + "access-control-limit-to-specific": "Ogranicz zmiany do wybranych plików", + "access-control-process-all-bitstreams": "Zaktualizuj wszystkie pliki dla tej pozycji", + "access-control-bitstreams-selected": "wybrane pliki", + "access-control-cancel": "Anuluj", + "access-control-execute": "Wykonaj", + "access-control-add-more": "Dodaj więcej", + "access-control-select-bitstreams-modal.title": "Wybierz pliki", + "access-control-select-bitstreams-modal.no-items": "Brak pozycji do wyświetlenia.", + "access-control-select-bitstreams-modal.close": "Zamknij", + "access-control-option-label": "Typ warunków dostępu", + "access-control-option-note": "Wybierz warunki dostępu, które chcesz przypisać do zaznaczonych pozycji.", + "access-control-option-start-date": "Dostęp od", + "access-control-option-start-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", + "access-control-option-end-date": "Dostęp do", + "access-control-option-end-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", } From 93299ec83da645189b1183806faee1d11a8e2e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dykas?= <96572102+michdyk@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:50:37 +0200 Subject: [PATCH 101/282] Update pl.json5 fix issues from tests --- src/assets/i18n/pl.json5 | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/assets/i18n/pl.json5 b/src/assets/i18n/pl.json5 index 39e1fce8e62..0bc2b2ec4a5 100644 --- a/src/assets/i18n/pl.json5 +++ b/src/assets/i18n/pl.json5 @@ -2336,12 +2336,12 @@ "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Adres e-mail", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Usuń / Dodaj", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Usuń użytkownika z nazwę "{{name}}"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Dodano użytkownika o nazwie: "{{name}}"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Nie dodano użytkownika: "{{name}}"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Usunięto użytkownika: "{{name}}"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Nie usunięto użytkownika: "{{name}}"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodano użytkownika "{{name}}"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Usuń użytkownika z nazwę \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Dodano użytkownika o nazwie: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Nie dodano użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Nie usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodano użytkownika \"{{name}}\"", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę.", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nie znaleziono żadnych użytkowników", @@ -2381,7 +2381,7 @@ "supervision-group-selector.notification.create.failure.title": "Błąd", "supervision-group-selector.notification.create.already-existing": "Funkcja recenzenta już jest przypisana do tej grupy", "confirmation-modal.delete-subscription.header": "Usuń subksrypcje", - "confirmation-modal.delete-subscription.info": "Czy na pewno chcesz usunąć subskrypcję: "{{ dsoName }}"", + "confirmation-modal.delete-subscription.info": "Czy na pewno chcesz usunąć subskrypcję: \"{{ dsoName }}\"", "confirmation-modal.delete-subscription.cancel": "Anuluj", "confirmation-modal.delete-subscription.confirm": "Usuń", "error.validation.metadata.name.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", @@ -2433,8 +2433,8 @@ "workflow-item.search.result.delete-supervision.modal.info": "Czy na pewno usunąć zadanie dla recenzenta", "workflow-item.search.result.delete-supervision.modal.cancel": "Anuluj", "workflow-item.search.result.delete-supervision.modal.confirm": "Usuń", - "workflow-item.search.result.notification.deleted.success": "Usunięto zadanie dla recenzenta "{{name}}"", - "workflow-item.search.result.notification.deleted.failure": "Nie usunięto zadania dla recenzenta "{{name}}"", + "workflow-item.search.result.notification.deleted.success": "Usunięto zadanie dla recenzenta \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Nie usunięto zadania dla recenzenta \"{{name}}\"", "workflow-item.search.result.list.element.supervised-by": "Recenzja:", "workflow-item.search.result.list.element.supervised.remove-tooltip": "Usuń grupę recenzencką", "item.preview.dc.subject": "Słowo kluczowe:", @@ -2482,8 +2482,8 @@ "register-page.registration.email.error.not-valid-domain": "Użyj adresu e-mail z domeny: {{ domains }}", "register-page.registration.error.maildomain": "Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", "register-page.registration.info.maildomain": "Konta mogą być założone dla adresów e-mail z domeną", - "repository.title": "Repozytorium DSpace" - "search.filters.applied.f.supervisedBy": "Recenzent" + "repository.title": "Repozytorium DSpace", + "search.filters.applied.f.supervisedBy": "Recenzent", "search.filters.filter.show-tree": "Przeglądaj {{ name }} strukturę recenzentów", "search.filters.filter.supervisedBy.head": "Recenzent", "search.filters.filter.supervisedBy.placeholder": "Recenzent", From f58a7a2e9b4ea09359c48604d1867ca94185977b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dykas?= <96572102+michdyk@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:18:36 +0200 Subject: [PATCH 102/282] Update pl.json5 fix test 2 spaces instead of 1 --- src/assets/i18n/pl.json5 | 5238 +++++++++++++++++++------------------- 1 file changed, 2619 insertions(+), 2619 deletions(-) diff --git a/src/assets/i18n/pl.json5 b/src/assets/i18n/pl.json5 index 0bc2b2ec4a5..7a857ae4fdb 100644 --- a/src/assets/i18n/pl.json5 +++ b/src/assets/i18n/pl.json5 @@ -1,2621 +1,2621 @@ { - "401.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", - "401.link.home-page": "Zabierz mnie na stronę główną", - "401.unauthorized": "nieautoryzowany", - "403.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "403.link.home-page": "Zabierz mnie na stronę główną", - "403.forbidden": "zabroniony", - "404.help": "Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", - "404.link.home-page": "Zabierz mnie na stronę główną", - "404.page-not-found": "strona nie została znaleziona", - "admin.curation-tasks.breadcrumbs": "Systemowe zadania administracyjne", - "admin.curation-tasks.title": "Systemowe zadania administracyjne", - "admin.curation-tasks.header": "Systemowe zadania administracyjne", - "admin.registries.bitstream-formats.breadcrumbs": "Rejestr formatów", - "admin.registries.bitstream-formats.create.breadcrumbs": "Format strumienia bitów", - "admin.registries.bitstream-formats.create.failure.content": "Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", - "admin.registries.bitstream-formats.create.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.create.head": "Utwórz nowy format", - "admin.registries.bitstream-formats.create.new": "Dodaj nowy format", - "admin.registries.bitstream-formats.create.success.content": "Nowy format strumienia bitów został pomyślnie utworzony.", - "admin.registries.bitstream-formats.create.success.head": "Udało się", - "admin.registries.bitstream-formats.delete.failure.amount": "Nie udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.delete.success.amount": "Udało się usunąć {{ amount }} formatu(ów)", - "admin.registries.bitstream-formats.delete.success.head": "Udało się", - "admin.registries.bitstream-formats.description": "Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", - "admin.registries.bitstream-formats.edit.breadcrumbs": "Format strumienia bitów", - "admin.registries.bitstream-formats.edit.description.hint": "", - "admin.registries.bitstream-formats.edit.description.label": "Opis", - "admin.registries.bitstream-formats.edit.extensions.hint": "Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", - "admin.registries.bitstream-formats.edit.extensions.label": "Rozszerzenia plików", - "admin.registries.bitstream-formats.edit.extensions.placeholder": "Wprowadź rozszerzenie pliku bez kropki", - "admin.registries.bitstream-formats.edit.failure.content": "Wystąpił błąd podczas edycji formatu pliku.", - "admin.registries.bitstream-formats.edit.failure.head": "Nie udało się", - "admin.registries.bitstream-formats.edit.head": "Format plików: {{ format }}", - "admin.registries.bitstream-formats.edit.internal.hint": "Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", - "admin.registries.bitstream-formats.edit.internal.label": "Wewnętrzny", - "admin.registries.bitstream-formats.edit.mimetype.hint": "Typ MIME powiązany z tym formatem, nie musi być unikalny.", - "admin.registries.bitstream-formats.edit.mimetype.label": "Typ MIME", - "admin.registries.bitstream-formats.edit.shortDescription.hint": "Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", - "admin.registries.bitstream-formats.edit.shortDescription.label": "Nazwa", - "admin.registries.bitstream-formats.edit.success.content": "Format strumienia bitów został pomyślnie edytowany.", - "admin.registries.bitstream-formats.edit.success.head": "Udało się", - "admin.registries.bitstream-formats.edit.supportLevel.hint": "Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", - "admin.registries.bitstream-formats.edit.supportLevel.label": "Obsługiwany format", - "admin.registries.bitstream-formats.head": "Rejestr formatów", - "admin.registries.bitstream-formats.no-items": "Brak formatów plików do wyświetlenia.", - "admin.registries.bitstream-formats.table.delete": "Usuń zaznaczone", - "admin.registries.bitstream-formats.table.deselect-all": "Odznacz wszystkie", - "admin.registries.bitstream-formats.table.internal": "wewnętrzne", - "admin.registries.bitstream-formats.table.mimetype": "Typ MIME", - "admin.registries.bitstream-formats.table.name": "Nazwa", - "admin.registries.bitstream-formats.table.return": "Powrót", - "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Znane", - "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Wspierane", - "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Nieznane", - "admin.registries.bitstream-formats.table.supportLevel.head": "Obsługiwany format", - "admin.registries.bitstream-formats.title": "Rejestr formatów plików", - "admin.registries.metadata.breadcrumbs": "Rejestr metadanych", - "admin.registries.metadata.description": "W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", - "admin.registries.metadata.form.create": "Utwórz schemat metadanych", - "admin.registries.metadata.form.edit": "Edytuj schemat metadanych", - "admin.registries.metadata.form.name": "Nazwa", - "admin.registries.metadata.form.namespace": "Nazwa schematu", - "admin.registries.metadata.head": "Rejestr metadanych", - "admin.registries.metadata.schemas.no-items": "Brak rejestrów metadanych do pokazania.", - "admin.registries.metadata.schemas.table.delete": "Usuń zaznaczone", - "admin.registries.metadata.schemas.table.id": "ID", - "admin.registries.metadata.schemas.table.name": "Nazwa", - "admin.registries.metadata.schemas.table.namespace": "Nazwa schematu", - "admin.registries.metadata.title": "Rejestr metadanych", - "admin.registries.schema.breadcrumbs": "Schemat metadanych", - "admin.registries.schema.description": "Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", - "admin.registries.schema.fields.head": "Pola schematu metadanych", - "admin.registries.schema.fields.no-items": "Brak pól metadanych do pokazania.", - "admin.registries.schema.fields.table.delete": "Usuń zaznaczone", - "admin.registries.schema.fields.table.field": "Pole", - "admin.registries.schema.fields.table.scopenote": "Uwagi", - "admin.registries.schema.form.create": "Stwórz pole metadanych", - "admin.registries.schema.form.edit": "Edytuj pole metadanych", - "admin.registries.schema.form.element": "Element", - "admin.registries.schema.form.qualifier": "Kwalifikator", - "admin.registries.schema.form.scopenote": "Uwagi", - "admin.registries.schema.head": "Schemat metadanych", - "admin.registries.schema.notification.created": "Udało się utworzyć schemat metdanych \"{{prefix}}\"", - "admin.registries.schema.notification.deleted.failure": "Nie udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.deleted.success": "Udało się usunąć {{amount}} schematów metadanych", - "admin.registries.schema.notification.edited": "Udało się edytować schemat metadanych \"{{prefix}}\"", - "admin.registries.schema.notification.failure": "Błąd", - "admin.registries.schema.notification.field.created": "Udało się utworzyć pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.field.deleted.failure": "Nie udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.deleted.success": "Udało się usunąć {{amount}} pól metadanych", - "admin.registries.schema.notification.field.edited": "SUdało się edytować pole metadanych \"{{field}}\"", - "admin.registries.schema.notification.success": "Udało się", - "admin.registries.schema.return": "Powrót", - "admin.registries.schema.title": "Rejestr schematów metadanych", - "admin.access-control.epeople.actions.delete": "Usuń użytkownika", - "admin.access-control.epeople.actions.impersonate": "Personifikuj użytkownika", - "admin.access-control.epeople.actions.reset": "Zresetuj hasło", - "admin.access-control.epeople.actions.stop-impersonating": "Przestań personifikować użytkownika", - "admin.access-control.epeople.breadcrumbs": "Użytkownicy", - "admin.access-control.epeople.title": "Użytkownicy", - "admin.access-control.epeople.head": "Użytkownicy", - "admin.access-control.epeople.search.head": "Wyszukaj", - "admin.access-control.epeople.button.see-all": "Przeglądaj wszystko", - "admin.access-control.epeople.search.scope.metadata": "Metadane", - "admin.access-control.epeople.search.scope.email": "E-mail", - "admin.access-control.epeople.search.button": "Wyszukaj", - "admin.access-control.epeople.search.placeholder": "Wyszukaj użytkownika...", - "admin.access-control.epeople.button.add": "Dodaj użytkownika", - "admin.access-control.epeople.table.id": "ID", - "admin.access-control.epeople.table.name": "Nazwa", - "admin.access-control.epeople.table.email": "E-mail", - "admin.access-control.epeople.table.edit": "Edytuj", - "admin.access-control.epeople.table.edit.buttons.edit": "Edytuj \"{{name}}\"", - "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Brak uprawnień do edycji wybranej grupy", - "admin.access-control.epeople.table.edit.buttons.remove": "Usuń \"{{name}}\"", - "admin.access-control.epeople.no-items": "Brak użytkowników do wyświetlenia.", - "admin.access-control.epeople.form.create": "Utwórz użytkownika", - "admin.access-control.epeople.form.edit": "Edytuj użytkownika", - "admin.access-control.epeople.form.firstName": "Imię", - "admin.access-control.epeople.form.lastName": "Nazwisko", - "admin.access-control.epeople.form.email": "E-mail", - "admin.access-control.epeople.form.emailHint": "Adres e-mail musi być poprawny", - "admin.access-control.epeople.form.canLogIn": "Możliwość zalogowania", - "admin.access-control.epeople.form.requireCertificate": "Wymagany certyfikat", - "admin.access-control.epeople.form.return": "Powrót", - "admin.access-control.epeople.form.notification.created.success": "Udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure": "Nie udało się utworzyć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", - "admin.access-control.epeople.form.notification.edited.success": "Udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.edited.failure": "Nie udało się edytować użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.success": "Udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.notification.deleted.failure": "Nie udało się usunąć użytkownika \"{{name}}\"", - "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Członek grup:", - "admin.access-control.epeople.form.table.id": "ID", - "admin.access-control.epeople.form.table.name": "Nazwa", - "admin.access-control.epeople.form.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.epeople.form.memberOfNoGroups": "Ten użytkownik nie jest członkiem żadnej grupy", - "admin.access-control.epeople.form.goToGroups": "Dodaj do grup", - "admin.access-control.epeople.notification.deleted.failure": "Nie udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.epeople.notification.deleted.success": "Udało się usunąć użytkownika: \"{{name}}\"", - "admin.access-control.groups.title": "Grupy", - "admin.access-control.groups.breadcrumbs": "Grupy", - "admin.access-control.groups.singleGroup.breadcrumbs": "Edytuj grupę", - "admin.access-control.groups.title.singleGroup": "Edytuj grupę", - "admin.access-control.groups.title.addGroup": "Nowa grupa", - "admin.access-control.groups.addGroup.breadcrumbs": "Nowa grupa", - "admin.access-control.groups.head": "Grupy/role", - "admin.access-control.groups.button.add": "Dodaj grupę", - "admin.access-control.groups.search.head": "Szukaj grup", - "admin.access-control.groups.button.see-all": "Przeszukaj wszystko", - "admin.access-control.groups.search.button": "Wyszukaj", - "admin.access-control.groups.search.placeholder": "Wyszukaj grupy...", - "admin.access-control.groups.table.id": "ID", - "admin.access-control.groups.table.name": "Nazwa", - "admin.access-control.groups.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.groups.table.members": "Członkowie", - "admin.access-control.groups.table.edit": "Edytuj", - "admin.access-control.groups.table.edit.buttons.edit": "Edytuj \"{{name}}\"", - "admin.access-control.groups.no-items": "Nie znaleziono grup z podaną frazą lub podanym UUID", - "admin.access-control.groups.notification.deleted.success": "Udało się usunąć grupę \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{name}}\"", - "admin.access-control.groups.notification.deleted.failure.content": "Powód: \"{{cause}}\"", - "admin.access-control.groups.form.alert.permanent": "Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", - "admin.access-control.groups.form.alert.workflowGroup": "Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", - "admin.access-control.groups.form.head.create": "Utwórz grupę", - "admin.access-control.groups.form.head.edit": "Edytuj grupę", - "admin.access-control.groups.form.groupName": "Nazwa grupy", - "admin.access-control.groups.form.groupCommunity": "Zbiór lub kolekcja", - "admin.access-control.groups.form.groupDescription": "Opis", - "admin.access-control.groups.form.notification.created.success": "Udało się utworzyć grupę \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure": "Nie udało się utworzyć grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", - "admin.access-control.groups.form.notification.edited.failure": "Nie udało się edytować grupy \"{{name}}\"", - "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Nazwa \"{{name}}\" już w użyciu!", - "admin.access-control.groups.form.notification.edited.success": "Udało się edytować grupę \"{{name}}\"", - "admin.access-control.groups.form.actions.delete": "Usuń grupę", - "admin.access-control.groups.form.delete-group.modal.header": "Usuń grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.info": "Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", - "admin.access-control.groups.form.delete-group.modal.cancel": "Anuluj", - "admin.access-control.groups.form.delete-group.modal.confirm": "Usuń", - "admin.access-control.groups.form.notification.deleted.success": "Udało się usunąć grupę \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{ name }}\"", - "admin.access-control.groups.form.notification.deleted.failure.content": "Powód: \"{{ cause }}\"", - "admin.access-control.groups.form.members-list.head": "Użytkownik", - "admin.access-control.groups.form.members-list.search.head": "Dodaj użytkownika", - "admin.access-control.groups.form.members-list.button.see-all": "Pokaż wszystkich", - "admin.access-control.groups.form.members-list.headMembers": "Aktualni członkowie", - "admin.access-control.groups.form.members-list.search.scope.metadata": "Metadane", - "admin.access-control.groups.form.members-list.search.scope.email": "E-mail", - "admin.access-control.groups.form.members-list.search.button": "Wyszukaj", - "admin.access-control.groups.form.members-list.table.id": "ID", - "admin.access-control.groups.form.members-list.table.name": "Nazwa", - "admin.access-control.groups.form.members-list.table.identity": "Tożsamość", - "admin.access-control.groups.form.members-list.table.email": "E-mail", - "admin.access-control.groups.form.members-list.table.netid": "NetID", - "admin.access-control.groups.form.members-list.table.edit": "Usuń / Dodaj", - "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Usuń użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.addMember": "Udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.addMember": "Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", - "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Dodaj użytkownika o nazwie \"{{name}}\"", - "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.members-list.no-members-yet": "Brak użytkowników w grupie, wyszukaj ich i dodaj.", - "admin.access-control.groups.form.members-list.no-items": "Nie znaleziono użytkowników podczas wyszukiwania", - "admin.access-control.groups.form.subgroups-list.notification.failure": "Coś poszło nie tak: \"{{cause}}\"", - "admin.access-control.groups.form.subgroups-list.head": "Grupy", - "admin.access-control.groups.form.subgroups-list.search.head": "Dodaj podgrupę", - "admin.access-control.groups.form.subgroups-list.button.see-all": "Przeglądaj wszystkie", - "admin.access-control.groups.form.subgroups-list.headSubgroups": "Aktualne podgrupy", - "admin.access-control.groups.form.subgroups-list.search.button": "Wyszukaj", - "admin.access-control.groups.form.subgroups-list.table.id": "ID", - "admin.access-control.groups.form.subgroups-list.table.name": "Nazwa", - "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Zbiór/kolekcja", - "admin.access-control.groups.form.subgroups-list.table.edit": "Usuń / Dodaj", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Usuń podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Dodaj podgrupę o nazwie \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Aktualna grupa", - "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Udało się dodać podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Nie udało się dodać podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Udało się usunąć podgrupę: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Nie udało się usunąć podgrupy: \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", - "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ta grupa jest już stworzona i nie może zostać dodana pononwie.", - "admin.access-control.groups.form.subgroups-list.no-items": "Nie znaleziono grup z tą nazwą lub UUID", - "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Brak podgrup w grupie.", - "admin.access-control.groups.form.return": "Powrót", - "admin.search.breadcrumbs": "Wyszukiwanie administracyjne", - "admin.search.collection.edit": "Edytuj", - "admin.search.community.edit": "Edytuj", - "admin.search.item.delete": "Usuń", - "admin.search.item.edit": "Edytuj", - "admin.search.item.make-private": "Ukryj", - "admin.search.item.make-public": "Upublicznij", - "admin.search.item.move": "Przenieś", - "admin.search.item.reinstate": "Zmień instancję", - "admin.search.item.withdraw": "Wycofane", - "admin.search.title": "Wyszukiwanie administracyjne", - "administrativeView.search.results.head": "Wyszukiwanie administracyjne", - "admin.workflow.breadcrumbs": "Zarządzaj procesem", - "admin.workflow.title": "Zarządzaj procesem", - "admin.workflow.item.workflow": "Proces", - "admin.workflow.item.delete": "Usuń", - "admin.workflow.item.send-back": "Odeślij z powrotem", - "admin.metadata-import.breadcrumbs": "Importuj metadane", - "admin.metadata-import.title": "Importuj metadane", - "admin.metadata-import.page.header": "Importuj metadane", - "admin.metadata-import.page.help": "Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", - "admin.metadata-import.page.dropMsg": "Upuść plik w formacie CSV", - "admin.metadata-import.page.dropMsgReplace": "Upuść, aby zastąpić metadane w formacie CSV do importu", - "admin.metadata-import.page.button.return": "Powrót", - "admin.metadata-import.page.button.proceed": "Zastosuj", - "admin.metadata-import.page.error.addFile": "Najpierw wybierz plik!", - "auth.errors.invalid-user": "Niewłaściwy adres e-mail lub hasło.", - "auth.messages.expired": "Twoja sesja wygasła. Zaloguj się ponownie.", - "auth.messages.token-refresh-failed": "Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", - "bitstream.download.page": "Pobieranie {{bitstream}}...", - "bitstream.download.page.back": "Powrót", - "bitstream.edit.authorizations.link": "Edytuj polityki plików", - "bitstream.edit.authorizations.title": "Edytuj polityki plików", - "bitstream.edit.return": "Powrót", - "bitstream.edit.bitstream": "Pliki: ", - "bitstream.edit.form.description.hint": "Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", - "bitstream.edit.form.description.label": "Opis", - "bitstream.edit.form.embargo.hint": "Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", - "bitstream.edit.form.embargo.label": "Embargo do wybranej daty", - "bitstream.edit.form.fileName.hint": "Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", - "bitstream.edit.form.fileName.label": "Nazwa pliku", - "bitstream.edit.form.newFormat.label": "Opisz nowy format", - "bitstream.edit.form.newFormat.hint": "Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", - "bitstream.edit.form.primaryBitstream.label": "Pierwotny plik", - "bitstream.edit.form.selectedFormat.hint": "Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", - "bitstream.edit.form.selectedFormat.label": "Wybrany format", - "bitstream.edit.form.selectedFormat.unknown": "Tego formatu nie ma na liście", - "bitstream.edit.notifications.error.format.title": "Wystąpił błąd podczas zapisu formatu pliku", - "bitstream.edit.notifications.saved.content": "Zmiany w pliku zostały zapisane.", - "bitstream.edit.notifications.saved.title": "Plik został zapisany", - "bitstream.edit.title": "Edytuj plik", - "bitstream-request-a-copy.alert.canDownload1": "Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", - "bitstream-request-a-copy.alert.canDownload2": "tutaj", - "bitstream-request-a-copy.header": "Wystąp o kopię wybranego pliku", - "bitstream-request-a-copy.intro": "Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", - "bitstream-request-a-copy.intro.bitstream.one": "Wystąpienie o dostęp do następujących plików: ", - "bitstream-request-a-copy.intro.bitstream.all": "Wystąpienie o dostęp do wszystkich plików. ", - "bitstream-request-a-copy.name.label": "Imię *", - "bitstream-request-a-copy.name.error": "Imię jest wymagane", - "bitstream-request-a-copy.email.label": "Adres e-mail *", - "bitstream-request-a-copy.email.hint": "Plik zostanie przesłany na podany adres e-mail", - "bitstream-request-a-copy.email.error": "Proszę wprowadzić prawidłowy adres e-mail", - "bitstream-request-a-copy.allfiles.label": "Pliki", - "bitstream-request-a-copy.files-all-false.label": "Tylko plik, dla którego wystąpiono o dostęp", - "bitstream-request-a-copy.files-all-true.label": "Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", - "bitstream-request-a-copy.message.label": "Wiadomość", - "bitstream-request-a-copy.return": "Powrót", - "bitstream-request-a-copy.submit": "Wystąp o kopię", - "bitstream-request-a-copy.submit.success": "Wystąpienie o dostęp do pliku zostało przesłane.", - "bitstream-request-a-copy.submit.error": "Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", - "browse.comcol.by.author": "wg autorów", - "browse.comcol.by.dateissued": "wg daty wydania", - "browse.comcol.by.subject": "wg tematu", - "browse.comcol.by.title": "wg tytułu", - "browse.comcol.head": "Przeglądaj", - "browse.empty": "Brak rekordów do wyświetlenia.", - "browse.metadata.author": "Autor", - "browse.metadata.dateissued": "Data wydania", - "browse.metadata.subject": "Temat", - "browse.metadata.title": "Tytuł", - "browse.metadata.author.breadcrumbs": "Przeglądaj wg autorów", - "browse.metadata.dateissued.breadcrumbs": "Przeglądaj wg daty wydania", - "browse.metadata.subject.breadcrumbs": "Przeglądaj wg tematów", - "browse.metadata.title.breadcrumbs": "Przeglądaj wg tytułów", - "browse.startsWith.choose_start": "(Wybierz start)", - "browse.startsWith.choose_year": "(Wybierz rok)", - "browse.startsWith.choose_year.label": "Wybierz rok wydania", - "browse.startsWith.jump": "Przejdź do miejsca w indeksie:", - "browse.startsWith.months.april": "kwiecień", - "browse.startsWith.months.august": "sierpień", - "browse.startsWith.months.december": "grudzień", - "browse.startsWith.months.february": "luty", - "browse.startsWith.months.january": "styczeń", - "browse.startsWith.months.july": "lipiec", - "browse.startsWith.months.june": "czerwiec", - "browse.startsWith.months.march": "marzec", - "browse.startsWith.months.may": "maj", - "browse.startsWith.months.none": "(wybierz miesiąc)", - "browse.startsWith.months.none.label": "Wybierz miesiąc wydania", - "browse.startsWith.months.november": "listopad", - "browse.startsWith.months.october": "październik", - "browse.startsWith.months.september": "wrzesień", - "browse.startsWith.submit": "Zastosuj", - "browse.startsWith.type_date": "Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", - "browse.startsWith.type_date.label": "Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", - "browse.startsWith.type_text": "Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", - "browse.title": "Przeglądaj {{ collection }} wg {{ field }} {{ value }}", - "chips.remove": "Usuń chip", - "collection.create.head": "Utwórz kolekcję", - "collection.create.notifications.success": "Udało się utworzyć kolekcję", - "collection.create.sub-head": "Udało się utworzyć kolekcję dla zbioru {{ parent }}", - "collection.curate.header": "Administrator kolekcji: {{collection}}", - "collection.delete.cancel": "Anuluj", - "collection.delete.confirm": "Zatwierdź", - "collection.delete.processing": "Usuwanie", - "collection.delete.head": "Usuń kolekcję", - "collection.delete.notification.fail": "Kolekcja nie może być usunięt", - "collection.delete.notification.success": "Udało się usunąć kolekcję", - "collection.delete.text": "Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", - "collection.edit.delete": "Usuń kolekcję", - "collection.edit.head": "Edytuj kolekcję", - "collection.edit.breadcrumbs": "Edytuj kolekcję", - "collection.edit.tabs.mapper.head": "Item Mapper", - "collection.edit.tabs.item-mapper.title": "Edytuj kolekcję - Item Mapper", - "collection.edit.item-mapper.cancel": "Anuluj", - "collection.edit.item-mapper.collection": "Kolekcja: \"<b>{{name}}</b>\"", - "collection.edit.item-mapper.confirm": "Mapuj wybrane elementy", - "collection.edit.item-mapper.description": "To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", - "collection.edit.item-mapper.head": "Item Mapper - Mapuj pozycje z innych kolekcji", - "collection.edit.item-mapper.no-search": "Wpisz co chcesz wyszukać", - "collection.edit.item-mapper.notifications.map.error.content": "Wystąpiły błędy podczas mapowania {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.error.head": "Mapowanie błędów", - "collection.edit.item-mapper.notifications.map.success.content": "Udało się zmapować {{amount}} pozycji.", - "collection.edit.item-mapper.notifications.map.success.head": "Mapowanie zakończone", - "collection.edit.item-mapper.notifications.unmap.error.content": "Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.error.head": "Usuń błędy mapowania", - "collection.edit.item-mapper.notifications.unmap.success.content": "Udało się usunąć błędy mapowania z {{amount}} elementów.", - "collection.edit.item-mapper.notifications.unmap.success.head": "Usuwanie mapowania zakończone", - "collection.edit.item-mapper.remove": "Usuń wybrane mapowanie elementów", - "collection.edit.item-mapper.search-form.placeholder": "Wyszukaj pozycje...", - "collection.edit.item-mapper.tabs.browse": "Wyszukaj mapowane elementy", - "collection.edit.item-mapper.tabs.map": "Mapuj nowe elementy", - "collection.edit.logo.delete.title": "Usuń", - "collection.edit.logo.delete-undo.title": "Cofnij usunięcie", - "collection.edit.logo.label": "Logo kolekcji", - "collection.edit.logo.notifications.add.error": "Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", - "collection.edit.logo.notifications.add.success": "Udało się przesłać logo kolekcji.", - "collection.edit.logo.notifications.delete.success.title": "Logo usunięte", - "collection.edit.logo.notifications.delete.success.content": "Udało się usunąć logo kolekcji", - "collection.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", - "collection.edit.logo.upload": "Upuść logo kolekcji, aby je wgrać", - "collection.edit.notifications.success": "Udało się edytować kolekcję", - "collection.edit.return": "Powrót", - "collection.edit.tabs.curate.head": "Kurator", - "collection.edit.tabs.curate.title": "Edytowanie kolekcji - kurator", - "collection.edit.tabs.authorizations.head": "Autoryzacje", - "collection.edit.tabs.authorizations.title": "Edytowanie kolekcji - autoryzacje", - "collection.edit.tabs.metadata.head": "Edytuj metadane", - "collection.edit.tabs.metadata.title": "Edytowanie kolekcji - metadane", - "collection.edit.tabs.roles.head": "Przypisz role", - "collection.edit.tabs.roles.title": "Edytowanie kolekcji - role", - "collection.edit.tabs.source.external": "Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", - "collection.edit.tabs.source.form.errors.oaiSource.required": "Musisz wskazać id docelowej kolekcji.", - "collection.edit.tabs.source.form.harvestType": "Odczytywanie zawartości", - "collection.edit.tabs.source.form.head": "Skonfiguruj zewnętrzne źródło", - "collection.edit.tabs.source.form.metadataConfigId": "Format metadanych", - "collection.edit.tabs.source.form.oaiSetId": "Określony zestaw ID OAI", - "collection.edit.tabs.source.form.oaiSource": "Dostawca OAI", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Odczytaj metadane i pliki (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", - "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Odczytaj tylko metadane", - "collection.edit.tabs.source.head": "Źródło treści", - "collection.edit.tabs.source.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", - "collection.edit.tabs.source.notifications.discarded.title": "Zmiany odrzucone", - "collection.edit.tabs.source.notifications.invalid.content": "Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", - "collection.edit.tabs.source.notifications.invalid.title": "Nieprawidłowe metadane", - "collection.edit.tabs.source.notifications.saved.content": "Zmiany wprowadzone w kolekcji zostały zapisane.", - "collection.edit.tabs.source.notifications.saved.title": "Źródło treści zapisane", - "collection.edit.tabs.source.title": "Collection Edit - Źródło treści", - "collection.edit.template.add-button": "Dodaj", - "collection.edit.template.breadcrumbs": "Szablon pozycji", - "collection.edit.template.cancel": "Anuluj", - "collection.edit.template.delete-button": "Usuń", - "collection.edit.template.edit-button": "Edytuj", - "collection.edit.template.error": "Wystąpił błąd podczas odzyskiwania szablonu pozycji", - "collection.edit.template.head": "Edytuj szablon dla kolekcji \"{{ collection }}\"", - "collection.edit.template.label": "Szablon pozycji", - "collection.edit.template.loading": "ładowanie szablonu pozycji...", - "collection.edit.template.notifications.delete.error": "Nie udało się usunąć szablonu pozycji", - "collection.edit.template.notifications.delete.success": "Udało się usunąć szablon pozycji", - "collection.edit.template.title": "Edytuj szablon pozycji", - "collection.form.abstract": "Opis skrócony", - "collection.form.description": "Tekst powitalny (HTML)", - "collection.form.errors.title.required": "Wpisz nazwę kolekcji", - "collection.form.license": "Licencja", - "collection.form.provenance": "Pochodzenie", - "collection.form.rights": "Tekst praw autorskich (HTML)", - "collection.form.tableofcontents": "Wiadomości (HTML)", - "collection.form.title": "Nazwa", - "collection.form.entityType": "Typ danych", - "collection.page.browse.recent.head": "Ostatnie zgłoszenia", - "collection.page.browse.recent.empty": "Brak pozycji do wyświetlenia", - "collection.page.edit": "Edytuj kolekcję", - "collection.page.handle": "Stały URI dla kolekcji", - "collection.page.license": "Licencja", - "collection.page.news": "Wiadomości", - "collection.select.confirm": "Zaakceptuj zaznaczone", - "collection.select.empty": "Brak kolekcji do wyświetlenia", - "collection.select.table.title": "Tytuł", - "collection.source.controls.head": "Kontrolki odczytywania", - "collection.source.controls.test.submit.error": "Coś poszło nie tak podczas rozpoczynania testów ustawień", - "collection.source.controls.test.failed": "Scenariusz testowy ustawień nie zadziałał", - "collection.source.controls.test.completed": "Scenariusz testowy ustawień został zakończony", - "collection.source.controls.test.submit": "Konfiguracja testowa", - "collection.source.controls.test.running": "Testowanie konfiguracji...", - "collection.source.controls.import.submit.success": "Import został rozpoczęty", - "collection.source.controls.import.submit.error": "Coś poszło nie tak podczas rozpoczynania importu", - "collection.source.controls.import.submit": "Importuj teraz", - "collection.source.controls.import.running": "Importowanie...", - "collection.source.controls.import.failed": "Wystąpił błąd podczas importu", - "collection.source.controls.import.completed": "Import zakończony", - "collection.source.controls.reset.submit.success": "Reset ustawień i powtórny import zostały rozpoczęte poprawnie", - "collection.source.controls.reset.submit.error": "Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", - "collection.source.controls.reset.failed": "Wystąpił błąd podczas resetowania ustawień i ponownego importu", - "collection.source.controls.reset.completed": "Reset ustawień i powtórny import zostały zakończone", - "collection.source.controls.reset.submit": "Resetowanie i powtórny import", - "collection.source.controls.reset.running": "Resetowanie i powtórny import...", - "collection.source.controls.harvest.status": "Status odczytywania:", - "collection.source.controls.harvest.start": "Czas rozpoczęcia odczytywania:", - "collection.source.controls.harvest.last": "Czas ostatniego odczytywania:", - "collection.source.controls.harvest.message": "Informacje nt. odczytywania:", - "collection.source.controls.harvest.no-information": "bd.", - "collection.source.update.notifications.error.content": "Te ustawienia zostały przetestowane i nie działają.", - "collection.source.update.notifications.error.title": "Błąd serwera", - "communityList.breadcrumbs": "Lista zbiorów", - "communityList.tabTitle": "Lista zbiorów", - "communityList.title": "Lista zbiorów", - "communityList.showMore": "Pokaż więcej", - "community.create.head": "Utwórz zbiór", - "community.create.notifications.success": "Udało się utworzyć zbiór", - "community.create.sub-head": "Utwórz podzbiór dla zbioru {{ parent }}", - "community.curate.header": "Zarządzaj zbiorem: {{community}}", - "community.delete.cancel": "Anuluj", - "community.delete.confirm": "Potwierdź", - "community.delete.processing": "Usuwanie...", - "community.delete.head": "Usuń zbiór", - "community.delete.notification.fail": "Zbiór nie może być usunięty", - "community.delete.notification.success": "Udało się usunąć zbiór", - "community.delete.text": "Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", - "community.edit.delete": "Usuń ten zbiór", - "community.edit.head": "Edytuj zbiór", - "community.edit.breadcrumbs": "Edytuj zbiór", - "community.edit.logo.delete.title": "Usuń logo", - "community.edit.logo.delete-undo.title": "Cofnij usunięcie", - "community.edit.logo.label": "Logo zbioru", - "community.edit.logo.notifications.add.error": "Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", - "community.edit.logo.notifications.add.success": "Przesłanie loga powiodło się.", - "community.edit.logo.notifications.delete.success.title": "Logo usunięte", - "community.edit.logo.notifications.delete.success.content": "Usunięcie loga zbioru powiodło się", - "community.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", - "community.edit.logo.upload": "Upuść logo zbioru, aby je przesłać", - "community.edit.notifications.success": "Udało się edytować zbiór", - "community.edit.notifications.unauthorized": "Nie masz uprawnień, aby wykonać te zmiany", - "community.edit.notifications.error": "Wystąpił błąd podczas edycji zbioru", - "community.edit.return": "Cofnij", - "community.edit.tabs.curate.head": "Administruj", - "community.edit.tabs.curate.title": "Edycja zbioru - administrator", - "community.edit.tabs.metadata.head": "Edytuj metadane", - "community.edit.tabs.metadata.title": "Edycja zbioru - metadane", - "community.edit.tabs.roles.head": "Przypisz role", - "community.edit.tabs.roles.title": "Edycja zbioru - role", - "community.edit.tabs.authorizations.head": "Uprawnienia", - "community.edit.tabs.authorizations.title": "Edycja zbioru - uprawnienia", - "community.listelement.badge": "Zbiór", - "comcol-role.edit.no-group": "Brak", - "comcol-role.edit.create": "Utwórz", - "comcol-role.edit.restrict": "Ogranicz", - "comcol-role.edit.delete": "Usuń", - "comcol-role.edit.community-admin.name": "Administratorzy", - "comcol-role.edit.collection-admin.name": "Administratorzy", - "comcol-role.edit.community-admin.description": "Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", - "comcol-role.edit.collection-admin.description": "Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", - "comcol-role.edit.submitters.name": "Zgłaszający", - "comcol-role.edit.submitters.description": "Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", - "comcol-role.edit.item_read.name": "Domyślny dostęp do odczytu pozycji", - "comcol-role.edit.item_read.description": "Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", - "comcol-role.edit.item_read.anonymous-group": "Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", - "comcol-role.edit.bitstream_read.name": "Domyślny dostęp do oczytu plików", - "comcol-role.edit.bitstream_read.description": "Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", - "comcol-role.edit.bitstream_read.anonymous-group": "Domyślny status odczytu dla nowych plików to Anonimowy.", - "comcol-role.edit.editor.name": "Redaktorzy", - "comcol-role.edit.editor.description": "Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", - "comcol-role.edit.finaleditor.name": "Redaktorzy końcowi", - "comcol-role.edit.finaleditor.description": "Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", - "comcol-role.edit.reviewer.name": "Recenzenci", - "comcol-role.edit.reviewer.description": "Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", - "community.form.abstract": "Opis skrócony", - "community.form.description": "Wstęp (HTML)", - "community.form.errors.title.required": "Wprowadź nazwę zbioru", - "community.form.rights": "Prawa autoskie (HTML)", - "community.form.tableofcontents": "Wiadomości (HTML)", - "community.form.title": "Nazwa", - "community.page.edit": "Edytuj ten zbiór", - "community.page.handle": "Stały URI zbioru", - "community.page.license": "Licencja", - "community.page.news": "Wiadomości", - "community.all-lists.head": "Podzbiory i kolekcje", - "community.sub-collection-list.head": "Kolekcje w tym zbiorze", - "community.sub-community-list.head": "Kolekcje w tym zbiorze", - "cookies.consent.accept-all": "Zaakceptuj wszystko", - "cookies.consent.accept-selected": "Zaakceptuj wybrane", - "cookies.consent.app.opt-out.description": "Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", - "cookies.consent.app.opt-out.title": "(możesz ją wyłaczyć)", - "cookies.consent.app.purpose": "cel", - "cookies.consent.app.required.description": "Ta aplikacja jest zawsze wymagana", - "cookies.consent.app.required.title": "(zawsze wymagana)", - "cookies.consent.update": "Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", - "cookies.consent.close": "Zamknij", - "cookies.consent.decline": "Odrzuć", - "cookies.consent.content-notice.description": "Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", - "cookies.consent.content-notice.learnMore": "Dostosuj", - "cookies.consent.content-modal.description": "Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", - "cookies.consent.content-modal.privacy-policy.name": "polityka prywatności", - "cookies.consent.content-modal.privacy-policy.text": "Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", - "cookies.consent.content-modal.title": "Informacje, które zbieramy", - "cookies.consent.app.title.authentication": "Logowanie", - "cookies.consent.app.description.authentication": "Musisz się zalogować", - "cookies.consent.app.title.preferences": "Preferencje", - "cookies.consent.app.description.preferences": "Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.acknowledgement": "Zgody", - "cookies.consent.app.description.acknowledgement": "Wymagane, aby zapisać Twoje preferencje", - "cookies.consent.app.title.google-analytics": "Google Analytics", - "cookies.consent.app.description.google-analytics": "Pozwól na śledzenie do celów statystycznych", - "cookies.consent.purpose.functional": "Funkcjonalne", - "cookies.consent.purpose.statistical": "Statystyczne", - "curation-task.task.checklinks.label": "Sprawdź odnośniki w metadanych", - "curation-task.task.noop.label": "NOOP", - "curation-task.task.profileformats.label": "Profil formatów plików", - "curation-task.task.requiredmetadata.label": "Sprawdź poprawność wymaganych metadanych", - "curation-task.task.translate.label": "Microsoft Translator", - "curation-task.task.vscan.label": "Skan antywirusowy", - "curation.form.task-select.label": "Zadanie:", - "curation.form.submit": "Start", - "curation.form.submit.success.head": "Udało się rozpocząć zadanie administratora", - "curation.form.submit.success.content": "Zostaniesz przeniesiony na stronę procesu.", - "curation.form.submit.error.head": "Nie udało się się zakończyć zadania administratora", - "curation.form.submit.error.content": "Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", - "curation.form.handle.label": "Automatyzacja:", - "curation.form.handle.hint": "Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", - "deny-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "deny-request-copy.email.subject": "Wystąp o kopię dokumentu", - "deny-request-copy.error": "Wystąpił błąd", - "deny-request-copy.header": "Odrzuć prośbę o przesłanie kopii dokumentu", - "deny-request-copy.intro": "Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", - "deny-request-copy.success": "Z powodzeniem odrzucono prośbę o udostępnienie pozycji", - "dso.name.untitled": "Brak tytułu", - "dso-selector.claim.item.head": "Wskazówki profilu", - "dso-selector.claim.item.body": "Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", - "dso-selector.claim.item.create-from-scratch": "Utwórz nowy", - "dso-selector.claim.item.not-mine-label": "Żaden nie jest mój", - "dso-selector.create.collection.head": "Nowa kolekcja", - "dso-selector.create.collection.sub-level": "Utwórz nową kolekcję w", - "dso-selector.create.community.head": "Nowy zbiór", - "dso-selector.create.community.sub-level": "Utwórz nowy zbiór", - "dso-selector.create.community.top-level": "Utwórz nowy nadrzędny zbiór", - "dso-selector.create.item.head": "Nowa pozycja", - "dso-selector.create.item.sub-level": "Utwórz nową pozycję w", - "dso-selector.create.submission.head": "Nowe zgłoszenie", - "dso-selector.edit.collection.head": "Edytuj kolekcję", - "dso-selector.edit.community.head": "Edytuj zbiór", - "dso-selector.edit.item.head": "Edytuj pozycję", - "dso-selector.error.title": "Wystąpił błąd podczas wyszukiwania typu {{ type }}", - "dso-selector.export-metadata.dspaceobject.head": "Eksportuj metadane z", - "dso-selector.no-results": "Nie znaleziono {{ type }}", - "dso-selector.placeholder": "Wyszukaj {{ type }}", - "dso-selector.select.collection.head": "Wybierz kolekcję", - "dso-selector.set-scope.community.head": "Wybierz wyszukiwanie zakresu", - "dso-selector.set-scope.community.button": "Wyszukaj w całym DSpace", - "dso-selector.set-scope.community.input-header": "Wyszukaj zbiór lub kolekcję", - "confirmation-modal.export-metadata.header": "Eksportuj metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.info": "Czy na pewno chcesz eksportować metadane z {{ dsoName }}", - "confirmation-modal.export-metadata.cancel": "Anuluj", - "confirmation-modal.export-metadata.confirm": "Eksportuj", - "confirmation-modal.delete-eperson.header": "Usuń użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.info": "Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.cancel": "Anuluj", - "confirmation-modal.delete-eperson.confirm": "Usuń", - "error.bitstream": "Wystąpił błąd podczas tworzenia plików", - "error.browse-by": "Wystąpił błąd podczas tworzenia pozycji", - "error.collection": "Wystąpił błąd podczas tworzenia kolekcji", - "error.collections": "Wystąpił błąd podczas tworzenia kolekcji", - "error.community": "Wystąpił błąd podczas tworzenia ziboru", - "error.identifier": "Nie znaleziono pozycji z podanym identyfikatorem", - "error.default": "Błąd", - "error.item": "Wystąpił błąd podczas tworzenia pozycji", - "error.items": "Wystąpił błąd podczas tworzenia pozycji", - "error.objects": "Wystąpił błąd podczas tworzenia obiektów", - "error.recent-submissions": "Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", - "error.search-results": "Wystąpił błąd podczas tworzenia wyników wyszukiwania", - "error.sub-collections": "Wystąpił błąd podczas tworzenia podkolekcji", - "error.sub-communities": "Wystąpił błąd podczas tworzenia podzbiorów", - "error.submission.sections.init-form-error": "Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", - "error.top-level-communities": "Błąd podczas pobierania nadrzędnego zbioru", - "error.validation.license.notgranted": "Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", - "error.validation.pattern": "Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", - "error.validation.filerequired": "Przesłanie pliku jest obowiązkowe", - "error.validation.required": "Pole jest wymagane", - "error.validation.NotValidEmail": "E-mail nie jest poprawny", - "error.validation.emailTaken": "E-mail jest już zarejestrowany", - "error.validation.groupExists": "Ta grupa już istnieje", - "file-section.error.header": "Błąd podczas uzyskiwania plików dla tej pozycji", - "footer.copyright": "copyright © 2002-{{ year }}", - "footer.link.dspace": "oprogramowanie DSpace", - "footer.link.lyrasis": "LYRASIS", - "footer.link.cookies": "Ustawienia plików cookies", - "footer.link.privacy-policy": "Polityka prywatności", - "footer.link.end-user-agreement": "Umowa użytkownika", - "forgot-email.form.header": "Nie pamiętam hasła", - "forgot-email.form.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "forgot-email.form.email": "Adres e-mail *", - "forgot-email.form.email.error.required": "Uzupełnij adres e-mail", - "forgot-email.form.email.error.pattern": "Uzupełnij prawidłowy adres e-mail", - "forgot-email.form.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "forgot-email.form.submit": "Wyślij", - "forgot-email.form.success.head": "Wysłano wiadomość weryfikacyjną", - "forgot-email.form.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "forgot-email.form.error.head": "Błąd podczas rejestracji adresu e-mail", - "forgot-email.form.error.content": "Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", - "forgot-password.title": "Nie pamiętam hasła", - "forgot-password.form.head": "Nie pamiętam hasła", - "forgot-password.form.info": "Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", - "forgot-password.form.card.security": "Bezpieczeństwo", - "forgot-password.form.identification.header": "Identifikacja", - "forgot-password.form.identification.email": "Adres e-mail: ", - "forgot-password.form.label.password": "Hasło", - "forgot-password.form.label.passwordrepeat": "Potwierdź hasło", - "forgot-password.form.error.empty-password": "Wpisz hasło poniżej.", - "forgot-password.form.error.matching-passwords": "Hasła nie są identyczne.", - "forgot-password.form.notification.error.title": "Błąd podczas próby ustawienia nowego hasła", - "forgot-password.form.notification.success.content": "Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", - "forgot-password.form.notification.success.title": "Resetowanie hasła udane", - "forgot-password.form.submit": "Wpisz hasło", - "form.add": "Dodaj", - "form.add-help": "Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", - "form.cancel": "Anuluj", - "form.clear": "Wyczyść", - "form.clear-help": "Kliknij tutaj, aby usunąć wybraną wartość", - "form.discard": "Odrzuć", - "form.drag": "Przeciągnij", - "form.edit": "Edytuj", - "form.edit-help": "Kliknij tutaj, aby edytować wybraną wartość", - "form.first-name": "Imię", - "form.last-name": "Nazwisko", - "form.loading": "Ładowanie...", - "form.lookup": "Przeglądaj", - "form.lookup-help": "Kliknij tutaj, aby zobaczyć istniejące powiązania", - "form.no-results": "Nie znaleziono rezultatów", - "form.no-value": "Nie wprowadzono wartości", - "form.remove": "Usuń", - "form.save": "Zapisz", - "form.save-help": "Zapisz zmiany", - "form.search": "Wyszukaj", - "form.search-help": "Kliknij tutaj, aby wyszukać w istniejących komentarzach", - "form.submit": "Zapisz", - "form.repeatable.sort.tip": "Upuść nową pozycję w nowym miejscu", - "grant-deny-request-copy.deny": "Nie przesyłaj kopii", - "grant-deny-request-copy.email.back": "Cofnij", - "grant-deny-request-copy.email.message": "Wiadomości", - "grant-deny-request-copy.email.message.empty": "Proszę wprowadzić wiadomość", - "grant-deny-request-copy.email.permissions.info": "W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", - "grant-deny-request-copy.email.permissions.label": "Ustaw jako otwarty dostęp", - "grant-deny-request-copy.email.send": "Wyślij", - "grant-deny-request-copy.email.subject": "Temat", - "grant-deny-request-copy.email.subject.empty": "Wpisz temat", - "grant-deny-request-copy.grant": "Wyślij kopię", - "grant-deny-request-copy.header": "Prośba o przesłanie kopii dokumentu", - "grant-deny-request-copy.home-page": "Zabierz mnie na stronę główną", - "grant-deny-request-copy.intro1": "Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", - "grant-deny-request-copy.intro2": "Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", - "grant-deny-request-copy.processed": "Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", - "grant-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", - "grant-request-copy.email.subject": "Prośba o kopię dokumentu", - "grant-request-copy.error": "Wystąpił błąd", - "grant-request-copy.header": "Zezwól na wysłanie kopii dokumentu", - "grant-request-copy.intro": "To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", - "grant-request-copy.success": "Prośba o dostęp do dokumentu została przyjęta", - "home.description": "", - "home.breadcrumbs": "Strona główna", - "home.search-form.placeholder": "Przeszukaj repozytorium...", - "home.title": "Strona główna", - "home.top-level-communities.head": "Zbiory w DSpace", - "home.top-level-communities.help": "Przeszukaj kolekcje", - "info.end-user-agreement.accept": "Przeczytałem/am i akceptuję umowę użytkownika", - "info.end-user-agreement.accept.error": "Błąd wystąpił podczas akceptowania umowy użytkownika", - "info.end-user-agreement.accept.success": "Udało się zaktualizować umowę użytkownika", - "info.end-user-agreement.breadcrumbs": "Umowa użytkownika", - "info.end-user-agreement.buttons.cancel": "Anuluj", - "info.end-user-agreement.buttons.save": "Zapisz", - "info.end-user-agreement.head": "Umowa użytkownika", - "info.end-user-agreement.title": "Umowa użytkownika", - "info.privacy.breadcrumbs": "Oświadczenie polityki prywatności", - "info.privacy.head": "Oświadczenie polityki prywatności", - "info.privacy.title": "Oświadczenie polityki prywatności", - "item.alerts.private": "Ta pozycja jest prywatna", - "item.alerts.withdrawn": "Ta pozycja została wycofana", - "item.edit.authorizations.heading": "Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", - "item.edit.authorizations.title": "Edytuj politykę tej pozycji", - "item.badge.private": "Prywatny status publikacji", - "item.badge.withdrawn": "Wycofane publikacje", - "item.bitstreams.upload.bundle": "Pakiet", - "item.bitstreams.upload.bundle.placeholder": "Wybierz pakiet", - "item.bitstreams.upload.bundle.new": "Utworz pakiet", - "item.bitstreams.upload.bundles.empty": "Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", - "item.bitstreams.upload.cancel": "Anuluj", - "item.bitstreams.upload.drop-message": "Upuść plik, aby przesłać", - "item.bitstreams.upload.item": "Pozycja: ", - "item.bitstreams.upload.notifications.bundle.created.content": "Udało się utworzyć nowy pakiet.", - "item.bitstreams.upload.notifications.bundle.created.title": "Utwórz pakiet", - "item.bitstreams.upload.notifications.upload.failed": "Zweryfikuj pliki przed spróbowaniem ponownie.", - "item.bitstreams.upload.title": "Prześlij strumień bitów", - "item.edit.bitstreams.bundle.edit.buttons.upload": "Prześlij", - "item.edit.bitstreams.bundle.displaying": "Obecnie wyświetlono {{ amount }} plików z {{ total }}.", - "item.edit.bitstreams.bundle.load.all": "Załaduj wszystkie ({{ total }})", - "item.edit.bitstreams.bundle.load.more": "Załaduj więcej", - "item.edit.bitstreams.bundle.name": "PACZKA: {{ name }}", - "item.edit.bitstreams.discard-button": "Odrzuć", - "item.edit.bitstreams.edit.buttons.download": "Pobierz", - "item.edit.bitstreams.edit.buttons.drag": "Przeciągnij", - "item.edit.bitstreams.edit.buttons.edit": "Edytuj", - "item.edit.bitstreams.edit.buttons.remove": "Usuń", - "item.edit.bitstreams.edit.buttons.undo": "Cofnij zmiany", - "item.edit.bitstreams.empty": "Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", - "item.edit.bitstreams.headers.actions": "Akcje", - "item.edit.bitstreams.headers.bundle": "Paczka", - "item.edit.bitstreams.headers.description": "Opis", - "item.edit.bitstreams.headers.format": "Format", - "item.edit.bitstreams.headers.name": "Nazwa", - "item.edit.bitstreams.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", - "item.edit.bitstreams.notifications.discarded.title": "Zmiany odrzucone", - "item.edit.bitstreams.notifications.move.failed.title": "Błąd podczas przenoszenia plików", - "item.edit.bitstreams.notifications.move.saved.content": "Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", - "item.edit.bitstreams.notifications.move.saved.title": "Zmiana pozycji została zapisana", - "item.edit.bitstreams.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", - "item.edit.bitstreams.notifications.outdated.title": "Zmiany nieaktualne", - "item.edit.bitstreams.notifications.remove.failed.title": "Błąd podczas usuwania pliku", - "item.edit.bitstreams.notifications.remove.saved.content": "Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", - "item.edit.bitstreams.notifications.remove.saved.title": "Zmiany dotyczące usunięcia zapisane", - "item.edit.bitstreams.reinstate-button": "Cofnij", - "item.edit.bitstreams.save-button": "Zapisz", - "item.edit.bitstreams.upload-button": "Prześlij", - "item.edit.delete.cancel": "Anuluj", - "item.edit.delete.confirm": "Usuń", - "item.edit.delete.description": "Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", - "item.edit.delete.error": "Błąd wystąpił podczas usuwania pozycji", - "item.edit.delete.header": "Usuń pozycję: {{ id }}", - "item.edit.delete.success": "Ta pozycja została usunięta", - "item.edit.head": "Edytuj pozycję", - "item.edit.breadcrumbs": "Edytuj pozycję", - "item.edit.tabs.disabled.tooltip": "Nie masz dostępu do tej strony", - "item.edit.tabs.mapper.head": "Mapper kolekcji", - "item.edit.tabs.item-mapper.title": "Edytowanie pozycji - Mapper kolekcji", - "item.edit.item-mapper.buttons.add": "Mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.buttons.remove": "Usuń mapowanie pozycji do wybranych kolekcji", - "item.edit.item-mapper.cancel": "Anuluj", - "item.edit.item-mapper.description": "To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", - "item.edit.item-mapper.head": "Mapper pozycji - Mapowanie pozycji do kolekcji", - "item.edit.item-mapper.item": "Pozycja: \"<b>{{name}}</b>\"", - "item.edit.item-mapper.no-search": "Wpisz zapytanie, które chcesz wyszukać", - "item.edit.item-mapper.notifications.add.error.content": "Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.add.error.head": "Błędy mapowania", - "item.edit.item-mapper.notifications.add.success.content": "Udało się zmapować elementy dla {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.add.success.head": "Mapowanie zakończone", - "item.edit.item-mapper.notifications.remove.error.content": "Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", - "item.edit.item-mapper.notifications.remove.error.head": "Usunięcie mapowania błędów", - "item.edit.item-mapper.notifications.remove.success.content": "Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", - "item.edit.item-mapper.notifications.remove.success.head": "Usuwanie mapowania zakończone", - "item.edit.item-mapper.search-form.placeholder": "Przeszukaj kolekcje...", - "item.edit.item-mapper.tabs.browse": "Przeglądaj zmapowane kolekcje", - "item.edit.item-mapper.tabs.map": "Mapuj nowe kolekcje", - "item.edit.metadata.add-button": "Dodaj", - "item.edit.metadata.discard-button": "Odrzuć", - "item.edit.metadata.edit.buttons.edit": "Edytuj", - "item.edit.metadata.edit.buttons.remove": "Usuń", - "item.edit.metadata.edit.buttons.undo": "Cofnij zmiany", - "item.edit.metadata.edit.buttons.unedit": "Zatrzymaj edycję", - "item.edit.metadata.empty": "Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", - "item.edit.metadata.headers.edit": "Edytuj", - "item.edit.metadata.headers.field": "Pole", - "item.edit.metadata.headers.language": "Język", - "item.edit.metadata.headers.value": "Wartość", - "item.edit.metadata.metadatafield.invalid": "Wybierz aktualne pole metadanych", - "item.edit.metadata.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", - "item.edit.metadata.notifications.discarded.title": "Zmiany odrzucone", - "item.edit.metadata.notifications.error.title": "Wystąpił błąd", - "item.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", - "item.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadane", - "item.edit.metadata.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", - "item.edit.metadata.notifications.outdated.title": "Zmiany nieaktualne", - "item.edit.metadata.notifications.saved.content": "Twoje zmiany metadanych tej pozycji zostały zapisane.", - "item.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", - "item.edit.metadata.reinstate-button": "Cofnij", - "item.edit.metadata.save-button": "Zapisz", - "item.edit.modify.overview.field": "Pole", - "item.edit.modify.overview.language": "Język", - "item.edit.modify.overview.value": "Wartość", - "item.edit.move.cancel": "Anuluj", - "item.edit.move.save-button": "Zapisz", - "item.edit.move.discard-button": "Odrzuć", - "item.edit.move.description": "Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", - "item.edit.move.error": "Wystąpił błąd podczas przenoszenia pozycji", - "item.edit.move.head": "Przenieś pozycję: {{id}}", - "item.edit.move.inheritpolicies.checkbox": "Dziedziczenie polityk", - "item.edit.move.inheritpolicies.description": "Dziedzczenie domyślnych polityk z kolekcji docelowej", - "item.edit.move.move": "Przenieś", - "item.edit.move.processing": "Przenoszenie...", - "item.edit.move.search.placeholder": "Wpisz zapytanie, aby wyszukać w kolekcjach", - "item.edit.move.success": "Pozycja została przeniesiona", - "item.edit.move.title": "Przenieś pozycję", - "item.edit.private.cancel": "Anuluj", - "item.edit.private.confirm": "Ukryj", - "item.edit.private.description": "Czy chcesz ukryć tę pozycję?", - "item.edit.private.error": "Wystąpił błąd podczas ukrywania pozycji", - "item.edit.private.header": "Ukryj pozycję: {{ id }}", - "item.edit.private.success": "Pozycja jest teraz ukryta", - "item.edit.public.cancel": "Anuluj", - "item.edit.public.confirm": "Upublicznij", - "item.edit.public.description": "Czy chcesz upublicznić tę pozycję?", - "item.edit.public.error": "Wystąpił błąd podczas upubliczniania pozycji", - "item.edit.public.header": "Upublicznij pozycję: {{ id }}", - "item.edit.public.success": "Pozycja jest teraz publiczna", - "item.edit.reinstate.cancel": "Anuluj", - "item.edit.reinstate.confirm": "Przywróć", - "item.edit.reinstate.description": "Czy chcesz przywrócić tę pozycję?", - "item.edit.reinstate.error": "Wystąpił błąd podczas przywracania pozycji", - "item.edit.reinstate.header": "Przywróć pozycję: {{ id }}", - "item.edit.reinstate.success": "Pozycja została przywrócona", - "item.edit.relationships.discard-button": "Odrzuć", - "item.edit.relationships.edit.buttons.add": "Dodaj", - "item.edit.relationships.edit.buttons.remove": "Usuń", - "item.edit.relationships.edit.buttons.undo": "Cofnij zmiany", - "item.edit.relationships.no-relationships": "Brak relacji", - "item.edit.relationships.notifications.discarded.content": "Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", - "item.edit.relationships.notifications.discarded.title": "Zmiany zostały cofnięte", - "item.edit.relationships.notifications.failed.title": "Wystąpił błąd podczas edytowania relacji", - "item.edit.relationships.notifications.outdated.content": "Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", - "item.edit.relationships.notifications.outdated.title": "Zmiany są nieaktualne", - "item.edit.relationships.notifications.saved.content": "Twoje zmiany w relacjach tej pozycji zostały zapisane.", - "item.edit.relationships.notifications.saved.title": "Relacje zostały zapisane", - "item.edit.relationships.reinstate-button": "Cofnij", - "item.edit.relationships.save-button": "Zapisz", - "item.edit.relationships.no-entity-type": "Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", - "item.edit.return": "Cofnij", - "item.edit.tabs.bitstreams.head": "Pliki", - "item.edit.tabs.bitstreams.title": "Edycja pozycji - pliki", - "item.edit.tabs.curate.head": "Administruj", - "item.edit.tabs.curate.title": "Edytowanie pozycji - administruj", - "item.edit.tabs.metadata.head": "Metadane", - "item.edit.tabs.metadata.title": "Edycja pozycji - metadane", - "item.edit.tabs.relationships.head": "Relacje", - "item.edit.tabs.relationships.title": "Edycja pozycja - relacje", - "item.edit.tabs.status.buttons.authorizations.button": "Dostępy...", - "item.edit.tabs.status.buttons.authorizations.label": "Określu dostęp do pozycji", - "item.edit.tabs.status.buttons.delete.button": "Usuń permanentnie", - "item.edit.tabs.status.buttons.delete.label": "Usuń pozycję permanentnie", - "item.edit.tabs.status.buttons.mappedCollections.button": "Zmapowane kolekcje", - "item.edit.tabs.status.buttons.mappedCollections.label": "Zarządzaj mapowanymi kolekcjami", - "item.edit.tabs.status.buttons.move.button": "Przenieś...", - "item.edit.tabs.status.buttons.move.label": "Przenieś pozycję do innej kolekcji", - "item.edit.tabs.status.buttons.private.button": "Ukryj...", - "item.edit.tabs.status.buttons.private.label": "Ukry pozycję", - "item.edit.tabs.status.buttons.public.button": "Upublicznij...", - "item.edit.tabs.status.buttons.public.label": "Upublicznij pozycję", - "item.edit.tabs.status.buttons.reinstate.button": "Przywróć...", - "item.edit.tabs.status.buttons.reinstate.label": "Przywróć pozycję", - "item.edit.tabs.status.buttons.unauthorized": "You're not authorized to perform this action", - "item.edit.tabs.status.buttons.withdraw.button": "Wycofaj...", - "item.edit.tabs.status.buttons.withdraw.label": "Wycofaj z repozytorium", - "item.edit.tabs.status.description": "Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", - "item.edit.tabs.status.head": "Status", - "item.edit.tabs.status.labels.handle": "Identyfikator", - "item.edit.tabs.status.labels.id": "ID pozycji", - "item.edit.tabs.status.labels.itemPage": "Strona pozycji", - "item.edit.tabs.status.labels.lastModified": "Ostatnia modyfikacja", - "item.edit.tabs.status.title": "Edycja pozycji - Status", - "item.edit.tabs.versionhistory.head": "Historia wersji", - "item.edit.tabs.versionhistory.title": "Edycja pozycji - historia wersji", - "item.edit.tabs.versionhistory.under-construction": "Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", - "item.edit.tabs.view.head": "Widok pozycji", - "item.edit.tabs.view.title": "Edycja pozycji - widok", - "item.edit.withdraw.cancel": "Anuluj", - "item.edit.withdraw.confirm": "Wycofaj", - "item.edit.withdraw.description": "Czy na pewno chcesz wycofać pozycję?", - "item.edit.withdraw.error": "Wystąpił błąd podczas wycofywania pozycji", - "item.edit.withdraw.header": "Wycofaj pozycję: {{ id }}", - "item.edit.withdraw.success": "Pozycja została wycofana", - "item.listelement.badge": "Pozycja", - "item.page.description": "Opis", - "item.page.journal-issn": "ISSN czasopisma", - "item.page.journal-title": "Tytuł czasopisma", - "item.page.publisher": "Wydawca", - "item.page.titleprefix": "Pozycja: ", - "item.page.volume-title": "Tytuł tomu", - "item.search.results.head": "Wyniki wyszukiwania pozycji", - "item.search.title": "Wyszukiwanie pozycji", - "item.page.abstract": "Abstrakt", - "item.page.author": "Autorzy", - "item.page.citation": "Cytowanie", - "item.page.collections": "Kolekcje", - "item.page.collections.loading": "Ładowanie...", - "item.page.collections.load-more": "Załaduj więcej", - "item.page.date": "Data", - "item.page.edit": "Edytuj pozycję", - "item.page.files": "Pliki", - "item.page.filesection.description": "Opis:", - "item.page.filesection.download": "Pobierz", - "item.page.filesection.format": "Format:", - "item.page.filesection.name": "Nazwa:", - "item.page.filesection.size": "Rozmiar:", - "item.page.journal.search.title": "Artykuły w czasopiśmie", - "item.page.link.full": "Zobacz szczegóły", - "item.page.link.simple": "Uproszczony widok", - "item.page.person.search.title": "Artykuły tego autora", - "item.page.related-items.view-more": "Pokaż o {{ amount }} więcej", - "item.page.related-items.view-less": "Ukryj {{ amount }}", - "item.page.relationships.isAuthorOfPublication": "Publikacje", - "item.page.relationships.isJournalOfPublication": "Publikacje", - "item.page.relationships.isOrgUnitOfPerson": "Autorzy", - "item.page.relationships.isOrgUnitOfProject": "Projekty naukowe", - "item.page.subject": "Słowa kluczowe", - "item.page.uri": "URI", - "item.page.bitstreams.view-more": "Pokaż więcej", - "item.page.bitstreams.collapse": "Pokaż mniej", - "item.page.filesection.original.bundle": "Oryginalne pliki", - "item.page.filesection.license.bundle": "Licencja", - "item.page.return": "Powrót", - "item.page.version.create": "Utwórz nową wersję", - "item.page.version.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.preview.dc.identifier.doi": "DOI", - "item.preview.dc.relation.ispartof": "Czasopismo lub seria", - "item.preview.dc.identifier.isbn": "ISBN", - "item.preview.dc.identifier.uri": "Identyfikator:", - "item.preview.dc.contributor.author": "Autorzy:", - "item.preview.dc.date.issued": "Data publikacji:", - "item.preview.dc.description.abstract": "Abstrakt:", - "item.preview.dc.identifier.other": "Inny identyfikator:", - "item.preview.dc.language.iso": "Język:", - "item.preview.dc.title": "Tytuł:", - "item.preview.dc.title.alternative": "Tytuł alternatywny", - "item.preview.dc.type": "Typ:", - "item.preview.dc.identifier": "Identyfikator:", - "item.preview.dc.relation.issn": "ISSN", - "item.preview.oaire.citation.issue": "Numer wydania", - "item.preview.oaire.citation.volume": "Numer tomu", - "item.preview.person.familyName": "Nazwisko:", - "item.preview.person.givenName": "Nazwa:", - "item.preview.person.identifier.orcid": "ORCID:", - "item.preview.project.funder.name": "Fundator:", - "item.preview.project.funder.identifier": "Identyfikator fundatora:", - "item.preview.oaire.awardNumber": "ID finansowania:", - "item.preview.dc.coverage.spatial": "Jurysdykcja:", - "item.preview.oaire.fundingStream": "Źródło finansowania:", - "item.select.confirm": "Potwierdź zaznaczone", - "item.select.empty": "Brak pozycji do wyświetlenia", - "item.select.table.author": "Autor", - "item.select.table.collection": "Kolekcja", - "item.select.table.title": "Tytuł", - "item.version.history.empty": "Jeszcze nie ma innych wersji tej pozycji.", - "item.version.history.head": "Poprzednie wersje", - "item.version.history.return": "Powrót", - "item.version.history.selected": "Wybrane wersje", - "item.version.history.selected.alert": "W tym momencie wyświetlono wersję {{version}} pozycji.", - "item.version.history.table.version": "Wersja", - "item.version.history.table.item": "Pozycja", - "item.version.history.table.editor": "Redaktor", - "item.version.history.table.date": "Data", - "item.version.history.table.summary": "Podsumowanie", - "item.version.history.table.workspaceItem": "Wersja robocza", - "item.version.history.table.workflowItem": "Pozycja workflow", - "item.version.history.table.actions": "Akcja", - "item.version.history.table.action.editWorkspaceItem": "Edytuj wersję roboczą pozycji", - "item.version.history.table.action.editSummary": "Edytuj podsumowanie", - "item.version.history.table.action.saveSummary": "Zapisz edycje podsumowania", - "item.version.history.table.action.discardSummary": "Odrzuć edycje podsumowania", - "item.version.history.table.action.newVersion": "Utwórz nową wersję z tej wersji", - "item.version.history.table.action.deleteVersion": "Wersja usunięta", - "item.version.history.table.action.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", - "item.version.notice": "To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", - "item.version.create.modal.header": "Nowa wersja", - "item.version.create.modal.text": "Utwórz nową wersję tej pozycji", - "item.version.create.modal.text.startingFrom": "zaczynając od wersji {{version}}", - "item.version.create.modal.button.confirm": "Utwórz", - "item.version.create.modal.button.confirm.tooltip": "Utwórz nową wersję", - "item.version.create.modal.button.cancel": "Anuluj", - "item.version.create.modal.button.cancel.tooltip": "Nie stwarzaj nowej wersji", - "item.version.create.modal.form.summary.label": "Podsumowanie", - "item.version.create.modal.form.summary.placeholder": "Wprowadź podsumowanie nowej wersji", - "item.version.create.notification.success": "Nowa wersja została utworzona z numerem {{version}}", - "item.version.create.notification.failure": "Nowa wersja nie została utworzona", - "item.version.create.notification.inProgress": "Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", - "item.version.delete.modal.header": "Usuń wersję", - "item.version.delete.modal.text": "Czy chcesz usunąć wersję {{version}}?", - "item.version.delete.modal.button.confirm": "Usuń", - "item.version.delete.modal.button.confirm.tooltip": "Usuń wersję", - "item.version.delete.modal.button.cancel": "Anuluj", - "item.version.delete.modal.button.cancel.tooltip": "Nie usuwaj tej wersji", - "item.version.delete.notification.success": "Wersja {{version}} została usunięta", - "item.version.delete.notification.failure": "Wersja {{version}} nie została usunięta", - "item.version.edit.notification.success": "Podsumowanie wersji {{version}} zostało zmienione", - "item.version.edit.notification.failure": "Podsumowanie wersji {{version}} nie zostało zmienione", - "journal.listelement.badge": "Czasopismo", - "journal.page.description": "Opis", - "journal.page.edit": "Edytuj tę pozycję", - "journal.page.editor": "Redaktor naczelny", - "journal.page.issn": "ISSN", - "journal.page.publisher": "Wydawca", - "journal.page.titleprefix": "Czasopismo: ", - "journal.search.results.head": "Wyniki wyszukiwania czasopism", - "journal.search.title": "Wyszukiwanie czasopism", - "journalissue.listelement.badge": "Numer czasopisma", - "journalissue.page.description": "Opis", - "journalissue.page.edit": "Edytuj pozycję", - "journalissue.page.issuedate": "Data wydania", - "journalissue.page.journal-issn": "ISSN czasopisma", - "journalissue.page.journal-title": "Tytuł czasopisma", - "journalissue.page.keyword": "Słowa kluczowe", - "journalissue.page.number": "Numer", - "journalissue.page.titleprefix": "Wydanie czasopisma: ", - "journalvolume.listelement.badge": "Numer tomu czasopisma", - "journalvolume.page.description": "Opis", - "journalvolume.page.edit": "Edytuj pozycję", - "journalvolume.page.issuedate": "Data wydania", - "journalvolume.page.titleprefix": "Numer tomu czasopisma: ", - "journalvolume.page.volume": "Numer wydania", - "iiifsearchable.listelement.badge": "Multimedia dokumentu", - "iiifsearchable.page.titleprefix": "Dokument: ", - "iiifsearchable.page.doi": "Stały link: ", - "iiifsearchable.page.issue": "Wydanie: ", - "iiifsearchable.page.description": "Opis: ", - "iiifviewer.fullscreen.notice": "Wyświetl na pełnym ekranie dla lepszego widoku.", - "iiif.listelement.badge": "Multimedia obrazu", - "iiif.page.titleprefix": "Obraz: ", - "iiif.page.doi": "Stały link: ", - "iiif.page.issue": "Numer wydania: ", - "iiif.page.description": "Opis: ", - "loading.bitstream": "Ładowanie pliku...", - "loading.bitstreams": "Ładowanie plików...", - "loading.browse-by": "Ładowanie pozycji...", - "loading.browse-by-page": "Ładowanie strony...", - "loading.collection": "Ładowanie kolekcji...", - "loading.collections": "Ładowanie kolekcji...", - "loading.content-source": "Ładowanie źródła treści...", - "loading.community": "Ładowanie zbioru...", - "loading.default": "Ładowanie...", - "loading.item": "Ładowanie pozycji...", - "loading.items": "Ładowanie pozycji...", - "loading.mydspace-results": "Ładowanie pozycji...", - "loading.objects": "Ładowanie...", - "loading.recent-submissions": "Ładowanie ostatnich zgłoszeń...", - "loading.search-results": "Ładowanie wyników wyszukiwania...", - "loading.sub-collections": "Ładowanie podkolekcji...", - "loading.sub-communities": "Ładowanie podzbioru...", - "loading.top-level-communities": "Ładowanie zbioru wyszego szczebla...", - "login.form.email": "Adres e-mail", - "login.form.forgot-password": "Nie pamiętasz hasła?", - "login.form.header": "Zaloguj się do DSpace", - "login.form.new-user": "Nie masz konta? Zarejestruj się.", - "login.form.or-divider": "lub", - "login.form.orcid": "Zaloguj za pomocą ORCID", - "login.form.oidc": "Zaloguj za pomocą OIDC", - "login.form.password": "Hasło", - "login.form.shibboleth": "Zaloguj za pomocą Shibboleth", - "login.form.submit": "Zaloguj się", - "login.title": "Zaloguj", - "login.breadcrumbs": "Zaloguj", - "logout.form.header": "Wyloguj się z DSpace", - "logout.form.submit": "Wyloguj się", - "logout.title": "Wylogowywanie", - "menu.header.admin": "Panel administracyjny", - "menu.header.image.logo": "Logo repozytorium", - "menu.header.admin.description": "Menu administratora", - "menu.section.access_control": "Uprawnienia", - "menu.section.access_control_authorizations": "Dostępy", - "menu.section.access_control_groups": "Grupy", - "menu.section.access_control_people": "Użytkownicy", - "menu.section.admin_search": "Wyszukiwanie administracyjne", - "menu.section.browse_community": "Ten zbiór", - "menu.section.browse_community_by_author": "Wg autorów", - "menu.section.browse_community_by_issue_date": "Wg daty wydania", - "menu.section.browse_community_by_title": "Wg tytułów", - "menu.section.browse_global": "Wszystko na DSpace", - "menu.section.browse_global_by_author": "Wg autorów", - "menu.section.browse_global_by_dateissued": "Wg daty wydania", - "menu.section.browse_global_by_subject": "Wg tematu", - "menu.section.browse_global_by_title": "Wg tytułu", - "menu.section.browse_global_communities_and_collections": "Zbiory i kolekcje", - "menu.section.control_panel": "Panel sterowania", - "menu.section.curation_task": "Zadanie administracyjne", - "menu.section.edit": "Edytuj", - "menu.section.edit_collection": "Kolekcja", - "menu.section.edit_community": "Zbiór", - "menu.section.edit_item": "Pozycja", - "menu.section.export": "Eksport", - "menu.section.export_collection": "Kolekcja", - "menu.section.export_community": "Zbiór", - "menu.section.export_item": "Pozycja", - "menu.section.export_metadata": "Metadane", - "menu.section.icon.access_control": "Sekcja menu Uprawnienia", - "menu.section.icon.admin_search": "Sekcja menu Wyszukiwanie administracyjne", - "menu.section.icon.control_panel": "Sekcja menu Panel sterowania", - "menu.section.icon.curation_tasks": "Sekcja menu Zadanie administracyjne", - "menu.section.icon.edit": "Sekcja menu Edycja", - "menu.section.icon.export": "Sekcja menu Eksport", - "menu.section.icon.find": "Sekcja menu Wyszukiwanie", - "menu.section.icon.import": "Sekcja menu Import", - "menu.section.icon.new": "Sekcja menu Dodaj", - "menu.section.icon.pin": "Przypnij boczny pasek", - "menu.section.icon.processes": "Sekcja menu Procesy", - "menu.section.icon.registries": "Sekcja menu Rejestry", - "menu.section.icon.statistics_task": "Sekcja menu Zadanie statystyczne", - "menu.section.icon.workflow": "Sekcja menu Zarządzanie workflow", - "menu.section.icon.unpin": "Odepnij boczny pasek", - "menu.section.import": "Import", - "menu.section.import_batch": "Import masowy (ZIP)", - "menu.section.import_metadata": "Metadane", - "menu.section.new": "Dodaj", - "menu.section.new_collection": "Kolekcja", - "menu.section.new_community": "Zbiór", - "menu.section.new_item": "Pozycja", - "menu.section.new_item_version": "Wersja pozycji", - "menu.section.new_process": "Proces", - "menu.section.pin": "Przypnij pasek boczny", - "menu.section.unpin": "Odepnij pasek boczny", - "menu.section.processes": "Procesy", - "menu.section.registries": "Rejestry", - "menu.section.registries_format": "Formaty", - "menu.section.registries_metadata": "Metadane", - "menu.section.statistics": "Statystyki", - "menu.section.statistics_task": "Zadanie statystyczne", - "menu.section.toggle.access_control": "Przełącz sekcję Uprawnienia", - "menu.section.toggle.control_panel": "Przełącz sekcję Panel sterowania", - "menu.section.toggle.curation_task": "Przełącz sekcję Zadanie kuratora", - "menu.section.toggle.edit": "Przełącz sekcję Edytuj", - "menu.section.toggle.export": "Przełącz sekcję Eksport", - "menu.section.toggle.find": "Przełącz sekcję Wyszukiwanie", - "menu.section.toggle.import": "Przełącz sekcję Import", - "menu.section.toggle.new": "Przełącz nową sekcję", - "menu.section.toggle.registries": "Przełącz sekcję Rejestry", - "menu.section.toggle.statistics_task": "Przełącz sekcję Zadanie statystyczne", - "menu.section.workflow": "Zarządzaj Workflow", - "mydspace.breadcrumbs": "Mój DSpace", - "mydspace.description": "", - "mydspace.messages.controller-help": "Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", - "mydspace.messages.description-placeholder": "Wpisz swoją wiadomość tutaj...", - "mydspace.messages.hide-msg": "Ukryj wiadomość", - "mydspace.messages.mark-as-read": "Oznacz jako przeczytane", - "mydspace.messages.mark-as-unread": "Oznacz jako nieprzeczytane", - "mydspace.messages.no-content": "Brak treści.", - "mydspace.messages.no-messages": "Brak wiadomości.", - "mydspace.messages.send-btn": "Wysłano", - "mydspace.messages.show-msg": "Pokaż wiadomość", - "mydspace.messages.subject-placeholder": "Temat...", - "mydspace.messages.submitter-help": "Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", - "mydspace.messages.title": "Wiadomości", - "mydspace.messages.to": "Do", - "mydspace.new-submission": "Nowe zgłoszenie", - "mydspace.new-submission-external": "Import medatanych z zewnętrznego źródła", - "mydspace.new-submission-external-short": "Import metadanych", - "mydspace.results.head": "Twoje zadania", - "mydspace.results.no-abstract": "Brak abstraktu", - "mydspace.results.no-authors": "Brak autorów", - "mydspace.results.no-collections": "Brak kolekcji", - "mydspace.results.no-date": "Brak daty", - "mydspace.results.no-files": "Brak plików", - "mydspace.results.no-results": "Brak pozycji do wyświetlenia", - "mydspace.results.no-title": "Brak tytułu", - "mydspace.results.no-uri": "Brak Uri", - "mydspace.search-form.placeholder": "Wyszukaj w mydspace...", - "mydspace.show.workflow": "Wszystkie zadania", - "mydspace.show.workspace": "Twoje zadania", - "mydspace.status.mydspaceArchived": "Zarchiwizowano", - "mydspace.status.mydspaceValidation": "Walidacja", - "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redaktora", - "mydspace.status.mydspaceWorkflow": "Workflow", - "mydspace.status.mydspaceWorkspace": "Wersja robocza", - "mydspace.title": "Mój DSpace", - "mydspace.upload.upload-failed": "Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", - "mydspace.upload.upload-failed-manyentries": "Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", - "mydspace.upload.upload-failed-moreonefile": "Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", - "mydspace.upload.upload-multiple-successful": "Utworzono {{qty}} przestrzeni roboczych.", - "mydspace.view-btn": "Widok", - "nav.browse.header": "Cały DSpace", - "nav.community-browse.header": "Wg zbiorów", - "nav.language": "Zmień język", - "nav.login": "Zaloguj", - "nav.logout": "Menu profilu użytkownika i wylogowywanie", - "nav.main.description": "Główny pasek nawigacji", - "nav.mydspace": "Mój DSpace", - "nav.profile": "Profil", - "nav.search": "Wyszukiwanie", - "nav.statistics.header": "Statystyki", - "nav.stop-impersonating": "Przestań impersonifikować użytkownika", - "nav.toggle": "Przełącz nawigację", - "nav.user.description": "Pasek profilu użytkownika", - "none.listelement.badge": "Pozycja", - "person.listelement.badge": "Osoba", - "person.listelement.no-title": "Nie znaleziono imienia", - "person.page.birthdate": "Data urodzenia", - "person.page.edit": "Edytuj pozycję", - "person.page.email": "Adres e-mail", - "person.page.firstname": "Imię", - "person.page.jobtitle": "Stanowisko", - "person.page.lastname": "Nazwisko", - "person.page.link.full": "Pokaż wszystkie metadane", - "person.page.orcid": "ORCID", - "person.page.orcid.create": "Utwórz ORCID ID", - "person.page.orcid.granted-authorizations": "Udzielone dostępy", - "person.page.orcid.grant-authorizations": "Udziel dostępu", - "person.page.orcid.link": "Połącz z ORCID ID", - "person.page.orcid.orcid-not-linked-message": "ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", - "person.page.orcid.unlink": "Odepnij z ORCID", - "person.page.orcid.unlink.processing": "Procesowanie...", - "person.page.orcid.missing-authorizations": "Brak dostępów", - "person.page.orcid.missing-authorizations-message": "Brakuj następujących dostępów:", - "person.page.orcid.no-missing-authorizations-message": "Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", - "person.page.orcid.no-orcid-message": "Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", - "person.page.orcid.profile-preferences": "Preferencje profilu", - "person.page.orcid.funding-preferences": "Preferencje finansowania", - "person.page.orcid.publications-preferences": "Preferencje publikacji", - "person.page.orcid.remove-orcid-message": "Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", - "person.page.orcid.save.preference.changes": "Aktualizuj ustawienia", - "person.page.orcid.sync-profile.affiliation": "Afiliacja", - "person.page.orcid.sync-profile.biographical": "Biografia", - "person.page.orcid.sync-profile.education": "Edukacja", - "person.page.orcid.sync-profile.identifiers": "Identyfikatory", - "person.page.orcid.sync-fundings.all": "Wszystkie źrodła finansowania", - "person.page.orcid.sync-fundings.mine": "Moje źrodła finansowania", - "person.page.orcid.sync-fundings.my_selected": "Wybrane źródła finansowania", - "person.page.orcid.sync-fundings.disabled": "Nieaktywne", - "person.page.orcid.sync-publications.all": "Wszystkie publikacje", - "person.page.orcid.sync-publications.mine": "Moje publikacje", - "person.page.orcid.sync-publications.my_selected": "Wybrane publikacje", - "person.page.orcid.sync-publications.disabled": "Nieaktywne", - "person.page.orcid.sync-queue.discard": "Odrzuć zmianę i nie synchronizuj z ORCID", - "person.page.orcid.sync-queue.discard.error": "Rekord kolejki ORCID nie został odrzucony", - "person.page.orcid.sync-queue.discard.success": "Rekord kolejki ORCID został odrzucony", - "person.page.orcid.sync-queue.empty-message": "Rejestr kolejki w ORCID jest pusty", - "person.page.orcid.sync-queue.description.affiliation": "Afiliacje", - "person.page.orcid.sync-queue.description.country": "Kraj", - "person.page.orcid.sync-queue.description.education": "Edukacja", - "person.page.orcid.sync-queue.description.external_ids": "Zewnętrzne identyfikatory", - "person.page.orcid.sync-queue.description.other_names": "Inne imiona", - "person.page.orcid.sync-queue.description.qualification": "Kwalifikacje", - "person.page.orcid.sync-queue.description.researcher_urls": "URL naukowca", - "person.page.orcid.sync-queue.description.keywords": "Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.insert": "Dodaj nowy wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.update": "Aktualizuj ten wpis w rejestrze ORCID", - "person.page.orcid.sync-queue.tooltip.delete": "Usuń ten wpis z rejestru ORCID", - "person.page.orcid.sync-queue.tooltip.publication": "Publikacja", - "person.page.orcid.sync-queue.tooltip.affiliation": "Afiliacja", - "person.page.orcid.sync-queue.tooltip.education": "Edukacja", - "person.page.orcid.sync-queue.tooltip.qualification": "Kwalifikacje", - "person.page.orcid.sync-queue.tooltip.other_names": "Inna nazwa", - "person.page.orcid.sync-queue.tooltip.country": "Kraj", - "person.page.orcid.sync-queue.tooltip.keywords": "Słowa kluczowe", - "person.page.orcid.sync-queue.tooltip.external_ids": "Zewnętrzny identyfikator", - "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL naukowca", - "person.page.orcid.sync-queue.send": "Synchronizuj z rejestrem ORCID", - "person.page.orcid.sync-queue.send.unauthorized-error.title": "Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", - "person.page.orcid.sync-queue.send.unauthorized-error.content": "Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", - "person.page.orcid.sync-queue.send.bad-request-error": "Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", - "person.page.orcid.sync-queue.send.error": "Wysłanie zgłoszenia do ORCID nie powiodło się", - "person.page.orcid.sync-queue.send.conflict-error": "Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", - "person.page.orcid.sync-queue.send.not-found-warning": "Pozycja nie istnieje już w rejestrze ORCID.", - "person.page.orcid.sync-queue.send.success": "Zgłoszenie do ORCID zostało zakończone pomyślnie", - "person.page.orcid.sync-queue.send.validation-error": "Dane, które chcesz zsynchronizować z ORCID nie są poprawne", - "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Waluta jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", - "person.page.orcid.sync-queue.send.validation-error.title.required": "Tytuł jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.type.required": "Typ jest wymagany", - "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Data początkowa jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.funder.required": "Instytucja finansująca jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.required": "Instytucja jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Nazwa instytucji jest wymagana", - "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Aby wysłać instytucję, należy podać adres", - "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Aby wysłać adres, należy podać miasto", - "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Aby wysłać adres, należy podać kraj", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", - "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Należy uzupełnić wartość w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Należy uzupełnić źródło w identyfikatorze instytucji", - "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", - "person.page.orcid.synchronization-mode": "Tryb synchronizacji", - "person.page.orcid.synchronization-mode.batch": "Wsad", - "person.page.orcid.synchronization-mode.label": "Tryb synchronizacji", - "person.page.orcid.synchronization-mode-message": "Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", - "person.page.orcid.synchronization-settings-update.success": "Opcje synchronizacji zostały zaktualizowane", - "person.page.orcid.synchronization-settings-update.error": "Opcje synchronizacji nie zostały zaktualizowane", - "person.page.orcid.synchronization-mode.manual": "Ręczna", - "person.page.orcid.scope.authenticate": "Uzyskaj swój ORCID iD", - "person.page.orcid.scope.read-limited": "Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", - "person.page.orcid.scope.activities-update": "Dodaj/aktualizuj swoje aktywności naukowe", - "person.page.orcid.scope.person-update": "Dodaj/aktualizuj inne informacje o Tobie", - "person.page.orcid.unlink.success": "Odłączenie Twojego profilu od rejestru ORCID powiodło się", - "person.page.orcid.unlink.error": "Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", - "person.page.staffid": "ID pracownika", - "person.page.titleprefix": "Osoba: ", - "person.search.results.head": "Wyniki wyszukiwania użytkowników", - "person.search.title": "Wyniki wyszukiwania użytkowników", - "process.new.select-parameters": "Parametry", - "process.new.cancel": "Anuluj", - "process.new.submit": "Zapisz", - "process.new.select-script": "Skrypt", - "process.new.select-script.placeholder": "Wybierz skrypt...", - "process.new.select-script.required": "Skrypt jest wymagany", - "process.new.parameter.file.upload-button": "Wybierz plik...", - "process.new.parameter.file.required": "Proszę wybrać plik", - "process.new.parameter.string.required": "Wartość parametru jest wymagana", - "process.new.parameter.type.value": "wartość", - "process.new.parameter.type.file": "plik", - "process.new.parameter.required.missing": "Te parametry są wymagane, ale nie zostały uzupełnione:", - "process.new.notification.success.title": "Udało się", - "process.new.notification.success.content": "Udało się stworzyć proces", - "process.new.notification.error.title": "Błąd", - "process.new.notification.error.content": "Wystąpił błąd podczas tworzenia procesu", - "process.new.header": "Utwórz nowy proces", - "process.new.title": "Utwórz nowy proces", - "process.new.breadcrumbs": "Utwórz nowy proces", - "process.detail.arguments": "Argumenty", - "process.detail.arguments.empty": "Do tego procesu nie zostały przypisane żadne argumenty", - "process.detail.back": "Cofnij", - "process.detail.output": "Dane wyjściowe procesu", - "process.detail.logs.button": "Odzyskaj dane wyjściowe procesu", - "process.detail.logs.loading": "Odzyskiwanie", - "process.detail.logs.none": "Ten proces nie ma danych wyjściowych", - "process.detail.output-files": "Pliki", - "process.detail.output-files.empty": "Ten proces nie ma żadnych plików danych wyjściowych", - "process.detail.script": "Skrypt", - "process.detail.title": "Proces: {{ id }} - {{ name }}", - "process.detail.start-time": "Czas rozpoczęcia procesu", - "process.detail.end-time": "Czas zakończenia procesu", - "process.detail.status": "Status", - "process.detail.create": "Stwórz podobny proces", - "process.overview.table.finish": "Czas zakończenia (UTC)", - "process.overview.table.id": "Identyfikator procesu", - "process.overview.table.name": "Nazwa", - "process.overview.table.start": "Czas rozpoczęcia (UTC)", - "process.overview.table.status": "Status", - "process.overview.table.user": "Użytkownik", - "process.overview.title": "Przegląd procesów", - "process.overview.breadcrumbs": "Przegląd procesów", - "process.overview.new": "Nowy", - "profile.breadcrumbs": "Zaktualizuj profil", - "profile.card.identify": "Dane", - "profile.card.security": "Bezpieczeństwo", - "profile.form.submit": "Zaktualizuj profil", - "profile.groups.head": "Posiadane uprawnienia do kolekcji", - "profile.head": "Zaktualizuj profil", - "profile.metadata.form.error.firstname.required": "Imię jest wymagane", - "profile.metadata.form.error.lastname.required": "Nazwisko jest wymagane", - "profile.metadata.form.label.email": "Adres e-mail", - "profile.metadata.form.label.firstname": "Imię", - "profile.metadata.form.label.language": "Język", - "profile.metadata.form.label.lastname": "Nazwisko", - "profile.metadata.form.label.phone": "Telefon kontaktowy", - "profile.metadata.form.notifications.success.content": "Zmiany w profilu zostały zapisane.", - "profile.metadata.form.notifications.success.title": "Profil zapisany", - "profile.notifications.warning.no-changes.content": "Nie dokonano żadnych zmian w profilu.", - "profile.notifications.warning.no-changes.title": "Brak zmian", - "profile.security.form.error.matching-passwords": "Hasła nie są identyczne.", - "profile.security.form.info": "Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", - "profile.security.form.label.password": "Hasło", - "profile.security.form.label.passwordrepeat": "Potwierdź hasło", - "profile.security.form.notifications.success.content": "Twoje zmiany w haśle zostały zapisane.", - "profile.security.form.notifications.success.title": "Hasło zapisane", - "profile.security.form.notifications.error.title": "Błąd podczas próby zmiany hasła", - "profile.security.form.notifications.error.not-same": "Hasła nie są identyczne.", - "profile.title": "Zaktualizuj profil", - "profile.card.researcher": "Profil naukowca", - "project.listelement.badge": "Projekt badawczy", - "project.page.contributor": "Autorzy", - "project.page.description": "Opis", - "project.page.edit": "Edytuj pozycję", - "project.page.expectedcompletion": "Spodziewany termin zakończenia", - "project.page.funder": "Instytucje finansujące", - "project.page.id": "ID", - "project.page.keyword": "Słowa kluczowe", - "project.page.status": "Status", - "project.page.titleprefix": "Projekt badawczy: ", - "project.search.results.head": "Wyniki wyszukiwania projektów", - "publication.listelement.badge": "Publikacja", - "publication.page.description": "Opis", - "publication.page.edit": "Edytuj pozycję", - "publication.page.journal-issn": "ISSN czasopisma", - "publication.page.journal-title": "Tytuł czasopisma", - "publication.page.publisher": "Wydawca", - "publication.page.titleprefix": "Publikacja: ", - "publication.page.volume-title": "Tytuł tomu", - "publication.search.results.head": "Wyniki wyszukiwania publikacji", - "publication.search.title": "Wyszukiwanie publikacji", - "media-viewer.next": "Nowy", - "media-viewer.previous": "Poprzedni", - "media-viewer.playlist": "Playlista", - "register-email.title": "Rejestracja nowego użytkownika", - "register-page.create-profile.header": "Stwórz profil", - "register-page.create-profile.identification.header": "Dane", - "register-page.create-profile.identification.email": "Adres e-mail", - "register-page.create-profile.identification.first-name": "Imię *", - "register-page.create-profile.identification.first-name.error": "Wpisz imię", - "register-page.create-profile.identification.last-name": "Nazwisko *", - "register-page.create-profile.identification.last-name.error": "Wpisz nazwisko", - "register-page.create-profile.identification.contact": "Telefon kontaktowy", - "register-page.create-profile.identification.language": "Język", - "register-page.create-profile.security.header": "Bezpieczeństwo", - "register-page.create-profile.security.info": "Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", - "register-page.create-profile.security.label.password": "Hasło *", - "register-page.create-profile.security.label.passwordrepeat": "Potwierdź hasło *", - "register-page.create-profile.security.error.empty-password": "Wprowadź hasło w polu poniżej.", - "register-page.create-profile.security.error.matching-passwords": "Hasła nie są identyczne.", - "register-page.create-profile.submit": "Rejestracja zakończona", - "register-page.create-profile.submit.error.content": "Coś się nie udało podczas rejestracji nowego użytkownika.", - "register-page.create-profile.submit.error.head": "Rejestracja nie powiodła się", - "register-page.create-profile.submit.success.content": "Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", - "register-page.create-profile.submit.success.head": "Rejestracja zakończona", - "register-page.registration.header": "Rejestracja nowego użytkownika", - "register-page.registration.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", - "register-page.registration.email": "Adres e-mail *", - "register-page.registration.email.error.required": "Wypełnij adres e-mail", - "register-page.registration.email.error.pattern": "Wypełnij poprawny adres e-mail", - "register-page.registration.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", - "register-page.registration.submit": "Zarejestruj się", - "register-page.registration.success.head": "Wiadomość weryfikacyjna zostałą wysłana", - "register-page.registration.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", - "register-page.registration.error.head": "Błąd podczas próby rejestracji adresu e-mail", - "register-page.registration.error.content": "Błąd podczas próby rejestracji adresu e-mail: {{ email }}", - "relationships.add.error.relationship-type.content": "Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", - "relationships.add.error.server.content": "Błąd serwera", - "relationships.add.error.title": "Nie można dodać relacji", - "relationships.isAuthorOf": "Autorzy", - "relationships.isAuthorOf.Person": "Autorzy (osoby)", - "relationships.isAuthorOf.OrgUnit": "Autorzy (jednostki organizacyjne)", - "relationships.isIssueOf": "Numery czasopisma", - "relationships.isJournalIssueOf": "Numer czasopisma", - "relationships.isJournalOf": "Czasopisma", - "relationships.isOrgUnitOf": "Jednostki organizacyjne", - "relationships.isPersonOf": "Autorzy", - "relationships.isProjectOf": "Projekty badawcze", - "relationships.isPublicationOf": "Publikacje", - "relationships.isPublicationOfJournalIssue": "Artykuły", - "relationships.isSingleJournalOf": "Czasopismo", - "relationships.isSingleVolumeOf": "Tom czasopisma", - "relationships.isVolumeOf": "Tomy czasopisma", - "relationships.isContributorOf": "Autorzy", - "relationships.isContributorOf.OrgUnit": "Autor (Jednostka organizacyjna)", - "relationships.isContributorOf.Person": "Autor", - "relationships.isFundingAgencyOf.OrgUnit": "Instytucja finansująca", - "repository.image.logo": "Logo repozytorium", - "repository.title.prefix": "DSpace Angular :: ", - "researcher.profile.action.processing": "Procesowanie...", - "researcher.profile.associated": "Przypisanie profilu badacza", - "researcher.profile.create.new": "Utwórz nowy", - "researcher.profile.create.success": "Profil badacza został utworzony", - "researcher.profile.create.fail": "Wystąpił błąd poczas tworzenia profilu badacza.", - "researcher.profile.delete": "Usuń", - "researcher.profile.expose": "Ujawnij", - "researcher.profile.hide": "Ukryj", - "researcher.profile.not.associated": "Profil badacza nie został jeszcze przypisany", - "researcher.profile.view": "Widok", - "researcher.profile.private.visibility": "PRYWATNY", - "researcher.profile.public.visibility": "PUBLICZNY", - "researcher.profile.status": "Status:", - "researcherprofile.claim.not-authorized": "Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", - "researcherprofile.error.claim.body": "Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", - "researcherprofile.error.claim.title": "Błąd", - "researcherprofile.success.claim.body": "Wystąpienie z prośbą o przypisanie profilu udane", - "researcherprofile.success.claim.title": "Sukces", - "repository.title.prefixDSpace": "DSpace Angular ::", - "resource-policies.add.button": "Dodaj", - "resource-policies.add.for.": "Dodaj nową politykę", - "resource-policies.add.for.bitstream": "Dodaj nową politykę dla plików", - "resource-policies.add.for.bundle": "Dodaj nową politykę paczek", - "resource-policies.add.for.item": "Dodaj nową politykę pozycji", - "resource-policies.add.for.community": "Dodaj nową politykę zbioru", - "resource-policies.add.for.collection": "Dodaj nową politykę kolekcji", - "resource-policies.create.page.heading": "Utwórz nową politykę zasobu dla ", - "resource-policies.create.page.failure.content": "Wystąpił błąd podczas dodawania polityki zasobów.", - "resource-policies.create.page.success.content": "Działanie powiodło się", - "resource-policies.create.page.title": "Utwórz nową politykę zasobu", - "resource-policies.delete.btn": "Usuń zaznaczone", - "resource-policies.delete.btn.title": "Usuń zaznaczone polityki zasobów", - "resource-policies.delete.failure.content": "Wystąpił błąd podczas usuwania wybranych polityk zasobów.", - "resource-policies.delete.success.content": "Działanie powiodło się", - "resource-policies.edit.page.heading": "Edytuj politykę zasobu ", - "resource-policies.edit.page.failure.content": "Wystąpił błąd poczas edytowania polityki zasobu.", - "resource-policies.edit.page.success.content": "Działanie udało się", - "resource-policies.edit.page.title": "Edytuj politykę zasobu", - "resource-policies.form.action-type.label": "Wybierz ten typ akcji", - "resource-policies.form.action-type.required": "Musisz wybrać akcję polityki zasobu.", - "resource-policies.form.eperson-group-list.label": "Użytkownik lub grupa, która otrzyma uprawnienia.", - "resource-policies.form.eperson-group-list.select.btn": "Wybierz", - "resource-policies.form.eperson-group-list.tab.eperson": "Wyszukaj użytkownika", - "resource-policies.form.eperson-group-list.tab.group": "Wyszukaj grupę", - "resource-policies.form.eperson-group-list.table.headers.action": "Akcja", - "resource-policies.form.eperson-group-list.table.headers.id": "ID", - "resource-policies.form.eperson-group-list.table.headers.name": "Nazwa", - "resource-policies.form.date.end.label": "Data zakończenia", - "resource-policies.form.date.start.label": "Data rozpoczęcia", - "resource-policies.form.description.label": "Opis", - "resource-policies.form.name.label": "Nazwa", - "resource-policies.form.policy-type.label": "Wybierz typ polityki", - "resource-policies.form.policy-type.required": "Musisz wybrać typ polityki zasobu.", - "resource-policies.table.headers.action": "Akcja", - "resource-policies.table.headers.date.end": "Data zakończenia", - "resource-policies.table.headers.date.start": "Data rozpoczęcia", - "resource-policies.table.headers.edit": "Edytuj", - "resource-policies.table.headers.edit.group": "Edytuj grupę", - "resource-policies.table.headers.edit.policy": "Edytuj politykę", - "resource-policies.table.headers.eperson": "Użytkownik", - "resource-policies.table.headers.group": "Grupa", - "resource-policies.table.headers.id": "ID", - "resource-policies.table.headers.name": "Nazwa", - "resource-policies.table.headers.policyType": "typ", - "resource-policies.table.headers.title.for.bitstream": "Polityki dla plików", - "resource-policies.table.headers.title.for.bundle": "Polityki dla paczek", - "resource-policies.table.headers.title.for.item": "Polityki dla pozycji", - "resource-policies.table.headers.title.for.community": "Polityki dla zbioru", - "resource-policies.table.headers.title.for.collection": "Polityki dla kolekcji", - "search.description": "", - "search.switch-configuration.title": "Pokaż", - "search.title": "Szukaj", - "search.breadcrumbs": "Szukaj", - "search.search-form.placeholder": "Szukaj w repozytorium...", - "search.filters.applied.f.author": "Autor", - "search.filters.applied.f.dateIssued.max": "Data zakończenia", - "search.filters.applied.f.dateIssued.min": "Data rozpoczęcia", - "search.filters.applied.f.dateSubmitted": "Data zgłoszenia", - "search.filters.applied.f.discoverable": "Ukryty", - "search.filters.applied.f.entityType": "Typ pozycji", - "search.filters.applied.f.has_content_in_original_bundle": "Ma przypisane pliki", - "search.filters.applied.f.itemtype": "Typ", - "search.filters.applied.f.namedresourcetype": "Status", - "search.filters.applied.f.subject": "Temat", - "search.filters.applied.f.submitter": "Zgłaszający", - "search.filters.applied.f.jobTitle": "Stanowisko", - "search.filters.applied.f.birthDate.max": "Data zakończenia tworzenia", - "search.filters.applied.f.birthDate.min": "Data rozpoczęcia tworzenia", - "search.filters.applied.f.withdrawn": "Wycofane", - "search.filters.filter.author.head": "Autor", - "search.filters.filter.author.placeholder": "Autor", - "search.filters.filter.author.label": "Wyszukaj autora", - "search.filters.filter.birthDate.head": "Data urodzenia", - "search.filters.filter.birthDate.placeholder": "Data urodzenia", - "search.filters.filter.birthDate.label": "Wyszukaj datę urodzenia", - "search.filters.filter.collapse": "Ukryj filtr", - "search.filters.filter.creativeDatePublished.head": "Data opublikowania", - "search.filters.filter.creativeDatePublished.placeholder": "Data opublikowania", - "search.filters.filter.creativeDatePublished.label": "Wyszukaj datę opublikowania", - "search.filters.filter.creativeWorkEditor.head": "Redaktor", - "search.filters.filter.creativeWorkEditor.placeholder": "Redaktor", - "search.filters.filter.creativeWorkEditor.label": "Wyszukaj redaktora", - "search.filters.filter.creativeWorkKeywords.head": "Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.placeholder": "Słowo kluczowe", - "search.filters.filter.creativeWorkKeywords.label": "Wyszukaj temat", - "search.filters.filter.creativeWorkPublisher.head": "Wydawca", - "search.filters.filter.creativeWorkPublisher.placeholder": "Wydawca", - "search.filters.filter.creativeWorkPublisher.label": "Wyszukaj wydawcę", - "search.filters.filter.dateIssued.head": "Data", - "search.filters.filter.dateIssued.max.placeholder": "Data maksymalna", - "search.filters.filter.dateIssued.max.label": "Koniec", - "search.filters.filter.dateIssued.min.placeholder": "Data minimalna", - "search.filters.filter.dateIssued.min.label": "Start", - "search.filters.filter.dateSubmitted.head": "Data zgłoszenia", - "search.filters.filter.dateSubmitted.placeholder": "Data zgłoszenia", - "search.filters.filter.dateSubmitted.label": "Wyszukaj datę zgłoszenia", - "search.filters.filter.discoverable.head": "Ukryty", - "search.filters.filter.withdrawn.head": "Wycofane", - "search.filters.filter.entityType.head": "Typ pozycji", - "search.filters.filter.entityType.placeholder": "Typ pozycji", - "search.filters.filter.entityType.label": "Wyszukaj typ pozycji", - "search.filters.filter.expand": "Rozwiń filtr", - "search.filters.filter.has_content_in_original_bundle.head": "Ma przypisane pliki", - "search.filters.filter.itemtype.head": "Typ", - "search.filters.filter.itemtype.placeholder": "Typ", - "search.filters.filter.itemtype.label": "Wyszukaj typ", - "search.filters.filter.jobTitle.head": "Stanowisko", - "search.filters.filter.jobTitle.placeholder": "Stanowisko", - "search.filters.filter.jobTitle.label": "Wyszukaj stanowisko", - "search.filters.filter.knowsLanguage.head": "Znajomość języka", - "search.filters.filter.knowsLanguage.placeholder": "Znajomość języka", - "search.filters.filter.knowsLanguage.label": "Wyszukaj wg znajomości języka", - "search.filters.filter.namedresourcetype.head": "Status", - "search.filters.filter.namedresourcetype.placeholder": "Status", - "search.filters.filter.namedresourcetype.label": "Wyszukaj status", - "search.filters.filter.objectpeople.head": "Osoby", - "search.filters.filter.objectpeople.placeholder": "Osoby", - "search.filters.filter.objectpeople.label": "Wyszukaj użytkowników", - "search.filters.filter.organizationAddressCountry.head": "Kraj", - "search.filters.filter.organizationAddressCountry.placeholder": "Kraj", - "search.filters.filter.organizationAddressCountry.label": "Wyszukaj kraj", - "search.filters.filter.organizationAddressLocality.head": "Miasto", - "search.filters.filter.organizationAddressLocality.placeholder": "Miasto", - "search.filters.filter.organizationAddressLocality.label": "Wyszukaj miasto", - "search.filters.filter.organizationFoundingDate.head": "Data założenia", - "search.filters.filter.organizationFoundingDate.placeholder": "Data założenia", - "search.filters.filter.organizationFoundingDate.label": "Wyszukaj datę założenia", - "search.filters.filter.scope.head": "Zakres", - "search.filters.filter.scope.placeholder": "Filtr zakresu", - "search.filters.filter.scope.label": "Wyszukaj filtr zakresu", - "search.filters.filter.show-less": "Pokaż mniej", - "search.filters.filter.show-more": "Pokaż więcej", - "search.filters.filter.subject.head": "Temat", - "search.filters.filter.subject.placeholder": "Temat", - "search.filters.filter.subject.label": "Wyszukaj temat", - "search.filters.filter.submitter.head": "Zgłaszający", - "search.filters.filter.submitter.placeholder": "Zgłaszający", - "search.filters.filter.submitter.label": "Wyszukaj zgłaszającego", - "search.filters.entityType.JournalIssue": "Numer czasopisma", - "search.filters.entityType.JournalVolume": "Tom czasopisma", - "search.filters.entityType.OrgUnit": "Jednostka organizacyjna", - "search.filters.has_content_in_original_bundle.true": "Tak", - "search.filters.has_content_in_original_bundle.false": "Nie", - "search.filters.discoverable.true": "Nie", - "search.filters.discoverable.false": "Tak", - "search.filters.withdrawn.true": "Tak", - "search.filters.withdrawn.false": "Nie", - "search.filters.head": "Filtry", - "search.filters.reset": "Resetuj filtry", - "search.filters.search.submit": "Zastosuj", - "search.form.search": "Wyszukaj", - "search.form.search_dspace": "W repozytorium", - "search.form.scope.all": "W całym DSpace", - "search.results.head": "Wyniki wyszukiwania", - "default.search.results.head": "Wyniki wyszukiwania", - "search.results.no-results": "Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", - "search.results.no-results-link": "fraz podobnych do Twojego wyszukiwania", - "search.results.empty": "Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", - "search.sidebar.close": "Wróć do wyników wyszukiwania", - "search.sidebar.filters.title": "Filtry", - "search.sidebar.open": "Narzędzia wyszukiwania", - "search.sidebar.results": "wyniki", - "search.sidebar.settings.rpp": "Wyników na stronie", - "search.sidebar.settings.sort-by": "Sortuj według", - "search.sidebar.settings.title": "Ustawienia", - "search.view-switch.show-detail": "Wyświetl widok szczegółowy", - "search.view-switch.show-grid": "Wyświetl jako siatkę", - "search.view-switch.show-list": "Wyświetl jako listę", - "sorting.ASC": "Rosnąco", - "sorting.DESC": "Malejąco", - "sorting.dc.title.ASC": "Tytułami rosnąco", - "sorting.dc.title.DESC": "Tytułami malejąco", - "sorting.score.ASC": "Najmniej trafne", - "sorting.score.DESC": "Najbardziej trafne", - "sorting.dc.date.issued.ASC": "Data wydania rosnąco", - "sorting.dc.date.issued.DESC": "Data wydania malejąco", - "sorting.dc.date.accessioned.ASC": "Data dostępu rosnąco", - "sorting.dc.date.accessioned.DESC": "Data dostępu malejąco", - "sorting.lastModified.ASC": "Ostatnia modyfikacja rosnąco", - "sorting.lastModified.DESC": "Ostatnia modyfikacja malejąco", - "statistics.title": "Statystyki", - "statistics.header": "Statystyki dla {{ scope }}", - "statistics.breadcrumbs": "Statystyki", - "statistics.page.no-data": "Brak dostępnych danych", - "statistics.table.no-data": "Brak dostępnych danych", - "statistics.table.header.views": "Wyświetlenia", - "submission.edit.breadcrumbs": "Edytuj zgłoszenie", - "submission.edit.title": "Edytuj zgłoszenie", - "submission.general.cancel": "Anuluj", - "submission.general.cannot_submit": "Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", - "submission.general.deposit": "Deponuj", - "submission.general.discard.confirm.cancel": "Anuluj", - "submission.general.discard.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.general.discard.confirm.submit": "Tak, na pewno", - "submission.general.discard.confirm.title": "Odrzuć zgłoszenie", - "submission.general.discard.submit": "Odrzuć", - "submission.general.info.saved": "Zapisane", - "submission.general.info.pending-changes": "Niezapisane zmiany", - "submission.general.save": "Zapisz", - "submission.general.save-later": "Zapisz wersję roboczą", - "submission.import-external.page.title": "Importuj metdane z zewnętrznego źródła", - "submission.import-external.title": "Importuj metadane z zewnętrznego źródła", - "submission.import-external.title.Journal": "Importuj czasopismo z zewnętrznego źródła", - "submission.import-external.title.JournalIssue": "Importuj numer czasopisma z zewnętrznego źródła", - "submission.import-external.title.JournalVolume": "Importuj tom czasopisma z zewnętrznego źródła", - "submission.import-external.title.OrgUnit": "Importuj wydawcę z zewnętrznego źródła", - "submission.import-external.title.Person": "Importuj osobę z zewnętrznego źródła", - "submission.import-external.title.Project": "Importuj projekt z zewnętrznego źródła", - "submission.import-external.title.Publication": "Importuj publikację z zewnętrznego źródła", - "submission.import-external.title.none": "Importuj metadane z zewnętrznego źródła", - "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", - "submission.import-external.back-to-my-dspace": "Powrót do MyDSpace", - "submission.import-external.search.placeholder": "Wyszukaj zewnętrzne źródła danych", - "submission.import-external.search.button": "Szukaj", - "submission.import-external.search.button.hint": "Zacznij wpisywać frazę, aby wyszukać", - "submission.import-external.search.source.hint": "Wybierz zewnętrzne źródło", - "submission.import-external.source.ads": "NASA/ADS", - "submission.import-external.source.arxiv": "arXiv", - "submission.import-external.source.cinii": "CiNii", - "submission.import-external.source.crossref": "CrossRef", - "submission.import-external.source.loading": "ładowanie...", - "submission.import-external.source.sherpaJournal": "Czasopisma w SHERPA", - "submission.import-external.source.sherpaJournalIssn": "Czasopisma w SHERPA wg ISSN", - "submission.import-external.source.sherpaPublisher": "Wydawcy w SHERPA", - "submission.import-external.source.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.import-external.source.orcid": "ORCID", - "submission.import-external.source.orcidWorks": "ORCID", - "submission.import-external.source.pubmed": "Pubmed", - "submission.import-external.source.pubmedeu": "Pubmed Europe", - "submission.import-external.source.lcname": "Nazwy Biblioteki Kongresu", - "submission.import-external.source.scielo": "SciELO", - "submission.import-external.source.scopus": "Scopus", - "submission.import-external.source.vufind": "VuFind", - "submission.import-external.source.wos": "Web Of Science", - "submission.import-external.source.epo": "Europejski Urząd Patentowy (EPO)", - "submission.import-external.preview.title.Journal": "Podgląd czasopisma", - "submission.import-external.preview.title.OrgUnit": "Podgląd organizacji", - "submission.import-external.preview.title.Person": "Podgląd osoby", - "submission.import-external.preview.title.Project": "Podgląd projektu", - "submission.import-external.preview.title.Publication": "Podgląd publikacji", - "submission.import-external.preview.subtitle": "Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", - "submission.import-external.preview.button.import": "Rozpocznij zgłoszenie", - "submission.import-external.preview.error.import.title": "Błąd zgłoszenia", - "submission.import-external.preview.error.import.body": "Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", - "submission.sections.describe.relationship-lookup.close": "Zamknij", - "submission.sections.describe.relationship-lookup.external-source.added": "Udało się dodać wpis do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importuj zdalny tom czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Nowy typ danych dodany!", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekt", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Importuj zdalnego autora", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Importuj zdalną osobę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Importuj zdalny produkt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importuj zdalną aparaturę badawczą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Importuj zdalne wydarzenie", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Importuj zdalną instytucję finansującą", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importuj zdalnego wydawcę", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Importuj zdalnie patent", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Importuj zdalnie projekt", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Importuj zdalnie publikację", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Udało się dodać autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Udało się zaimportować i dodać zewnętrznego autora do selekcji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Nadrzędność", - "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Importuj jako nową, lokalną, nadrzędną pozycję", - "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Anuluj", - "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Wybierz kolekcję do zaimportowania nowych pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Importuj jako nowy lokalny typ danych", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Importuj z LC Name", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Importuj z ORCID", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Importuj z Sherpa Journal", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Importuj z Sherpa Publisher", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Importuj z PubMed", - "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Importuj z arXiv", - "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Import", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Importuj zdalne czasopismo", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Successfully added local journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Successfully imported and added external journal to the selection", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Udało się dodać lokalne czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Importuj zdalny numer czasopisma", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Udało się dodać lokalny numer czasopismo do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", - "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Wybierz lokalne powiązanie:", - "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Odznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Odznacz stronę", - "submission.sections.describe.relationship-lookup.search-tab.loading": "Ładowanie...", - "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Wyszukaj zapytanie", - "submission.sections.describe.relationship-lookup.search-tab.search": "Zastosuj", - "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Wyszukaj...", - "submission.sections.describe.relationship-lookup.search-tab.select-all": "Zaznacz wszystko", - "submission.sections.describe.relationship-lookup.search-tab.select-page": "Zaznacz stronę", - "submission.sections.describe.relationship-lookup.selected": "Zaznacz {{ size }} pozycji", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Czasopisma lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Projekty lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Publikacje lokalne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Autorzy lokalni ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Lokalne jednostki organizacyjne ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Lokalne paczki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Lokalne pliki danych ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Lokalne czasopisma ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Lokalne numery czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Lokalne tomy czasopism ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa Publishers ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC Names ({{ 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": "Wyszukaj instytucje finansujące", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Wyszukaj finansowanie", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Wyszukaj jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projekty", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finansowanie OpenAIRE API", - "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekt", - "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projekty", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Instytucja finansująca projekt", - "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Wyszukaj...", - "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Aktualne zaznaczenie ({{ count }})", - "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalIssue": "Numery czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.JournalVolume": "Tomy czasopisma", - "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Czasopisma", - "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Autorzy", - "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.Project": "Projekty", - "submission.sections.describe.relationship-lookup.title.Publication": "Publikacje", - "submission.sections.describe.relationship-lookup.title.Person": "Autorzy", - "submission.sections.describe.relationship-lookup.title.OrgUnit": "Jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.title.DataPackage": "Paczki danych", - "submission.sections.describe.relationship-lookup.title.DataFile": "Pliki danych", - "submission.sections.describe.relationship-lookup.title.Funding Agency": "Instytucja finansująca", - "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Finansowanie", - "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Nadrzędna jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Przełącz na listę rozwijaną", - "submission.sections.describe.relationship-lookup.selection-tab.settings": "Ustawienia", - "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Twoje zaznaczenie jest puste.", - "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Wybrane tomy czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Wybrane projekty", - "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Wybrane publikacje", - "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Wybrani autorzy", - "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Wybrane jednostki organizacyjne", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Wybrane pakiety danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Wybrane pliki danych", - "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Wybrane czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Wybrany tom czasopisma", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Wybrane instytucje finansujące", - "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Wybrane finansowanie", - "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Wybrany numer wydania", - "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Wybrana jednostka organizacyjna", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.selection-tab.title": "Wyniki wyszukiwania", - "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", - "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Zapisz nowy wariant imienia", - "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Użyj tylko w tym zgłoszeniu", - "submission.sections.ccLicense.type": "Typ licencji", - "submission.sections.ccLicense.select": "Wybierz typ licencji…", - "submission.sections.ccLicense.change": "Zmień typ licencji…", - "submission.sections.ccLicense.none": "Brak dostępnych licencji", - "submission.sections.ccLicense.option.select": "Wybierz opcję…", - "submission.sections.ccLicense.link": "Wybrano licencję:", - "submission.sections.ccLicense.confirmation": "Udzielam powyższej licencji", - "submission.sections.general.add-more": "Dodaj więcej", - "submission.sections.general.collection": "Kolekcja", - "submission.sections.general.deposit_error_notice": "Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", - "submission.sections.general.deposit_success_notice": "Udało się wprowadzić pozycję.", - "submission.sections.general.discard_error_notice": "Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", - "submission.sections.general.discard_success_notice": "Udało się odrzucić pozycję.", - "submission.sections.general.metadata-extracted": "Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", - "submission.sections.general.metadata-extracted-new-section": "Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", - "submission.sections.general.no-collection": "Nie znaleziono kolekcji", - "submission.sections.general.no-sections": "Opcje niedostępne", - "submission.sections.general.save_error_notice": "Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", - "submission.sections.general.save_success_notice": "Udało się zapisać zgłoszenie.", - "submission.sections.general.search-collection": "Szukaj kolekcji", - "submission.sections.general.sections_not_valid": "Niektóre sekcje są niekompletne.", - "submission.sections.submit.progressbar.CClicense": "Licencja Creative Commons", - "submission.sections.submit.progressbar.describe.recycle": "Odzyskaj", - "submission.sections.submit.progressbar.describe.stepcustom": "Opisz", - "submission.sections.submit.progressbar.describe.stepone": "Opisz", - "submission.sections.submit.progressbar.describe.steptwo": "Opisz", - "submission.sections.submit.progressbar.detect-duplicate": "Potencjalne duplikaty", - "submission.sections.submit.progressbar.license": "Zdeponuj licencję", - "submission.sections.submit.progressbar.upload": "Prześlij pliki", - "submission.sections.status.errors.title": "Błędy", - "submission.sections.status.valid.title": "Poprawność", - "submission.sections.status.warnings.title": "Ostrzeżenia", - "submission.sections.status.errors.aria": "ma błędy", - "submission.sections.status.valid.aria": "jest poprawne", - "submission.sections.status.warnings.aria": "ma ostrzeżenia", - "submission.sections.toggle.open": "Otwórz sekcję", - "submission.sections.toggle.close": "Zamknij sekcję", - "submission.sections.toggle.aria.open": "Rozwiń sekcję {{sectionHeader}}", - "submission.sections.toggle.aria.close": "Zwiń sekcję {{sectionHeader}}", - "submission.sections.upload.delete.confirm.cancel": "Anuluj", - "submission.sections.upload.delete.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", - "submission.sections.upload.delete.confirm.submit": "Tak, na pewno", - "submission.sections.upload.delete.confirm.title": "Usuń plik", - "submission.sections.upload.delete.submit": "Usuń", - "submission.sections.upload.download.title": "Pobierz plik", - "submission.sections.upload.drop-message": "Upuść pliki, aby załączyć je do tej pozycji", - "submission.sections.upload.edit.title": "Edytuj plik", - "submission.sections.upload.form.access-condition-label": "Typ dostępu", - "submission.sections.upload.form.date-required": "Data jest wymagana.", - "submission.sections.upload.form.date-required-from": "Data przyznania dostępu od jest wymagana.", - "submission.sections.upload.form.date-required-until": "Data przyznania dostępu do jest wymagana.", - "submission.sections.upload.form.from-label": "Pozwól na dostęp od", - "submission.sections.upload.form.from-placeholder": "Od", - "submission.sections.upload.form.group-label": "Grupa", - "submission.sections.upload.form.group-required": "Grupa jest wymagana", - "submission.sections.upload.form.until-label": "Pozwól na dostęp do", - "submission.sections.upload.form.until-placeholder": "Do", - "submission.sections.upload.header.policy.default.nolist": "Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", - "submission.sections.upload.header.policy.default.withlist": "Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", - "submission.sections.upload.info": "Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", - "submission.sections.upload.no-entry": "Nie", - "submission.sections.upload.no-file-uploaded": "Pliki nie zostały jeszcze wgrane.", - "submission.sections.upload.save-metadata": "Zapisz metadane", - "submission.sections.upload.undo": "Anuluj", - "submission.sections.upload.upload-failed": "Przesyłanie nieudane", - "submission.sections.upload.upload-successful": "Przesyłanie udane", - "submission.submit.breadcrumbs": "Nowe zgłoszenie", - "submission.submit.title": "Nowe zgłoszenie", - "submission.workflow.generic.delete": "Usuń", - "submission.workflow.generic.delete-help": "Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", - "submission.workflow.generic.edit": "Edytuj", - "submission.workflow.generic.edit-help": "Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.generic.view": "Podgląd", - "submission.workflow.generic.view-help": "Wybierz tę opcję, aby wyświetlić metadane pozycji.", - "submission.workflow.tasks.claimed.approve": "Zatwierdź", - "submission.workflow.tasks.claimed.approve_help": "Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", - "submission.workflow.tasks.claimed.edit": "Edytuj", - "submission.workflow.tasks.claimed.edit_help": "Wybierz tę opcję, aby zmienić metadane pozycji.", - "submission.workflow.tasks.claimed.reject.reason.info": "Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", - "submission.workflow.tasks.claimed.reject.reason.placeholder": "Opisz powód odrzucenia zgłoszenia", - "submission.workflow.tasks.claimed.reject.reason.submit": "Odrzuć pozycję", - "submission.workflow.tasks.claimed.reject.reason.title": "Powód", - "submission.workflow.tasks.claimed.reject.submit": "Odrzuć", - "submission.workflow.tasks.claimed.reject_help": "Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", - "submission.workflow.tasks.claimed.return": "Cofnij do puli zadań", - "submission.workflow.tasks.claimed.return_help": "Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", - "submission.workflow.tasks.generic.error": "Podczas działania wystąpił błąd...", - "submission.workflow.tasks.generic.processing": "Procesowanie...", - "submission.workflow.tasks.generic.submitter": "Zgłaszający", - "submission.workflow.tasks.generic.success": "Udało się", - "submission.workflow.tasks.pool.claim": "Podejmij pracę", - "submission.workflow.tasks.pool.claim_help": "Przypisz to zadanie do siebie.", - "submission.workflow.tasks.pool.hide-detail": "Ukryj szczegóły", - "submission.workflow.tasks.pool.show-detail": "Pokaż szczegóły", - "thumbnail.default.alt": "Miniatura", - "thumbnail.default.placeholder": "Brak miniatury", - "thumbnail.project.alt": "Logo projektu", - "thumbnail.project.placeholder": "Obraz zastępczy projketu", - "thumbnail.orgunit.alt": "Logo jednostki organizacyjnej", - "thumbnail.orgunit.placeholder": "Obraz zastępczy jednostki organizacyjnej", - "thumbnail.person.alt": "Zdjęcie profilowe", - "thumbnail.person.placeholder": "Brak zdjęcia profilowego", - "title": "DSpace", - "vocabulary-treeview.header": "Widok drzewka", - "vocabulary-treeview.load-more": "Pokaż więcej", - "vocabulary-treeview.search.form.reset": "Resetuj", - "vocabulary-treeview.search.form.search": "Szukaj", - "vocabulary-treeview.search.no-result": "Brak pozycji do wyświetlenia", - "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", - "vocabulary-treeview.tree.description.srsc": "Kategorie tematów badań", - "uploader.browse": "wyszukaj na swoim urządzeniu", - "uploader.drag-message": "Przeciągnij i upuść pliki tutaj", - "uploader.delete.btn-title": "Usuń", - "uploader.or": ", lub ", - "uploader.processing": "Procesowanie", - "uploader.queue-length": "Długość kolejki", - "virtual-metadata.delete-item.info": "Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "virtual-metadata.delete-item.modal-head": "Wirtualne metadane tego powiązania", - "virtual-metadata.delete-relationship.modal-head": "Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", - "workflowAdmin.search.results.head": "Zarządzaj procesami", - "workflow-item.edit.breadcrumbs": "Edytuj pozycję procesu", - "workflow-item.edit.title": "Edytuj pozycję procesu", - "workflow-item.delete.notification.success.title": "Usunięte", - "workflow-item.delete.notification.success.content": "Ten element procesu został usunięty", - "workflow-item.delete.notification.error.title": "Coś poszło nie tak", - "workflow-item.delete.notification.error.content": "Ten element procesu nie mógł zostać usunięty", - "workflow-item.delete.title": "Usuń element procesu", - "workflow-item.delete.header": "Usuń element procesu", - "workflow-item.delete.button.cancel": "Anuluj", - "workflow-item.delete.button.confirm": "Usuń", - "workflow-item.send-back.notification.success.title": "SOdeślij do zgłaszającego", - "workflow-item.send-back.notification.success.content": "Ten element procesu został odesłany do zgłaszającego", - "workflow-item.send-back.notification.error.title": "Coś poszło nie tak", - "workflow-item.send-back.notification.error.content": "Ten element procesu nie mógł zostać odesłany do zgłaszającego", - "workflow-item.send-back.title": "Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.header": "Odeślij element procesu do zgłaszającego", - "workflow-item.send-back.button.cancel": "Anuluj", - "workflow-item.send-back.button.confirm": "Odeślij", - "workflow-item.view.breadcrumbs": "Widok procesu", - "idle-modal.header": "Sesja wkrótce wygaśnie", - "idle-modal.info": "Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", - "idle-modal.log-out": "Wyloguj", - "idle-modal.extend-session": "Wydłuż sesję", - "workspace.search.results.head": "Twoje zadania", - "orgunit.listelement.badge": "Jednostka organizacyjna", - "orgunit.page.city": "Miasto", - "orgunit.page.country": "Kraj", - "orgunit.page.dateestablished": "Data założenia", - "orgunit.page.description": "Opis", - "orgunit.page.edit": "Edytuj pozycję", - "orgunit.page.id": "ID", - "orgunit.page.titleprefix": "Jednostka organizacyjna: ", - "pagination.options.description": "Opcje strony", - "pagination.results-per-page": "Wyników na stronę", - "pagination.showing.detail": "{{ range }} z {{ total }}", - "pagination.showing.label": "Teraz wyświetlane ", - "pagination.sort-direction": "Opcje sortowania", - "cookies.consent.purpose.sharing": "Udostępnianie", - "item.preview.dc.identifier.issn": "ISSN", - "500.page-internal-server-error": "Usługa niedostępna", - "500.help": "Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", - "500.link.home-page": "Zabierz mnie na stronę główną", - "error-page.description.401": "brak autoryzacji", - "error-page.description.403": "brak dostępu", - "error-page.description.500": "usługa niedostępna", - "error-page.description.404": "nie znaleziono strony", - "error-page.orcid.generic-error": "Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", - "access-status.embargo.listelement.badge": "Embargo", - "access-status.metadata.only.listelement.badge": "Tylko metadane", - "access-status.open.access.listelement.badge": "Open Access", - "access-status.restricted.listelement.badge": "Brak dostępu", - "access-status.unknown.listelement.badge": "Nieznane", - "admin.access-control.groups.table.edit.buttons.remove": "Usuń \"{{name}}\"", - "admin.metadata-import.page.validateOnly": "Tylko waliduj", - "admin.metadata-import.page.validateOnly.hint": "Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", - "bitstream.edit.form.iiifLabel.label": "Etykieta canvyIIIF", - "bitstream.edit.form.iiifLabel.hint": "Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", - "bitstream.edit.form.iiifToc.label": "Spis treści IIIF", - "bitstream.edit.form.iiifToc.hint": "Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", - "bitstream.edit.form.iiifWidth.label": "Szerokość canvy IIIF", - "bitstream.edit.form.iiifWidth.hint": "Szerokość canvy jest zwykle równa szerokości obrazu.", - "bitstream.edit.form.iiifHeight.label": "Wysokość canvy IIIF", - "bitstream.edit.form.iiifHeight.hint": "Wysokość canvy jest zwykle równa szerokości obrazu.", - "browse.back.all-results": "Wszystkie wyniki wyszukiwania", - "pagination.next.button": "Następny", - "pagination.previous.button": "Poprzedni", - "pagination.next.button.disabled.tooltip": "Brak więcej stron z wynikami wyszukiwania", - "browse.startsWith": ", zaczyna się od {{ startsWith }}", - "browse.title.page": "Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", - "collection.edit.item.authorizations.load-bundle-button": "Załaduj więcej paczek", - "collection.edit.item.authorizations.load-more-button": "Załaduj więcej", - "collection.edit.item.authorizations.show-bitstreams-button": "Pokaż polityki plików dla paczek", - "comcol-role.edit.create.error.title": "Nie udało się utworzyć grupy dla roli '{{ role }}'", - "curation.form.submit.error.invalid-handle": "Nie ustalono identyfikatora dla tego obiektu", - "confirmation-modal.delete-profile.header": "Usuń profil", - "confirmation-modal.delete-profile.info": "Czy na pewno chcesz usunąć profil", - "confirmation-modal.delete-profile.cancel": "Anuluj", - "confirmation-modal.delete-profile.confirm": "Usuń", - "error.invalid-search-query": "Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", - "feed.description": "Aktualności", - "footer.link.feedback": "Prześlij uwagi", - "form.group-collapse": "Zwiń", - "form.group-collapse-help": "Kliknij tutaj, aby zwinąć", - "form.group-expand": "Rozwiń", - "form.group-expand-help": "Kliknij tutaj, aby rozwinąć", - "health.breadcrumbs": "Stan systemu", - "health-page.heading": "Stan systemu", - "health-page.info-tab": "Informacje", - "health-page.status-tab": "Status", - "health-page.error.msg": "Serwis stanu systemu jest tymczasowo niedostępny", - "health-page.property.status": "Kod statusu", - "health-page.section.db.title": "Baza danych", - "health-page.section.geoIp.title": "GeoIp", - "health-page.section.solrAuthorityCore.title": "Autentykacja", - "health-page.section.solrOaiCore.title": "OAI", - "health-page.section.solrSearchCore.title": "Wyszukiwarka", - "health-page.section.solrStatisticsCore.title": "Statystyki", - "health-page.section-info.app.title": "Backend aplikacji", - "health-page.section-info.java.title": "Java", - "health-page.status": "Status", - "health-page.status.ok.info": "operacyjny", - "health-page.status.error.info": "Wykryte problemy", - "health-page.status.warning.info": "Wykryte potencjalne problemy", - "health-page.title": "Stan systemu", - "health-page.section.no-issues": "Nie wykryto żadnych problemów", - "info.feedback.breadcrumbs": "Uwagi", - "info.feedback.head": "Uwagi", - "info.feedback.title": "Uwagi", - "info.feedback.info": "Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", - "info.feedback.email_help": "Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", - "info.feedback.send": "Prześlij uwagi", - "info.feedback.comments": "Komentarz", - "info.feedback.email-label": "Twoj adres e-mail", - "info.feedback.create.success": "Uwagi przesłane!", - "info.feedback.error.email.required": "Poprawny adres e-mail jest wymagany", - "info.feedback.error.message.required": "Treść komentarza jest wymagana", - "info.feedback.page-label": "Strona", - "info.feedback.page_help": "Ta strona odnosi się do uwag.", - "item.orcid.return": "Powrót", - "item.truncatable-part.show-more": "Pokaż więcej", - "item.truncatable-part.show-less": "Pokaż mniej", - "item.page.orcid.title": "ORCID", - "item.page.orcid.tooltip": "Otwórz ustawienia ORCID", - "item.page.claim.button": "Podejmij pracę", - "item.page.claim.tooltip": "Podejmij pracę jako profil", - "item.version.create.modal.submitted.header": "Tworzenie nowej wersji...", - "item.version.create.modal.submitted.text": "Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", - "journal-relationships.search.results.head": "Wyniki wyszukiwania czasopism", - "menu.section.icon.health": "Sekcja menu Stan systemu", - "menu.section.health": "Stan systemu", - "metadata-export-search.tooltip": "Eksportuj wyniki wyszukiwania w formacie CSV", - "metadata-export-search.submit.success": "Eksport rozpoczął się", - "metadata-export-search.submit.error": "Eksport nie rozpoczął się", - "person.page.name": "Nazwa", - "person-relationships.search.results.head": "Wyniki wyszukiwania osób", - "profile.special.groups.head": "Autoryzacja do specjalnych grup, do których należysz", - "project-relationships.search.results.head": "Wyniki wyszukiwania projektów", - "publication-relationships.search.results.head": "Wyniki wyszukiwania publikacji", - "resource-policies.edit.page.target-failure.content": "Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", - "resource-policies.edit.page.other-failure.content": "Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", - "resource-policies.form.eperson-group-list.modal.header": "Nie można zmienić typu", - "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Nie można zastąpić użytkownika grupą.", - "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Nie można zastąpić grupy użytkownikiem.", - "resource-policies.form.eperson-group-list.modal.text2": "Usuń obecną polityke zasobu i stwórz nową o określonym typie.", - "resource-policies.form.eperson-group-list.modal.close": "Ok", - "search.results.view-result": "Widok", - "default-relationships.search.results.head": "Wyniki wyszukiwania", - "statistics.table.title.TotalVisits": "Wyświetlnia ogółem", - "statistics.table.title.TotalVisitsPerMonth": "Wyświetlenia w miesiącu", - "statistics.table.title.TotalDownloads": "Pobrania", - "statistics.table.title.TopCountries": "Wyświetlenia wg krajów", - "statistics.table.title.TopCities": "Wyświetlenia wg miast", - "submission.import-external.preview.title": "Podgląd pozycji", - "submission.import-external.preview.title.none": "Podgląd pozycji", - "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import pozycji zdalnie", - "submission.sections.general.cannot_deposit": "Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", - "submission.sections.submit.progressbar.accessCondition": "Warunki dostępu do pozycji", - "submission.sections.submit.progressbar.sherpapolicy": "Polityki Sherpa", - "submission.sections.submit.progressbar.sherpaPolicies": "Informacje o polityce open access wydawcy.", - "submission.sections.status.info.title": "Dodatkowe informacje", - "submission.sections.status.info.aria": "Dodatkowe informacje", - "submission.sections.upload.form.access-condition-hint": "Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", - "submission.sections.upload.form.from-hint": "Wybierz datę, od której ma zostać zastosowany warunek dostępu", - "submission.sections.upload.form.until-hint": "Wybierz datę, do której ma zostać zastosowany warunek dostępu", - "submission.sections.accesses.form.discoverable-description": "Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", - "submission.sections.accesses.form.discoverable-label": "Niemożliwe do wyszukania", - "submission.sections.accesses.form.access-condition-label": "Typ warunku dostępu", - "submission.sections.accesses.form.access-condition-hint": "Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", - "submission.sections.accesses.form.date-required": "Data jest wymagana.", - "submission.sections.accesses.form.date-required-from": "Początkowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.date-required-until": "Końcowa data przyznania dostępu jest wymagana.", - "submission.sections.accesses.form.from-label": "Udziel dostępu od", - "submission.sections.accesses.form.from-hint": "Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.from-placeholder": "Od", - "submission.sections.accesses.form.group-label": "Grupa", - "submission.sections.accesses.form.group-required": "Grupa jest wymagana.", - "submission.sections.accesses.form.until-label": "Udziel dostępu do", - "submission.sections.accesses.form.until-hint": "Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", - "submission.sections.accesses.form.until-placeholder": "Do", - "submission.sections.sherpa.publication.information": "Informacje o publikacji", - "submission.sections.sherpa.publication.information.title": "Tytuł", - "submission.sections.sherpa.publication.information.issns": "Numery ISSN", - "submission.sections.sherpa.publication.information.url": "URL", - "submission.sections.sherpa.publication.information.publishers": "Wydawca", - "submission.sections.sherpa.publication.information.romeoPub": "Wydawca Romeo", - "submission.sections.sherpa.publication.information.zetoPub": "Wydawca Zeto", - "submission.sections.sherpa.publisher.policy": "Polityka wydawnicza", - "submission.sections.sherpa.publisher.policy.description": "Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", - "submission.sections.sherpa.publisher.policy.openaccess": "Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", - "submission.sections.sherpa.publisher.policy.more.information": "Aby uzuyskać więcej informacji, kliknij tutaj:", - "submission.sections.sherpa.publisher.policy.version": "Wersja", - "submission.sections.sherpa.publisher.policy.embargo": "Embargo", - "submission.sections.sherpa.publisher.policy.noembargo": "Brak embargo", - "submission.sections.sherpa.publisher.policy.nolocation": "Brak", - "submission.sections.sherpa.publisher.policy.license": "Licencja", - "submission.sections.sherpa.publisher.policy.prerequisites": "Wymagania wstępne", - "submission.sections.sherpa.publisher.policy.location": "Lokalizacja", - "submission.sections.sherpa.publisher.policy.conditions": "Wymagania", - "submission.sections.sherpa.publisher.policy.refresh": "Odśwież", - "submission.sections.sherpa.record.information": "Informacje o rekordzie", - "submission.sections.sherpa.record.information.id": "ID", - "submission.sections.sherpa.record.information.date.created": "Data utworzenia", - "submission.sections.sherpa.record.information.date.modified": "Ostatnia modyfikacja", - "submission.sections.sherpa.record.information.uri": "URI", - "submission.sections.sherpa.error.message": "Wystąpił błąd podczas pobierania informacji z Sherpa", - "submission.workspace.generic.view": "Podgląd", - "submission.workspace.generic.view-help": "Wybierz tę opcje, aby zobaczyć metadane.", - "workflow.search.results.head": "Zadania na workflow", - "workspace-item.view.breadcrumbs": "Widok wersji roboczej", - "workspace-item.view.title": "Widok wersji roboczej", - "researcher.profile.change-visibility.fail": "Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", - "person.page.orcid.link.processing": "Łączenie profilu z ORCID...", - "person.page.orcid.link.error.message": "Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", - "person.page.orcid.sync-queue.table.header.type": "Typ", - "person.page.orcid.sync-queue.table.header.description": "Opis", - "person.page.orcid.sync-queue.table.header.action": "Akcja", - "person.page.orcid.sync-queue.tooltip.project": "Projekt", - "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Niewłaściwy dwuznakowy kod kraju ISO 3166", - "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Wymagana data publikacji to co najmniej rok po 1900", - "person.page.orcid.synchronization-mode-funding-message": "Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", - "person.page.orcid.synchronization-mode-publication-message": "Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", - "person.page.orcid.synchronization-mode-profile-message": "Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", - "person.orcid.sync.setting": "Ustawienia synchronizacji z ORCID", - "person.orcid.registry.queue": "Kolejka rejestru z ORCID", - "person.orcid.registry.auth": "Autoryzacje z ORCID", - "home.recent-submissions.head": "Najnowsze publikacje", - "submission.sections.sherpa-policy.title-empty": "Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", - "admin.batch-import.breadcrumbs": "Import zbiorczy", - "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", - "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", - "admin.batch-import.page.error.addFile": "Najpierw wybierz plik (ZIP)", - "admin.batch-import.page.header": "Import masowy", - "admin.batch-import.page.help": "Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", - "admin.batch-import.page.remove": "usuń", - "admin.batch-import.page.validateOnly.hint": "Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", - "collection.form.correctionSubmissionDefinition": "Wzór zgłoszenia do prośby o korektę", - "comcol-role.edit.delete.error.title": "Nie udało się usunąć roli '{{ role }}' dla grup", - "confirmation-modal.export-batch.header": "Eksport maasowy (ZIP) {{ dsoName }}", - "confirmation-modal.export-batch.info": "Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", - "dso-selector.export-batch.dspaceobject.head": "Eksport masowy (ZIP) z", - "menu.section.export_batch": "Eksport masowy (ZIP)", - "nav.user-profile-menu-and-logout": "Profil użytkownika i wylogowywanie", - "process.detail.actions": "Akcje", - "process.detail.delete.body": "Czy na pewno chcesz usunąć bieżący proces?", - "process.detail.delete.button": "Usuń proces", - "process.detail.delete.cancel": "Anuluj", - "process.detail.delete.confirm": "Usuń proces", - "process.detail.delete.error": "Nie udało się usunąć procesu", - "process.detail.delete.header": "Usuń proces", - "process.detail.delete.success": "Proces został usunięty.", - "admin.batch-import.title": "Masowy import", - "admin.metadata-import.page.button.select-collection": "Wybierz kolekcję", - "admin.registries.bitstream-formats.table.id": "ID", - "admin.registries.schema.fields.table.id": "ID", - "cookies.consent.app.description.google-recaptcha": "Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", - "cookies.consent.app.disable-all.description": "Przełącz, aby zaakceptować lub odrzucić wszystkie", - "cookies.consent.app.disable-all.title": "Akceptowacja lub odrzucenie wszystkich", - "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", - "cookies.consent.content-modal.service": "usługa", - "cookies.consent.content-modal.services": "usługi", - "cookies.consent.content-notice.description.no-privacy": "Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", - "cookies.consent.content-notice.title": "Zgoda na ciasteczka", - "cookies.consent.ok": "Zgadzam się", - "cookies.consent.purpose.registration-password-recovery": "Rejestracja i odzyskiwanie hasła", - "cookies.consent.save": "Zapisz", - "curation-task.task.citationpage.label": "Generuj stronę z cytowaniem", - "dso-selector.import-batch.dspaceobject.head": "Import masowy z", - "orgunit.listelement.no-title": "Brak tytyłu", - "process.bulk.delete.error.body": "Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", - "process.bulk.delete.error.head": "Błąd podczas usuwania procesu", - "process.bulk.delete.success": "{{count}} proces/y został/y usunięte", - "process.overview.delete": "Usuń {{count}} proces/y", - "process.overview.delete.body": "Czy na pewno usunąć {{count}} proces/y?", - "process.overview.delete.clear": "Wyczyść selekcję procesów do usunięcia", - "process.overview.delete.header": "Usuń procesy", - "process.overview.delete.processing": "{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", - "process.overview.table.actions": "Akcje", - "profile.security.form.label.current-password": "Aktualne hasło", - "profile.security.form.notifications.error.change-failed": "Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", - "profile.security.form.notifications.error.general": "Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", - "register-page.registration.error.recaptcha": "Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", - "register-page.registration.google-recaptcha.must-accept-cookies": "Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", - "register-page.registration.google-recaptcha.notification.message.error": "Wystąpił błąd podczas weryfikacji reCaptcha", - "register-page.registration.google-recaptcha.notification.message.expired": "Weryfikacja wygasła. Zweryfikuj ponownie.", - "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", - "register-page.registration.google-recaptcha.open-cookie-settings": "Otwórz ustawienia plików cookies", - "search.results.response.500": "Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", - "submission.sections.license.granted-label": "Potwierdzam akceptację powyższej licencji", - "submission.sections.license.notgranted": "Najpierw musisz zaakceptować licencję", - "submission.sections.license.required": "Najpierw musisz zaakceptować licencję", - "confirmation-modal.export-batch.confirm": "Eksportuj", - "confirmation-modal.export-batch.cancel": "Anuluj", - "admin.access-control.bulk-access.breadcrumbs": "Zbiorcza edycja dostępu do osiągnięć", - "administrativeBulkAccess.search.results.head": "Wyniki wyszukiwania", - "admin.access-control.bulk-access": "Zbiorcza edycja dostępu do osiągnięć", - "admin.access-control.bulk-access.title": "Zbiorcza edycja dostępu do osiągnięć", - "admin.access-control.bulk-access-browse.header": "Krok 1: Wybierz pozycje", - "admin.access-control.bulk-access-browse.search.header": "Wyszukaj", - "admin.access-control.bulk-access-browse.selected.header": "Obecny wybór({{number}})", - "admin.access-control.bulk-access-settings.header": "Krok 2: Działanie do wykonania", - "admin.access-control.groups.form.tooltip.editGroupPage": "Na tej stronie można edytować opcje grupy i przypisane do niej osoby. W górnej sekcji można edytować nazwę i opis grupy, chyba że jest to grupa administratorów dla zbioru i kolekcji. W tym przypadku nazwa i opis grupy są generowane automatycznie i nie można ich edytować. W kolejnych sekcjach można edytować przypisanie użytkowników do grupy. Szczegóły na [stronie](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", - "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Aby dodać lub usunąć użytkownika do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj paska wyszukiwania poniżej, aby wyszukać użytkowników (użyj listy rozwijanej po lewej stronie paska wyszukiwania, aby wybrać, czy chcesz wyszukiwać według imienia i nazwiska, czy według adresu e-mail). Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może mieć kilka stron: użyj strzałek pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", - "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Aby dodać lub usunąć podgrupę do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj wyszukiwarki poniżej, aby wyszukać użytkowników. Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może składać się z kilku stron: użyj przycisków pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", - "admin.workflow.item.workspace": "Przestrzeń robocza", - "admin.workflow.item.policies": "Polityki", - "admin.workflow.item.supervision": "Recenzja", - "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", - "admin.metadata-import.page.error.addFileUrl": "Najpierw wpisz URL pliku!", - "admin.metadata-import.page.toggle.upload": "Prześlij", - "admin.metadata-import.page.toggle.url": "URL", - "admin.metadata-import.page.urlMsg": "Wpisz URL pliku ZIP, aby wykonać import masowy", - "advanced-workflow-action.rating.form.rating.label": "Ocena", - "advanced-workflow-action.rating.form.rating.error": "Ta pozycja musi zostać oceniona", - "advanced-workflow-action.rating.form.review.label": "Recenzja", - "advanced-workflow-action.rating.form.review.error": "Musisz wpisać tekst recenzji", - "advanced-workflow-action.rating.description": "Wybierz ocenę poniżej", - "advanced-workflow-action.rating.description-requiredDescription": "Wybierz ocenę poniżej i wpisz uzasadnienie", - "advanced-workflow-action.select-reviewer.description-single": "Wybierz recenzenta przed zdeponowaniem pozycji", - "advanced-workflow-action.select-reviewer.description-multiple": "Wybierz jednego lub więcej recenzentów przed zdeponowaniem pozycji", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "Użytkownicy", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Dodaj użytkownika", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Przeglądaj wszystko", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Aktualni użytkownicy", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadane", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "Adres e-mail (dokładny)", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Wyszukaj", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nazwa", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Tożsamość", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Adres e-mail", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Usuń / Dodaj", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Usuń użytkownika z nazwę \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Dodano użytkownika o nazwie: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Nie dodano użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Usunięto użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Nie usunięto użytkownika: \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodano użytkownika \"{{name}}\"", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę.", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nie znaleziono żadnych użytkowników", - "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Recenzent nie jest wybrany.", - "bitstream.edit.notifications.error.primaryBitstream.title": "Wystąpił błąd podczas zapisu pliku.", - "browse.comcol.by.srsc": "Wg słów kluczowych", - "browse.metadata.srsc.breadcrumbs": "Przeglądaj wg słów kluczowych", - "browse.startsWith.input": "Filtr", - "browse.taxonomy.button": "Przeglądaj", - "search.browse.item-back": "Powrót do wyników wyszukiwania", - "claimed-approved-search-result-list-element.title": "Zaakceptowano", - "claimed-declined-search-result-list-element.title": "Odrzucono i przesłano do deponującego", - "claimed-declined-task-search-result-list-element.title": "Odrzucono i przesłano do recenzenta", - "collection.edit.tabs.access-control.head": "Dostępy", - "collection.edit.tabs.access-control.title": "Edycja kolekcji - dostępy", - "collection.listelement.badge": "Kolekcja", - "community.edit.tabs.access-control.head": "Dostępy", - "community.edit.tabs.access-control.title": "Edycja zbioru - dostępy", - "comcol-role.edit.scorereviewers.name": "Ocena recenzenta", - "comcol-role.edit.scorereviewers.description": "Recenzenci mogą oceniać zdeponowane pozycje, co określi, czy pozycja zostanie przyjęta lub odrzucona.", - "curation-task.task.register-doi.label": "Rejestracja DOI", - "dso.name.unnamed": "Bez nazwy", - "dso-selector.create.community.or-divider": "lub", - "dso-selector.set-scope.community.or-divider": "lub", - "dso-selector.results-could-not-be-retrieved": "Wystąpił błąd, proszę odświeżyć stronę", - "supervision-group-selector.header": "Wybór grupy recenzenckiej", - "supervision-group-selector.select.type-of-order.label": "Wybierz typ funkcji", - "supervision-group-selector.select.type-of-order.option.none": "BRAK", - "supervision-group-selector.select.type-of-order.option.editor": "REDAKTOR", - "supervision-group-selector.select.type-of-order.option.observer": "OBSERWATOR", - "supervision-group-selector.select.group.label": "Wybierz grupę", - "supervision-group-selector.button.cancel": "Anuluj", - "supervision-group-selector.button.save": "Zapisz", - "supervision-group-selector.select.type-of-order.error": "Wybierz typ funkcji", - "supervision-group-selector.select.group.error": "Wybierz grupę", - "supervision-group-selector.notification.create.success.title": "Grupa recenzencka został dodana dla grupy {{ name }}", - "supervision-group-selector.notification.create.failure.title": "Błąd", - "supervision-group-selector.notification.create.already-existing": "Funkcja recenzenta już jest przypisana do tej grupy", - "confirmation-modal.delete-subscription.header": "Usuń subksrypcje", - "confirmation-modal.delete-subscription.info": "Czy na pewno chcesz usunąć subskrypcję: \"{{ dsoName }}\"", - "confirmation-modal.delete-subscription.cancel": "Anuluj", - "confirmation-modal.delete-subscription.confirm": "Usuń", - "error.validation.metadata.name.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", - "error.validation.metadata.name.max-length": "To pole nie może zawierać więcej niż 32 znaki", - "error.validation.metadata.namespace.max-length": "To pole nie może zawierać więcej niż 256 znaków", - "error.validation.metadata.element.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", - "error.validation.metadata.element.max-length": "To pole nie może zawierać więcej niż 64 znaki", - "error.validation.metadata.qualifier.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji", - "error.validation.metadata.qualifier.max-length": "To pole nie może zawierać więcej niż 64 znaki", - "forgot-email.form.email.error.not-email-form": "Wpisz prawidłowy adres e-mail", - "form.other-information.email": "Adres e-mail", - "form.other-information.first-name": "Imię", - "form.other-information.insolr": "Solr Index", - "form.other-information.institution": "Instytucja", - "form.other-information.last-name": "Nazwisko", - "form.other-information.orcid": "ORCID", - "form.create": "Utwórz", - "info.end-user-agreement.hosting-country": "Stany Zjednoczone", - "item.edit.identifiers.doi.status.UNKNOWN": "Nieznane", - "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "W kolejce do rejestracji", - "item.edit.identifiers.doi.status.TO_BE_RESERVED": "W kolejce do rezerwacji", - "item.edit.identifiers.doi.status.IS_REGISTERED": "Zarejestrowane", - "item.edit.identifiers.doi.status.IS_RESERVED": "Zarezerwowane", - "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Zarezerwowane (aktualizacja w kolejce)", - "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Zarejestrowane (aktualizacja w kolejce)", - "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "W kolejce do aktualizacji i rejestracji", - "item.edit.identifiers.doi.status.TO_BE_DELETED": "Zakolejkowane do usunięcia", - "item.edit.identifiers.doi.status.DELETED": "Usunięte", - "item.edit.identifiers.doi.status.PENDING": "Oczekujące (niezarejestrowane)", - "item.edit.identifiers.doi.status.MINTED": "Rezerwowanie nazwy (niezarejestrowane)", - "item.edit.tabs.status.buttons.register-doi.label": "Zarejestruj nowe lub oczekujące DOI", - "item.edit.tabs.status.buttons.register-doi.button": "Rejestruj DOI...", - "item.edit.register-doi.header": "Zarejestruj nowe lub oczekujące DOI", - "item.edit.register-doi.description": "Zweryfikuj poniższe identyfikatory i metadane pozycji i rozpocznij rejestrację DOI lub anuluj", - "item.edit.register-doi.confirm": "Zatwierdź", - "item.edit.register-doi.cancel": "Anuluj", - "item.edit.register-doi.success": "DOI jest w kolejce do rejestracji.", - "item.edit.register-doi.error": "Wystąpił błąd poczas rejestracji DOI", - "item.edit.register-doi.to-update": "To DOI zostało zarezerwowane i będzie znajdować się w kolejce do rejestracji", - "item.edit.metadata.edit.buttons.confirm": "Zatwierdź", - "item.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", - "item.edit.metadata.edit.buttons.virtual": "To pole przechowuje wirutalne wartości metadanych, np. wartość pobraną z encji, z którą jest połączona ta pozycja. Dodaj lub usuń relację w zakładce 'Relacje' ", - "item.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidcji pól metadanych", - "item.edit.metadata.reset-order-button": "Cofnij zamianę kolejności", - "item.edit.curate.title": "Zarządzaj pozycją: {{item}}", - "item.edit.tabs.access-control.head": "Dostęp", - "item.edit.tabs.access-control.title": "Edycja pozycji - dostęp", - "workflow-item.search.result.delete-supervision.modal.header": "Usuń zadanie dla recenzenta", - "workflow-item.search.result.delete-supervision.modal.info": "Czy na pewno usunąć zadanie dla recenzenta", - "workflow-item.search.result.delete-supervision.modal.cancel": "Anuluj", - "workflow-item.search.result.delete-supervision.modal.confirm": "Usuń", - "workflow-item.search.result.notification.deleted.success": "Usunięto zadanie dla recenzenta \"{{name}}\"", - "workflow-item.search.result.notification.deleted.failure": "Nie usunięto zadania dla recenzenta \"{{name}}\"", - "workflow-item.search.result.list.element.supervised-by": "Recenzja:", - "workflow-item.search.result.list.element.supervised.remove-tooltip": "Usuń grupę recenzencką", - "item.preview.dc.subject": "Słowo kluczowe:", - "item.preview.dc.publisher": "Wydawca:", - "itemtemplate.edit.metadata.add-button": "Dodaj", - "itemtemplate.edit.metadata.discard-button": "Cofnij", - "itemtemplate.edit.metadata.edit.buttons.confirm": "Zatwierdź", - "itemtemplate.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", - "itemtemplate.edit.metadata.edit.buttons.edit": "Edytuj", - "itemtemplate.edit.metadata.edit.buttons.remove": "Usuń", - "itemtemplate.edit.metadata.edit.buttons.undo": "Cofnij zmiany", - "itemtemplate.edit.metadata.edit.buttons.unedit": "Nie edytuj", - "itemtemplate.edit.metadata.empty": "To pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby je wprowadzić.", - "itemtemplate.edit.metadata.headers.edit": "Edytuj", - "itemtemplate.edit.metadata.headers.field": "Pole", - "itemtemplate.edit.metadata.headers.language": "Język", - "itemtemplate.edit.metadata.headers.value": "Wartość", - "itemtemplate.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidowania pola metadanych", - "itemtemplate.edit.metadata.metadatafield.invalid": "Wybierz odpowiednie pole metadanych", - "itemtemplate.edit.metadata.notifications.discarded.content": "Twoje zmiany nie zostały zachowane. Aby spróbować wprowadzić je ponownie wybierz Cofnij", - "itemtemplate.edit.metadata.notifications.discarded.title": "Zmiany nie zostały zachowane", - "itemtemplate.edit.metadata.notifications.error.title": "Wystąpił błąd", - "itemtemplate.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Upewnij się, że wszystkie pola zostały wypełnione prawidłowo.", - "itemtemplate.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadan", - "itemtemplate.edit.metadata.notifications.outdated.content": "Wzór dla pozycji, na którą w tym momencie pracujesz, został zmodyfikowany przez innego użytkownika. Twoje zmiany zostały odrzucone, aby uniknąć konfliktów pomiędzy wersjami.", - "itemtemplate.edit.metadata.notifications.outdated.title": "Zmiany zostały odrzucone", - "itemtemplate.edit.metadata.notifications.saved.content": "Zmiany w metadanych wzoru pozycji zostały zapisane.", - "itemtemplate.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", - "itemtemplate.edit.metadata.reinstate-button": "Cofnij", - "itemtemplate.edit.metadata.reset-order-button": "Cofnij zmianę kolejności", - "itemtemplate.edit.metadata.save-button": "Zapisz", - "menu.section.access_control_bulk": "Zbiorowe zarządzanie dostępem", - "menu.section.browse_global_by_srsc": "Wg słów kluczowych", - "mydspace.show.supervisedWorkspace": "Pozycje recenzowane", - "mydspace.status.mydspaceArchived": "Opublikowano", - "mydspace.status.mydspaceValidation": "Walidacja", - "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redakctora", - "mydspace.status.mydspaceWorkflow": "Redakcja", - "mydspace.status.mydspaceWorkspace": "Przestrzeń robocza", - "nav.context-help-toggle": "Przełącz pomoc kontekstową", - "nav.search.button": "Wpisz wyszukiwaną frazę", - "nav.subscriptions": "Subksrypcje", - "process.new.notification.error.max-upload.content": "Plik jest większy niż maksymalny dozwolony rozmiar pliku", - "register-page.registration.email.error.not-email-form": "Wprowadź poprawny adres e-mail", - "register-page.registration.email.error.not-valid-domain": "Użyj adresu e-mail z domeny: {{ domains }}", - "register-page.registration.error.maildomain": "Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", - "register-page.registration.info.maildomain": "Konta mogą być założone dla adresów e-mail z domeną", - "repository.title": "Repozytorium DSpace", - "search.filters.applied.f.supervisedBy": "Recenzent", - "search.filters.filter.show-tree": "Przeglądaj {{ name }} strukturę recenzentów", - "search.filters.filter.supervisedBy.head": "Recenzent", - "search.filters.filter.supervisedBy.placeholder": "Recenzent", - "search.filters.filter.supervisedBy.label": "Wyszukaj recenzenta", - "statistics.table.no-name": "(nazwa obiektu nie może zostać załadowana)", - "submission.import-external.source.datacite": "DataCite", - "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publikacje autora", - "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publikacje", - "submission.sections.identifiers.info": "Te identyfikatory zostaną utworzone dla pozycji:", - "submission.sections.identifiers.no_handle": "Do tej pozycji nie zostały przypisane żadne Handle", - "submission.sections.identifiers.no_doi": "Do tej pozycji nie zostały przypisane żadne DOI", - "submission.sections.identifiers.handle_label": "Handle: ", - "submission.sections.identifiers.doi_label": "DOI: ", - "submission.sections.identifiers.otherIdentifiers_label": "Inne identyfikatory: ", - "submission.sections.submit.progressbar.identifiers": "Identyfikatory", - "submission.workflow.generic.submit_select_reviewer": "Wybierz recenzenta", - "submission.workflow.generic.submit_select_reviewer-help": "", - "submission.workflow.generic.submit_score": "Wynik", - "submission.workflow.generic.submit_score-help": "", - "submission.workflow.tasks.claimed.decline": "Odrzuć", - "submission.workflow.tasks.claimed.decline_help": "", - "submitter.empty": "n.d.", - "subscriptions.title": "Subskrypcje", - "subscriptions.item": "Subskrypcje pozycji", - "subscriptions.collection": "Subskrypcje kolekcji", - "subscriptions.community": "Subskrypcje zbiorów", - "subscriptions.subscription_type": "Typ subksrypcji", - "subscriptions.frequency": "Częstotliwość subskrypcji", - "subscriptions.frequency.D": "Codziennie", - "subscriptions.frequency.M": "Co miesiąc", - "subscriptions.frequency.W": "Co tydzień", - "subscriptions.tooltip": "Subskrybuj", - "subscriptions.modal.title": "Subksrypcje", - "subscriptions.modal.type-frequency": "Rodzaj i częstotliwość subksrypcji", - "subscriptions.modal.close": "Zamknij", - "subscriptions.modal.delete-info": "Aby usunąć tę subksrypcję przejdź do strony 'Subskrypcje', która znajduje się w profilu użytkownika", - "subscriptions.modal.new-subscription-form.type.content": "Zawartość", - "subscriptions.modal.new-subscription-form.frequency.D": "Codziennie", - "subscriptions.modal.new-subscription-form.frequency.W": "Co tydzień", - "subscriptions.modal.new-subscription-form.frequency.M": "Co miesiąc", - "subscriptions.modal.new-subscription-form.submit": "Zapisz", - "subscriptions.modal.new-subscription-form.processing": "Ładowanie...", - "subscriptions.modal.create.success": "Zasubskrybowano {{ type }}", - "subscriptions.modal.delete.success": "Subskrypcja została anulowana", - "subscriptions.modal.update.success": "Twoja subskrypcja {{ type }} została zaktualizowana", - "subscriptions.modal.create.error": "Wystąpił bład podczas tworzenia subskrypcji", - "subscriptions.modal.delete.error": "Wystąpił bład podczas usuwania subskrypcji", - "subscriptions.modal.update.error": "Wystąpił bład podczas aktualizacji subskrypcji", - "subscriptions.table.dso": "Słowo kluczowe", - "subscriptions.table.subscription_type": "Typ subskrypcji", - "subscriptions.table.subscription_frequency": "Częstotliwość subskrypcji", - "subscriptions.table.action": "Akcja", - "subscriptions.table.edit": "Edytuj", - "subscriptions.table.delete": "Usuń", - "subscriptions.table.not-available": "Niedostępne", - "subscriptions.table.not-available-message": "Ta pozycja została usunięta lun nie masz do niej dostępu, aby ją wyswietlić", - "subscriptions.table.empty.message": "Ta pozycja nie ma w tym momencie żadnych subksrypcji. Aby zasubkrybować i otrzymywać aktualizacje o tym zbiorze lub kolekcji, wybierz przycisk subskrypcji na stronie pozycji.", - "vocabulary-treeview.info": "Wybierz słowo kluczowe, aby dodać je do filtra", - "supervisedWorkspace.search.results.head": "Pozycje recenzowane", - "supervision.search.results.head": "Status zadań: Szkic i redakcja", - "workspace-item.delete.breadcrumbs": "Usunięto wersję roboczą", - "workspace-item.delete.header": "Usuń wersję roboczą", - "workspace-item.delete.button.confirm": "Usuń", - "workspace-item.delete.button.cancel": "Anuluj", - "workspace-item.delete.notification.success.title": "Usunięto", - "workspace-item.delete.title": "Wersja robocza została usunieta", - "workspace-item.delete.notification.error.title": "Coś poszło nie tak", - "workspace-item.delete.notification.error.content": "Wersja robocza nie może zostać usunieta", - "workflow-item.advanced.title": "Zaawansowane workflow", - "workflow-item.selectrevieweraction.notification.success.title": "Wybrany recenzent", - "workflow-item.selectrevieweraction.notification.success.content": "Recenzent został przypisany", - "workflow-item.selectrevieweraction.notification.error.title": "Coś poszło nie tak", - "workflow-item.selectrevieweraction.notification.error.content": "Nie udało się wybrać recenzenta dla pozycji", - "workflow-item.selectrevieweraction.title": "Wybierz recenzenta", - "workflow-item.selectrevieweraction.header": "Wybierz recenzenta", - "workflow-item.selectrevieweraction.button.cancel": "Anuluj", - "workflow-item.selectrevieweraction.button.confirm": "Zatwierdź", - "workflow-item.scorereviewaction.notification.success.title": "Ocena recenzji", - "workflow-item.scorereviewaction.notification.success.content": "Ocena tej pozycji została zapisana", - "workflow-item.scorereviewaction.notification.error.title": "Coś poszło nie tak", - "workflow-item.scorereviewaction.notification.error.content": "Nie można ocenić tej pozycji", - "workflow-item.scorereviewaction.title": "Oceń pozycję", - "workflow-item.scorereviewaction.header": "Oceń pozycję", - "workflow-item.scorereviewaction.button.cancel": "Anuluj", - "workflow-item.scorereviewaction.button.confirm": "Potwierdź", - "listable-notification-object.default-message": "Ta pozycja nie może być odzyskana", - "system-wide-alert-banner.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", - "system-wide-alert-banner.countdown.prefix": "W", - "system-wide-alert-banner.countdown.days": "{{days}} dni,", - "system-wide-alert-banner.countdown.hours": "{{hours}} godziny", - "system-wide-alert-banner.countdown.minutes": "{{minutes}} minut:", - "menu.section.system-wide-alert": "Alert systemowy", - "system-wide-alert.form.header": "Alert systemowy", - "system-wide-alert-form.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", - "system-wide-alert.form.cancel": "Anuluj", - "system-wide-alert.form.save": "Zapisz", - "system-wide-alert.form.label.active": "AKTYWNE", - "system-wide-alert.form.label.inactive": "NIEAKTYWNE", - "system-wide-alert.form.error.message": "Alert systemowy musi zawierać wiadomość", - "system-wide-alert.form.label.message": "Alert systemowy", - "system-wide-alert.form.label.countdownTo.enable": "Wprowadź licznik czasowy", - "system-wide-alert.form.label.countdownTo.hint": "Wskazówka: Wpisz wartość licznika czasu. Kiedy licznik jest włączony, alert systemowy zostanie wyświetlony o wybranym czasie. Kiedy odliczanie zostanie zakończone, alert systemowy zostanie wyłączony. Serwer NIE zostanie zatrzymany automatycznie.", - "system-wide-alert.form.label.preview": "Podgląd alertu systemowego", - "system-wide-alert.form.update.success": "Alert systemowy został zaktualizowany", - "system-wide-alert.form.update.error": "Coś poszło nie tak podczas aktualizacji alertu systemowego", - "system-wide-alert.form.create.success": "Alert systemowy został utworzony", - "system-wide-alert.form.create.error": "Coś poszło nie tak podczas tworzenia alertu systemowego", - "admin.system-wide-alert.breadcrumbs": "Alerty systemowe", - "admin.system-wide-alert.title": "Alerty systemowe", - "item-access-control-title": "Ta strona pozwala na zmianę dostępów metadanych pozycji i plików do nich dołączonych.", - "collection-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w tej kolekcji. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", - "community-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w każdej kolekcji w tym zbiorze. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", - "access-control-item-header-toggle": "Metadane pozycji", - "access-control-bitstream-header-toggle": "Pliki", - "access-control-mode": "Tryb", - "access-control-access-conditions": "Warunki dostępu", - "access-control-no-access-conditions-warning-message": "W tym momencie żadne warunki dostępu nie zostały określone. Jeśli zadanie zostanie rozpoczęte, obecne warunki dostępu zostaną zastąpione domyślnymi warunkami dostępu z nadrzędnej kolekcji.", - "access-control-replace-all": "Zastąp warunki dostępu", - "access-control-add-to-existing": "Dodaj do już istniejących", - "access-control-limit-to-specific": "Ogranicz zmiany do wybranych plików", - "access-control-process-all-bitstreams": "Zaktualizuj wszystkie pliki dla tej pozycji", - "access-control-bitstreams-selected": "wybrane pliki", - "access-control-cancel": "Anuluj", - "access-control-execute": "Wykonaj", - "access-control-add-more": "Dodaj więcej", - "access-control-select-bitstreams-modal.title": "Wybierz pliki", - "access-control-select-bitstreams-modal.no-items": "Brak pozycji do wyświetlenia.", - "access-control-select-bitstreams-modal.close": "Zamknij", - "access-control-option-label": "Typ warunków dostępu", - "access-control-option-note": "Wybierz warunki dostępu, które chcesz przypisać do zaznaczonych pozycji.", - "access-control-option-start-date": "Dostęp od", - "access-control-option-start-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", - "access-control-option-end-date": "Dostęp do", - "access-control-option-end-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", + "401.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby powrócić do strony głównej.", + "401.link.home-page": "Zabierz mnie na stronę główną", + "401.unauthorized": "nieautoryzowany", + "403.help": "Nie masz uprawnień do dostępu do tej strony. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "403.link.home-page": "Zabierz mnie na stronę główną", + "403.forbidden": "zabroniony", + "404.help": "Nie możemy znaleźć strony, której szukasz. Strona mogła zostać przeniesiona lub usunięta. Możesz użyć przycisku poniżej, aby powrócić do strony głównej. ", + "404.link.home-page": "Zabierz mnie na stronę główną", + "404.page-not-found": "strona nie została znaleziona", + "admin.curation-tasks.breadcrumbs": "Systemowe zadania administracyjne", + "admin.curation-tasks.title": "Systemowe zadania administracyjne", + "admin.curation-tasks.header": "Systemowe zadania administracyjne", + "admin.registries.bitstream-formats.breadcrumbs": "Rejestr formatów", + "admin.registries.bitstream-formats.create.breadcrumbs": "Format strumienia bitów", + "admin.registries.bitstream-formats.create.failure.content": "Wystąpił błąd podczas tworzenia nowego formatu strumienia bitów.", + "admin.registries.bitstream-formats.create.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.create.head": "Utwórz nowy format", + "admin.registries.bitstream-formats.create.new": "Dodaj nowy format", + "admin.registries.bitstream-formats.create.success.content": "Nowy format strumienia bitów został pomyślnie utworzony.", + "admin.registries.bitstream-formats.create.success.head": "Udało się", + "admin.registries.bitstream-formats.delete.failure.amount": "Nie udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.delete.success.amount": "Udało się usunąć {{ amount }} formatu(ów)", + "admin.registries.bitstream-formats.delete.success.head": "Udało się", + "admin.registries.bitstream-formats.description": "Na liście formatów wyświetlono informacje o obsługiwanych formatach i czy są one wspierane przez system.", + "admin.registries.bitstream-formats.edit.breadcrumbs": "Format strumienia bitów", + "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.label": "Opis", + "admin.registries.bitstream-formats.edit.extensions.hint": "Rozszerzenia to rozszerzenia plików, które są używane do automatycznej identyfikacji formatu przesyłanych plików. Możesz wprowadzić kilka rozszerzeń dla każdego formatu.", + "admin.registries.bitstream-formats.edit.extensions.label": "Rozszerzenia plików", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Wprowadź rozszerzenie pliku bez kropki", + "admin.registries.bitstream-formats.edit.failure.content": "Wystąpił błąd podczas edycji formatu pliku.", + "admin.registries.bitstream-formats.edit.failure.head": "Nie udało się", + "admin.registries.bitstream-formats.edit.head": "Format plików: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint": "Formaty oznaczone jako wewnętrzne są ukryte przed użytkownikiem i wykorzystywane do celów administracyjnych.", + "admin.registries.bitstream-formats.edit.internal.label": "Wewnętrzny", + "admin.registries.bitstream-formats.edit.mimetype.hint": "Typ MIME powiązany z tym formatem, nie musi być unikalny.", + "admin.registries.bitstream-formats.edit.mimetype.label": "Typ MIME", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "Unikalna nazwa dla tego formatu, (np. Microsoft Word XP lub Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Nazwa", + "admin.registries.bitstream-formats.edit.success.content": "Format strumienia bitów został pomyślnie edytowany.", + "admin.registries.bitstream-formats.edit.success.head": "Udało się", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "Poziom wsparcia, jaki Twoja instytucja deklaruje dla tego formatu.", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Obsługiwany format", + "admin.registries.bitstream-formats.head": "Rejestr formatów", + "admin.registries.bitstream-formats.no-items": "Brak formatów plików do wyświetlenia.", + "admin.registries.bitstream-formats.table.delete": "Usuń zaznaczone", + "admin.registries.bitstream-formats.table.deselect-all": "Odznacz wszystkie", + "admin.registries.bitstream-formats.table.internal": "wewnętrzne", + "admin.registries.bitstream-formats.table.mimetype": "Typ MIME", + "admin.registries.bitstream-formats.table.name": "Nazwa", + "admin.registries.bitstream-formats.table.return": "Powrót", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Znane", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Wspierane", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Nieznane", + "admin.registries.bitstream-formats.table.supportLevel.head": "Obsługiwany format", + "admin.registries.bitstream-formats.title": "Rejestr formatów plików", + "admin.registries.metadata.breadcrumbs": "Rejestr metadanych", + "admin.registries.metadata.description": "W rejestrze metadanych przechowywana jest lista wszystkich pól metadanych dostępnych w repozytorium. Przechowywane pola są przechowywane w kilku rejestrach. DSpace wymaga kwalifikowanego rejestru metadanych Dublin Core.", + "admin.registries.metadata.form.create": "Utwórz schemat metadanych", + "admin.registries.metadata.form.edit": "Edytuj schemat metadanych", + "admin.registries.metadata.form.name": "Nazwa", + "admin.registries.metadata.form.namespace": "Nazwa schematu", + "admin.registries.metadata.head": "Rejestr metadanych", + "admin.registries.metadata.schemas.no-items": "Brak rejestrów metadanych do pokazania.", + "admin.registries.metadata.schemas.table.delete": "Usuń zaznaczone", + "admin.registries.metadata.schemas.table.id": "ID", + "admin.registries.metadata.schemas.table.name": "Nazwa", + "admin.registries.metadata.schemas.table.namespace": "Nazwa schematu", + "admin.registries.metadata.title": "Rejestr metadanych", + "admin.registries.schema.breadcrumbs": "Schemat metadanych", + "admin.registries.schema.description": "Ten schemat metadanych jest stworzony na podstawie \"{{namespace}}\".", + "admin.registries.schema.fields.head": "Pola schematu metadanych", + "admin.registries.schema.fields.no-items": "Brak pól metadanych do pokazania.", + "admin.registries.schema.fields.table.delete": "Usuń zaznaczone", + "admin.registries.schema.fields.table.field": "Pole", + "admin.registries.schema.fields.table.scopenote": "Uwagi", + "admin.registries.schema.form.create": "Stwórz pole metadanych", + "admin.registries.schema.form.edit": "Edytuj pole metadanych", + "admin.registries.schema.form.element": "Element", + "admin.registries.schema.form.qualifier": "Kwalifikator", + "admin.registries.schema.form.scopenote": "Uwagi", + "admin.registries.schema.head": "Schemat metadanych", + "admin.registries.schema.notification.created": "Udało się utworzyć schemat metdanych \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure": "Nie udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.deleted.success": "Udało się usunąć {{amount}} schematów metadanych", + "admin.registries.schema.notification.edited": "Udało się edytować schemat metadanych \"{{prefix}}\"", + "admin.registries.schema.notification.failure": "Błąd", + "admin.registries.schema.notification.field.created": "Udało się utworzyć pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure": "Nie udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.deleted.success": "Udało się usunąć {{amount}} pól metadanych", + "admin.registries.schema.notification.field.edited": "SUdało się edytować pole metadanych \"{{field}}\"", + "admin.registries.schema.notification.success": "Udało się", + "admin.registries.schema.return": "Powrót", + "admin.registries.schema.title": "Rejestr schematów metadanych", + "admin.access-control.epeople.actions.delete": "Usuń użytkownika", + "admin.access-control.epeople.actions.impersonate": "Personifikuj użytkownika", + "admin.access-control.epeople.actions.reset": "Zresetuj hasło", + "admin.access-control.epeople.actions.stop-impersonating": "Przestań personifikować użytkownika", + "admin.access-control.epeople.breadcrumbs": "Użytkownicy", + "admin.access-control.epeople.title": "Użytkownicy", + "admin.access-control.epeople.head": "Użytkownicy", + "admin.access-control.epeople.search.head": "Wyszukaj", + "admin.access-control.epeople.button.see-all": "Przeglądaj wszystko", + "admin.access-control.epeople.search.scope.metadata": "Metadane", + "admin.access-control.epeople.search.scope.email": "E-mail", + "admin.access-control.epeople.search.button": "Wyszukaj", + "admin.access-control.epeople.search.placeholder": "Wyszukaj użytkownika...", + "admin.access-control.epeople.button.add": "Dodaj użytkownika", + "admin.access-control.epeople.table.id": "ID", + "admin.access-control.epeople.table.name": "Nazwa", + "admin.access-control.epeople.table.email": "E-mail", + "admin.access-control.epeople.table.edit": "Edytuj", + "admin.access-control.epeople.table.edit.buttons.edit": "Edytuj \"{{name}}\"", + "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Brak uprawnień do edycji wybranej grupy", + "admin.access-control.epeople.table.edit.buttons.remove": "Usuń \"{{name}}\"", + "admin.access-control.epeople.no-items": "Brak użytkowników do wyświetlenia.", + "admin.access-control.epeople.form.create": "Utwórz użytkownika", + "admin.access-control.epeople.form.edit": "Edytuj użytkownika", + "admin.access-control.epeople.form.firstName": "Imię", + "admin.access-control.epeople.form.lastName": "Nazwisko", + "admin.access-control.epeople.form.email": "E-mail", + "admin.access-control.epeople.form.emailHint": "Adres e-mail musi być poprawny", + "admin.access-control.epeople.form.canLogIn": "Możliwość zalogowania", + "admin.access-control.epeople.form.requireCertificate": "Wymagany certyfikat", + "admin.access-control.epeople.form.return": "Powrót", + "admin.access-control.epeople.form.notification.created.success": "Udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure": "Nie udało się utworzyć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Nie udało się utworzyć użytkownika \"{{name}}\", email \"{{email}}\" już w użyciu.", + "admin.access-control.epeople.form.notification.edited.success": "Udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.edited.failure": "Nie udało się edytować użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.success": "Udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.failure": "Nie udało się usunąć użytkownika \"{{name}}\"", + "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Członek grup:", + "admin.access-control.epeople.form.table.id": "ID", + "admin.access-control.epeople.form.table.name": "Nazwa", + "admin.access-control.epeople.form.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.epeople.form.memberOfNoGroups": "Ten użytkownik nie jest członkiem żadnej grupy", + "admin.access-control.epeople.form.goToGroups": "Dodaj do grup", + "admin.access-control.epeople.notification.deleted.failure": "Nie udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.success": "Udało się usunąć użytkownika: \"{{name}}\"", + "admin.access-control.groups.title": "Grupy", + "admin.access-control.groups.breadcrumbs": "Grupy", + "admin.access-control.groups.singleGroup.breadcrumbs": "Edytuj grupę", + "admin.access-control.groups.title.singleGroup": "Edytuj grupę", + "admin.access-control.groups.title.addGroup": "Nowa grupa", + "admin.access-control.groups.addGroup.breadcrumbs": "Nowa grupa", + "admin.access-control.groups.head": "Grupy/role", + "admin.access-control.groups.button.add": "Dodaj grupę", + "admin.access-control.groups.search.head": "Szukaj grup", + "admin.access-control.groups.button.see-all": "Przeszukaj wszystko", + "admin.access-control.groups.search.button": "Wyszukaj", + "admin.access-control.groups.search.placeholder": "Wyszukaj grupy...", + "admin.access-control.groups.table.id": "ID", + "admin.access-control.groups.table.name": "Nazwa", + "admin.access-control.groups.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.groups.table.members": "Członkowie", + "admin.access-control.groups.table.edit": "Edytuj", + "admin.access-control.groups.table.edit.buttons.edit": "Edytuj \"{{name}}\"", + "admin.access-control.groups.no-items": "Nie znaleziono grup z podaną frazą lub podanym UUID", + "admin.access-control.groups.notification.deleted.success": "Udało się usunąć grupę \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content": "Powód: \"{{cause}}\"", + "admin.access-control.groups.form.alert.permanent": "Ta grupa jest stała, więc nie może być edytowana ani usunięta. Nadal możesz dodawać i usuwać członków grupy za pomocą tej strony.", + "admin.access-control.groups.form.alert.workflowGroup": "Ta grupa nie może być edytowana lub usunięta, ponieważ odnosi się do roli lub bierze udział w procesie \"{{name}}\" {{comcol}}. Możesz ją usunąć ze strony <a href='{{comcolEditRolesRoute}}'>\"assign roles\"</a> edycji {{comcol}}. Wciąż może dodawać i usuwać członków tej grupy, korzystając z tej strony.", + "admin.access-control.groups.form.head.create": "Utwórz grupę", + "admin.access-control.groups.form.head.edit": "Edytuj grupę", + "admin.access-control.groups.form.groupName": "Nazwa grupy", + "admin.access-control.groups.form.groupCommunity": "Zbiór lub kolekcja", + "admin.access-control.groups.form.groupDescription": "Opis", + "admin.access-control.groups.form.notification.created.success": "Udało się utworzyć grupę \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure": "Nie udało się utworzyć grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Nie udało się utworzyć grupy o nazwie: \"{{name}}\", upewnij się, że nazwa nie jest już używana.", + "admin.access-control.groups.form.notification.edited.failure": "Nie udało się edytować grupy \"{{name}}\"", + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Nazwa \"{{name}}\" już w użyciu!", + "admin.access-control.groups.form.notification.edited.success": "Udało się edytować grupę \"{{name}}\"", + "admin.access-control.groups.form.actions.delete": "Usuń grupę", + "admin.access-control.groups.form.delete-group.modal.header": "Usuń grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.info": "Czy na pewno chcesz usunąć grupę \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.cancel": "Anuluj", + "admin.access-control.groups.form.delete-group.modal.confirm": "Usuń", + "admin.access-control.groups.form.notification.deleted.success": "Udało się usunąć grupę \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.title": "Nie udało się usunąć grupy \"{{ name }}\"", + "admin.access-control.groups.form.notification.deleted.failure.content": "Powód: \"{{ cause }}\"", + "admin.access-control.groups.form.members-list.head": "Użytkownik", + "admin.access-control.groups.form.members-list.search.head": "Dodaj użytkownika", + "admin.access-control.groups.form.members-list.button.see-all": "Pokaż wszystkich", + "admin.access-control.groups.form.members-list.headMembers": "Aktualni członkowie", + "admin.access-control.groups.form.members-list.search.scope.metadata": "Metadane", + "admin.access-control.groups.form.members-list.search.scope.email": "E-mail", + "admin.access-control.groups.form.members-list.search.button": "Wyszukaj", + "admin.access-control.groups.form.members-list.table.id": "ID", + "admin.access-control.groups.form.members-list.table.name": "Nazwa", + "admin.access-control.groups.form.members-list.table.identity": "Tożsamość", + "admin.access-control.groups.form.members-list.table.email": "E-mail", + "admin.access-control.groups.form.members-list.table.netid": "NetID", + "admin.access-control.groups.form.members-list.table.edit": "Usuń / Dodaj", + "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Usuń użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.addMember": "Udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.addMember": "Nie udało się dodać użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Nie udało się usunąć użytkownika o nazwie: \"{{name}}\"", + "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Dodaj użytkownika o nazwie \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.members-list.no-members-yet": "Brak użytkowników w grupie, wyszukaj ich i dodaj.", + "admin.access-control.groups.form.members-list.no-items": "Nie znaleziono użytkowników podczas wyszukiwania", + "admin.access-control.groups.form.subgroups-list.notification.failure": "Coś poszło nie tak: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head": "Grupy", + "admin.access-control.groups.form.subgroups-list.search.head": "Dodaj podgrupę", + "admin.access-control.groups.form.subgroups-list.button.see-all": "Przeglądaj wszystkie", + "admin.access-control.groups.form.subgroups-list.headSubgroups": "Aktualne podgrupy", + "admin.access-control.groups.form.subgroups-list.search.button": "Wyszukaj", + "admin.access-control.groups.form.subgroups-list.table.id": "ID", + "admin.access-control.groups.form.subgroups-list.table.name": "Nazwa", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Zbiór/kolekcja", + "admin.access-control.groups.form.subgroups-list.table.edit": "Usuń / Dodaj", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Usuń podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Dodaj podgrupę o nazwie \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Aktualna grupa", + "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Udało się dodać podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Nie udało się dodać podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Udało się usunąć podgrupę: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Nie udało się usunąć podgrupy: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę grupy.", + "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ta grupa jest już stworzona i nie może zostać dodana pononwie.", + "admin.access-control.groups.form.subgroups-list.no-items": "Nie znaleziono grup z tą nazwą lub UUID", + "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Brak podgrup w grupie.", + "admin.access-control.groups.form.return": "Powrót", + "admin.search.breadcrumbs": "Wyszukiwanie administracyjne", + "admin.search.collection.edit": "Edytuj", + "admin.search.community.edit": "Edytuj", + "admin.search.item.delete": "Usuń", + "admin.search.item.edit": "Edytuj", + "admin.search.item.make-private": "Ukryj", + "admin.search.item.make-public": "Upublicznij", + "admin.search.item.move": "Przenieś", + "admin.search.item.reinstate": "Zmień instancję", + "admin.search.item.withdraw": "Wycofane", + "admin.search.title": "Wyszukiwanie administracyjne", + "administrativeView.search.results.head": "Wyszukiwanie administracyjne", + "admin.workflow.breadcrumbs": "Zarządzaj procesem", + "admin.workflow.title": "Zarządzaj procesem", + "admin.workflow.item.workflow": "Proces", + "admin.workflow.item.delete": "Usuń", + "admin.workflow.item.send-back": "Odeślij z powrotem", + "admin.metadata-import.breadcrumbs": "Importuj metadane", + "admin.metadata-import.title": "Importuj metadane", + "admin.metadata-import.page.header": "Importuj metadane", + "admin.metadata-import.page.help": "Tutaj możesz zaimportować pliki CSV, w których znajdują się metadane do operacji wsadowej. Zaimportuj je poprzez upuszczenie ich lub znajdź je na swoim komputerze", + "admin.metadata-import.page.dropMsg": "Upuść plik w formacie CSV", + "admin.metadata-import.page.dropMsgReplace": "Upuść, aby zastąpić metadane w formacie CSV do importu", + "admin.metadata-import.page.button.return": "Powrót", + "admin.metadata-import.page.button.proceed": "Zastosuj", + "admin.metadata-import.page.error.addFile": "Najpierw wybierz plik!", + "auth.errors.invalid-user": "Niewłaściwy adres e-mail lub hasło.", + "auth.messages.expired": "Twoja sesja wygasła. Zaloguj się ponownie.", + "auth.messages.token-refresh-failed": "Odświeżenie sesji nie powiodło się. Zaloguj się ponownie.", + "bitstream.download.page": "Pobieranie {{bitstream}}...", + "bitstream.download.page.back": "Powrót", + "bitstream.edit.authorizations.link": "Edytuj polityki plików", + "bitstream.edit.authorizations.title": "Edytuj polityki plików", + "bitstream.edit.return": "Powrót", + "bitstream.edit.bitstream": "Pliki: ", + "bitstream.edit.form.description.hint": "Opcjonalnie wprowadź krótki opis pliku, np.: \"<i>Główna część artykułu</i>\" lub \"<i>Dane z eksperymentu</i>\".", + "bitstream.edit.form.description.label": "Opis", + "bitstream.edit.form.embargo.hint": "Pierwszy dzień, od kiedy dostęp zostanie udzielony. <b>Tej daty nie może być edytować w tym formularzu.</b> Aby wybrać okres embarga czasowego, wybierz <i>Status pozycji</i> tab, kliknij <i>Autoryzacje...</i>, stwórz lub edytuj plik <i>PRZEYCZTAJ</i> zasady i wybierz określoną <i>Datę początkową</i>.", + "bitstream.edit.form.embargo.label": "Embargo do wybranej daty", + "bitstream.edit.form.fileName.hint": "Zmiana nazwy pliku dla strumienia bitów. Zauważ, że zmieni to wyświetlany adres URL strumienia bitów, ale stare linki nadal będą działać, o ile nie zmieni się identyfikator sekwencji.", + "bitstream.edit.form.fileName.label": "Nazwa pliku", + "bitstream.edit.form.newFormat.label": "Opisz nowy format", + "bitstream.edit.form.newFormat.hint": "Program, którego użyto do stworzenia pliku i numer wersji (np.: \"<i>ACMESoft SuperApp version 1.5</i>\").", + "bitstream.edit.form.primaryBitstream.label": "Pierwotny plik", + "bitstream.edit.form.selectedFormat.hint": "Jeśli formatu nie ma na powyższej liście, <b>wybierz \"format not in list\" above</b> i opisz jako \"Describe new format\".", + "bitstream.edit.form.selectedFormat.label": "Wybrany format", + "bitstream.edit.form.selectedFormat.unknown": "Tego formatu nie ma na liście", + "bitstream.edit.notifications.error.format.title": "Wystąpił błąd podczas zapisu formatu pliku", + "bitstream.edit.notifications.saved.content": "Zmiany w pliku zostały zapisane.", + "bitstream.edit.notifications.saved.title": "Plik został zapisany", + "bitstream.edit.title": "Edytuj plik", + "bitstream-request-a-copy.alert.canDownload1": "Masz już dostęp do tego pliki. Jeśli chcesz go pobrać, kliknij ", + "bitstream-request-a-copy.alert.canDownload2": "tutaj", + "bitstream-request-a-copy.header": "Wystąp o kopię wybranego pliku", + "bitstream-request-a-copy.intro": "Wpisz następujące informacje, aby wystąpić o kopię tej pozycji: ", + "bitstream-request-a-copy.intro.bitstream.one": "Wystąpienie o dostęp do następujących plików: ", + "bitstream-request-a-copy.intro.bitstream.all": "Wystąpienie o dostęp do wszystkich plików. ", + "bitstream-request-a-copy.name.label": "Imię *", + "bitstream-request-a-copy.name.error": "Imię jest wymagane", + "bitstream-request-a-copy.email.label": "Adres e-mail *", + "bitstream-request-a-copy.email.hint": "Plik zostanie przesłany na podany adres e-mail", + "bitstream-request-a-copy.email.error": "Proszę wprowadzić prawidłowy adres e-mail", + "bitstream-request-a-copy.allfiles.label": "Pliki", + "bitstream-request-a-copy.files-all-false.label": "Tylko plik, dla którego wystąpiono o dostęp", + "bitstream-request-a-copy.files-all-true.label": "Wszystkie pliki (w tej pozycji) z ograniczonym dostępem", + "bitstream-request-a-copy.message.label": "Wiadomość", + "bitstream-request-a-copy.return": "Powrót", + "bitstream-request-a-copy.submit": "Wystąp o kopię", + "bitstream-request-a-copy.submit.success": "Wystąpienie o dostęp do pliku zostało przesłane.", + "bitstream-request-a-copy.submit.error": "Coś poszło nie tak podczas wysyłania wystąpienia o dostęp do pliku", + "browse.comcol.by.author": "wg autorów", + "browse.comcol.by.dateissued": "wg daty wydania", + "browse.comcol.by.subject": "wg tematu", + "browse.comcol.by.title": "wg tytułu", + "browse.comcol.head": "Przeglądaj", + "browse.empty": "Brak rekordów do wyświetlenia.", + "browse.metadata.author": "Autor", + "browse.metadata.dateissued": "Data wydania", + "browse.metadata.subject": "Temat", + "browse.metadata.title": "Tytuł", + "browse.metadata.author.breadcrumbs": "Przeglądaj wg autorów", + "browse.metadata.dateissued.breadcrumbs": "Przeglądaj wg daty wydania", + "browse.metadata.subject.breadcrumbs": "Przeglądaj wg tematów", + "browse.metadata.title.breadcrumbs": "Przeglądaj wg tytułów", + "browse.startsWith.choose_start": "(Wybierz start)", + "browse.startsWith.choose_year": "(Wybierz rok)", + "browse.startsWith.choose_year.label": "Wybierz rok wydania", + "browse.startsWith.jump": "Przejdź do miejsca w indeksie:", + "browse.startsWith.months.april": "kwiecień", + "browse.startsWith.months.august": "sierpień", + "browse.startsWith.months.december": "grudzień", + "browse.startsWith.months.february": "luty", + "browse.startsWith.months.january": "styczeń", + "browse.startsWith.months.july": "lipiec", + "browse.startsWith.months.june": "czerwiec", + "browse.startsWith.months.march": "marzec", + "browse.startsWith.months.may": "maj", + "browse.startsWith.months.none": "(wybierz miesiąc)", + "browse.startsWith.months.none.label": "Wybierz miesiąc wydania", + "browse.startsWith.months.november": "listopad", + "browse.startsWith.months.october": "październik", + "browse.startsWith.months.september": "wrzesień", + "browse.startsWith.submit": "Zastosuj", + "browse.startsWith.type_date": "Lub wybierz datę (rok-miesiąc) i kliknij 'Przeglądaj'", + "browse.startsWith.type_date.label": "Lub wybierz datę (rok-miesiąc) i kliknij przycisk przeglądania", + "browse.startsWith.type_text": "Wpisz kilka pierwszych liter i kliknij przycisk przeglądania", + "browse.title": "Przeglądaj {{ collection }} wg {{ field }} {{ value }}", + "chips.remove": "Usuń chip", + "collection.create.head": "Utwórz kolekcję", + "collection.create.notifications.success": "Udało się utworzyć kolekcję", + "collection.create.sub-head": "Udało się utworzyć kolekcję dla zbioru {{ parent }}", + "collection.curate.header": "Administrator kolekcji: {{collection}}", + "collection.delete.cancel": "Anuluj", + "collection.delete.confirm": "Zatwierdź", + "collection.delete.processing": "Usuwanie", + "collection.delete.head": "Usuń kolekcję", + "collection.delete.notification.fail": "Kolekcja nie może być usunięt", + "collection.delete.notification.success": "Udało się usunąć kolekcję", + "collection.delete.text": "Czy na pewno chcesz usunąć kolekcję \"{{ dso }}\"", + "collection.edit.delete": "Usuń kolekcję", + "collection.edit.head": "Edytuj kolekcję", + "collection.edit.breadcrumbs": "Edytuj kolekcję", + "collection.edit.tabs.mapper.head": "Item Mapper", + "collection.edit.tabs.item-mapper.title": "Edytuj kolekcję - Item Mapper", + "collection.edit.item-mapper.cancel": "Anuluj", + "collection.edit.item-mapper.collection": "Kolekcja: \"<b>{{name}}</b>\"", + "collection.edit.item-mapper.confirm": "Mapuj wybrane elementy", + "collection.edit.item-mapper.description": "To jest narzędzie mapowania elementów, które pozwala administratorom kolekcji mapować elementy z innych kolekcji do tej kolekcji. Możesz wyszukiwać elementy z innych kolekcji i mapować je lub przeglądać listę aktualnie zmapowanych elementów.", + "collection.edit.item-mapper.head": "Item Mapper - Mapuj pozycje z innych kolekcji", + "collection.edit.item-mapper.no-search": "Wpisz co chcesz wyszukać", + "collection.edit.item-mapper.notifications.map.error.content": "Wystąpiły błędy podczas mapowania {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.error.head": "Mapowanie błędów", + "collection.edit.item-mapper.notifications.map.success.content": "Udało się zmapować {{amount}} pozycji.", + "collection.edit.item-mapper.notifications.map.success.head": "Mapowanie zakończone", + "collection.edit.item-mapper.notifications.unmap.error.content": "Błędy wystąpiły podczas usuwania mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.error.head": "Usuń błędy mapowania", + "collection.edit.item-mapper.notifications.unmap.success.content": "Udało się usunąć błędy mapowania z {{amount}} elementów.", + "collection.edit.item-mapper.notifications.unmap.success.head": "Usuwanie mapowania zakończone", + "collection.edit.item-mapper.remove": "Usuń wybrane mapowanie elementów", + "collection.edit.item-mapper.search-form.placeholder": "Wyszukaj pozycje...", + "collection.edit.item-mapper.tabs.browse": "Wyszukaj mapowane elementy", + "collection.edit.item-mapper.tabs.map": "Mapuj nowe elementy", + "collection.edit.logo.delete.title": "Usuń", + "collection.edit.logo.delete-undo.title": "Cofnij usunięcie", + "collection.edit.logo.label": "Logo kolekcji", + "collection.edit.logo.notifications.add.error": "Przesyłanie logo kolekcji nie powiodło się. Proszę zweryfikować zawartość przed ponowną ", + "collection.edit.logo.notifications.add.success": "Udało się przesłać logo kolekcji.", + "collection.edit.logo.notifications.delete.success.title": "Logo usunięte", + "collection.edit.logo.notifications.delete.success.content": "Udało się usunąć logo kolekcji", + "collection.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", + "collection.edit.logo.upload": "Upuść logo kolekcji, aby je wgrać", + "collection.edit.notifications.success": "Udało się edytować kolekcję", + "collection.edit.return": "Powrót", + "collection.edit.tabs.curate.head": "Kurator", + "collection.edit.tabs.curate.title": "Edytowanie kolekcji - kurator", + "collection.edit.tabs.authorizations.head": "Autoryzacje", + "collection.edit.tabs.authorizations.title": "Edytowanie kolekcji - autoryzacje", + "collection.edit.tabs.metadata.head": "Edytuj metadane", + "collection.edit.tabs.metadata.title": "Edytowanie kolekcji - metadane", + "collection.edit.tabs.roles.head": "Przypisz role", + "collection.edit.tabs.roles.title": "Edytowanie kolekcji - role", + "collection.edit.tabs.source.external": "Ta kolekcja pobiera swoją zawartość z zewnętrznego źródła", + "collection.edit.tabs.source.form.errors.oaiSource.required": "Musisz wskazać id docelowej kolekcji.", + "collection.edit.tabs.source.form.harvestType": "Odczytywanie zawartości", + "collection.edit.tabs.source.form.head": "Skonfiguruj zewnętrzne źródło", + "collection.edit.tabs.source.form.metadataConfigId": "Format metadanych", + "collection.edit.tabs.source.form.oaiSetId": "Określony zestaw ID OAI", + "collection.edit.tabs.source.form.oaiSource": "Dostawca OAI", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Odczytaj metadane i pliki (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Odczytaj metadane i bibliografię (wymaga wsparcia ORE)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Odczytaj tylko metadane", + "collection.edit.tabs.source.head": "Źródło treści", + "collection.edit.tabs.source.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby odzyskać swoje zmiany wybierz 'Powrót'", + "collection.edit.tabs.source.notifications.discarded.title": "Zmiany odrzucone", + "collection.edit.tabs.source.notifications.invalid.content": "Zmiany nie zostały zapisane. Sprawdź czy wszystkie pola są wypełnione poprawne przed zapisem.", + "collection.edit.tabs.source.notifications.invalid.title": "Nieprawidłowe metadane", + "collection.edit.tabs.source.notifications.saved.content": "Zmiany wprowadzone w kolekcji zostały zapisane.", + "collection.edit.tabs.source.notifications.saved.title": "Źródło treści zapisane", + "collection.edit.tabs.source.title": "Collection Edit - Źródło treści", + "collection.edit.template.add-button": "Dodaj", + "collection.edit.template.breadcrumbs": "Szablon pozycji", + "collection.edit.template.cancel": "Anuluj", + "collection.edit.template.delete-button": "Usuń", + "collection.edit.template.edit-button": "Edytuj", + "collection.edit.template.error": "Wystąpił błąd podczas odzyskiwania szablonu pozycji", + "collection.edit.template.head": "Edytuj szablon dla kolekcji \"{{ collection }}\"", + "collection.edit.template.label": "Szablon pozycji", + "collection.edit.template.loading": "ładowanie szablonu pozycji...", + "collection.edit.template.notifications.delete.error": "Nie udało się usunąć szablonu pozycji", + "collection.edit.template.notifications.delete.success": "Udało się usunąć szablon pozycji", + "collection.edit.template.title": "Edytuj szablon pozycji", + "collection.form.abstract": "Opis skrócony", + "collection.form.description": "Tekst powitalny (HTML)", + "collection.form.errors.title.required": "Wpisz nazwę kolekcji", + "collection.form.license": "Licencja", + "collection.form.provenance": "Pochodzenie", + "collection.form.rights": "Tekst praw autorskich (HTML)", + "collection.form.tableofcontents": "Wiadomości (HTML)", + "collection.form.title": "Nazwa", + "collection.form.entityType": "Typ danych", + "collection.page.browse.recent.head": "Ostatnie zgłoszenia", + "collection.page.browse.recent.empty": "Brak pozycji do wyświetlenia", + "collection.page.edit": "Edytuj kolekcję", + "collection.page.handle": "Stały URI dla kolekcji", + "collection.page.license": "Licencja", + "collection.page.news": "Wiadomości", + "collection.select.confirm": "Zaakceptuj zaznaczone", + "collection.select.empty": "Brak kolekcji do wyświetlenia", + "collection.select.table.title": "Tytuł", + "collection.source.controls.head": "Kontrolki odczytywania", + "collection.source.controls.test.submit.error": "Coś poszło nie tak podczas rozpoczynania testów ustawień", + "collection.source.controls.test.failed": "Scenariusz testowy ustawień nie zadziałał", + "collection.source.controls.test.completed": "Scenariusz testowy ustawień został zakończony", + "collection.source.controls.test.submit": "Konfiguracja testowa", + "collection.source.controls.test.running": "Testowanie konfiguracji...", + "collection.source.controls.import.submit.success": "Import został rozpoczęty", + "collection.source.controls.import.submit.error": "Coś poszło nie tak podczas rozpoczynania importu", + "collection.source.controls.import.submit": "Importuj teraz", + "collection.source.controls.import.running": "Importowanie...", + "collection.source.controls.import.failed": "Wystąpił błąd podczas importu", + "collection.source.controls.import.completed": "Import zakończony", + "collection.source.controls.reset.submit.success": "Reset ustawień i powtórny import zostały rozpoczęte poprawnie", + "collection.source.controls.reset.submit.error": "Coś poszło nie tak podczas rozpoczynania zresetowanego, powtórnego importu", + "collection.source.controls.reset.failed": "Wystąpił błąd podczas resetowania ustawień i ponownego importu", + "collection.source.controls.reset.completed": "Reset ustawień i powtórny import zostały zakończone", + "collection.source.controls.reset.submit": "Resetowanie i powtórny import", + "collection.source.controls.reset.running": "Resetowanie i powtórny import...", + "collection.source.controls.harvest.status": "Status odczytywania:", + "collection.source.controls.harvest.start": "Czas rozpoczęcia odczytywania:", + "collection.source.controls.harvest.last": "Czas ostatniego odczytywania:", + "collection.source.controls.harvest.message": "Informacje nt. odczytywania:", + "collection.source.controls.harvest.no-information": "bd.", + "collection.source.update.notifications.error.content": "Te ustawienia zostały przetestowane i nie działają.", + "collection.source.update.notifications.error.title": "Błąd serwera", + "communityList.breadcrumbs": "Lista zbiorów", + "communityList.tabTitle": "Lista zbiorów", + "communityList.title": "Lista zbiorów", + "communityList.showMore": "Pokaż więcej", + "community.create.head": "Utwórz zbiór", + "community.create.notifications.success": "Udało się utworzyć zbiór", + "community.create.sub-head": "Utwórz podzbiór dla zbioru {{ parent }}", + "community.curate.header": "Zarządzaj zbiorem: {{community}}", + "community.delete.cancel": "Anuluj", + "community.delete.confirm": "Potwierdź", + "community.delete.processing": "Usuwanie...", + "community.delete.head": "Usuń zbiór", + "community.delete.notification.fail": "Zbiór nie może być usunięty", + "community.delete.notification.success": "Udało się usunąć zbiór", + "community.delete.text": "Czy na pewno chcesz usunąć zbiór \"{{ dso }}\"", + "community.edit.delete": "Usuń ten zbiór", + "community.edit.head": "Edytuj zbiór", + "community.edit.breadcrumbs": "Edytuj zbiór", + "community.edit.logo.delete.title": "Usuń logo", + "community.edit.logo.delete-undo.title": "Cofnij usunięcie", + "community.edit.logo.label": "Logo zbioru", + "community.edit.logo.notifications.add.error": "Przesłanie loga zbioru nie powiodło się. Sprawdź czy wszystkie parametry są odpowiednie przed próbą ponownego przesłania.", + "community.edit.logo.notifications.add.success": "Przesłanie loga powiodło się.", + "community.edit.logo.notifications.delete.success.title": "Logo usunięte", + "community.edit.logo.notifications.delete.success.content": "Usunięcie loga zbioru powiodło się", + "community.edit.logo.notifications.delete.error.title": "Błąd podczas usuwania loga", + "community.edit.logo.upload": "Upuść logo zbioru, aby je przesłać", + "community.edit.notifications.success": "Udało się edytować zbiór", + "community.edit.notifications.unauthorized": "Nie masz uprawnień, aby wykonać te zmiany", + "community.edit.notifications.error": "Wystąpił błąd podczas edycji zbioru", + "community.edit.return": "Cofnij", + "community.edit.tabs.curate.head": "Administruj", + "community.edit.tabs.curate.title": "Edycja zbioru - administrator", + "community.edit.tabs.metadata.head": "Edytuj metadane", + "community.edit.tabs.metadata.title": "Edycja zbioru - metadane", + "community.edit.tabs.roles.head": "Przypisz role", + "community.edit.tabs.roles.title": "Edycja zbioru - role", + "community.edit.tabs.authorizations.head": "Uprawnienia", + "community.edit.tabs.authorizations.title": "Edycja zbioru - uprawnienia", + "community.listelement.badge": "Zbiór", + "comcol-role.edit.no-group": "Brak", + "comcol-role.edit.create": "Utwórz", + "comcol-role.edit.restrict": "Ogranicz", + "comcol-role.edit.delete": "Usuń", + "comcol-role.edit.community-admin.name": "Administratorzy", + "comcol-role.edit.collection-admin.name": "Administratorzy", + "comcol-role.edit.community-admin.description": "Administratorzy zbioru mogą tworzyć podzbiory lub kolekcje i zarządzać nimi lub przydzielać zarządzanie tymi podzbiorami lub kolekcji innym użytkownikom. Ponadto decydują, kto może przesyłać elementy do dowolnych podkolekcji, edytować metadane pozycji (po przesłaniu) i dodawać (mapować) istniejące pozycje z innych kolekcji (z zastrzeżeniem autoryzacji).", + "comcol-role.edit.collection-admin.description": "Administratorzy kolekcji decydują o tym, kto może przesyłać pozycje do kolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące elementy z innych kolekcji do tej kolekcji (z zastrzeżeniem uprawnień dla danej kolekcji).", + "comcol-role.edit.submitters.name": "Zgłaszający", + "comcol-role.edit.submitters.description": "Użytkownicy i grupy, którzy mają uprawnienia do przesyłania nowych pozycji do tej kolekcji.", + "comcol-role.edit.item_read.name": "Domyślny dostęp do odczytu pozycji", + "comcol-role.edit.item_read.description": "Użytkownicy i grupy, które mogą odczytywać nowe pozycje zgłoszone do tej kolekcji. Zmiany w tej roli nie działają wstecz. Istniejące pozycje w systemie będą nadal widoczne dla osób, które miały dostęp do odczytu w momencie ich dodania.", + "comcol-role.edit.item_read.anonymous-group": "Domyślny odczyt dla nowych pozycji jest obecnie ustawiony na Anonimowy.", + "comcol-role.edit.bitstream_read.name": "Domyślny dostęp do oczytu plików", + "comcol-role.edit.bitstream_read.description": "Administratorzy zbiorów mogą tworzyć podzbiory lub kolekcje, a także zarządzać nimi. Ponadto decydują o tym, kto może przesyłać elementy do podkolekcji, edytować metadane pozycji (po ich przesłaniu) oraz dodawać (mapować) istniejące pozycje z innych kolekcji (pod warunkiem posiadania odpowiednich uprawnień).", + "comcol-role.edit.bitstream_read.anonymous-group": "Domyślny status odczytu dla nowych plików to Anonimowy.", + "comcol-role.edit.editor.name": "Redaktorzy", + "comcol-role.edit.editor.description": "Redaktorzy mogą edytować metadane nowych pozycji, a następnie akceptować je lub odrzucać.", + "comcol-role.edit.finaleditor.name": "Redaktorzy końcowi", + "comcol-role.edit.finaleditor.description": "Redaktorzy końcowi mogą edytować metadane nowych pozycji, ale nie mogę odrzucać pozycji.", + "comcol-role.edit.reviewer.name": "Recenzenci", + "comcol-role.edit.reviewer.description": "Recenzenci mogą akceptować lub odrzucać nowe pozycje, ale nie mogę edytować ich metadanych.", + "community.form.abstract": "Opis skrócony", + "community.form.description": "Wstęp (HTML)", + "community.form.errors.title.required": "Wprowadź nazwę zbioru", + "community.form.rights": "Prawa autoskie (HTML)", + "community.form.tableofcontents": "Wiadomości (HTML)", + "community.form.title": "Nazwa", + "community.page.edit": "Edytuj ten zbiór", + "community.page.handle": "Stały URI zbioru", + "community.page.license": "Licencja", + "community.page.news": "Wiadomości", + "community.all-lists.head": "Podzbiory i kolekcje", + "community.sub-collection-list.head": "Kolekcje w tym zbiorze", + "community.sub-community-list.head": "Kolekcje w tym zbiorze", + "cookies.consent.accept-all": "Zaakceptuj wszystko", + "cookies.consent.accept-selected": "Zaakceptuj wybrane", + "cookies.consent.app.opt-out.description": "Aplikacja jest domyślnie włączona (możesz ją wyłączyć)", + "cookies.consent.app.opt-out.title": "(możesz ją wyłaczyć)", + "cookies.consent.app.purpose": "cel", + "cookies.consent.app.required.description": "Ta aplikacja jest zawsze wymagana", + "cookies.consent.app.required.title": "(zawsze wymagana)", + "cookies.consent.update": "Od ostatniej wizyty zostały wprowadzone zmiany. Zweryfikuj swoje zgody.", + "cookies.consent.close": "Zamknij", + "cookies.consent.decline": "Odrzuć", + "cookies.consent.content-notice.description": "Zbieramy i przetwarzamy Twoje dane do następujących celów: <strong>weryfikacja, preferencje, zgody i statystyka</strong>. <br/> Jeśli chcesz się dowiedzieć więcej, przycztaj naszą {privacyPolicy}.", + "cookies.consent.content-notice.learnMore": "Dostosuj", + "cookies.consent.content-modal.description": "Tutaj są wyświetlane informacje, które zbieramy o Tobie. Możesz je dostosować według swojego uznania.", + "cookies.consent.content-modal.privacy-policy.name": "polityka prywatności", + "cookies.consent.content-modal.privacy-policy.text": "Aby dowiedzieć się więcej przeczytaj naszą {privacyPolicy}.", + "cookies.consent.content-modal.title": "Informacje, które zbieramy", + "cookies.consent.app.title.authentication": "Logowanie", + "cookies.consent.app.description.authentication": "Musisz się zalogować", + "cookies.consent.app.title.preferences": "Preferencje", + "cookies.consent.app.description.preferences": "Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.acknowledgement": "Zgody", + "cookies.consent.app.description.acknowledgement": "Wymagane, aby zapisać Twoje preferencje", + "cookies.consent.app.title.google-analytics": "Google Analytics", + "cookies.consent.app.description.google-analytics": "Pozwól na śledzenie do celów statystycznych", + "cookies.consent.purpose.functional": "Funkcjonalne", + "cookies.consent.purpose.statistical": "Statystyczne", + "curation-task.task.checklinks.label": "Sprawdź odnośniki w metadanych", + "curation-task.task.noop.label": "NOOP", + "curation-task.task.profileformats.label": "Profil formatów plików", + "curation-task.task.requiredmetadata.label": "Sprawdź poprawność wymaganych metadanych", + "curation-task.task.translate.label": "Microsoft Translator", + "curation-task.task.vscan.label": "Skan antywirusowy", + "curation.form.task-select.label": "Zadanie:", + "curation.form.submit": "Start", + "curation.form.submit.success.head": "Udało się rozpocząć zadanie administratora", + "curation.form.submit.success.content": "Zostaniesz przeniesiony na stronę procesu.", + "curation.form.submit.error.head": "Nie udało się się zakończyć zadania administratora", + "curation.form.submit.error.content": "Wystąpił błąd podczas rozpoczynania zadania administracyjnego.", + "curation.form.handle.label": "Automatyzacja:", + "curation.form.handle.hint": "Wskazówka: Wpisz [prefix swojego identyfikatora]/0, aby zautomatyzować zadanie (nie wszystkie zadania mogą wspierać tę funkcję)", + "deny-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, przykro mi poinformować, że to niemożliwe, aby przestać kopię pliku, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.subject": "Wystąp o kopię dokumentu", + "deny-request-copy.error": "Wystąpił błąd", + "deny-request-copy.header": "Odrzuć prośbę o przesłanie kopii dokumentu", + "deny-request-copy.intro": "Ta wiadomość zostanie przesłana do osoby, która wystąpiła o dostęp", + "deny-request-copy.success": "Z powodzeniem odrzucono prośbę o udostępnienie pozycji", + "dso.name.untitled": "Brak tytułu", + "dso-selector.claim.item.head": "Wskazówki profilu", + "dso-selector.claim.item.body": "Istnieją profile, które mogą odnosić się do Ciebie. Jeśli, któryś z tych profilów jest Twój, wybierz go i przejdź do szczegółów, z opcji wybierz opcję przypisania profilu. W innym przypadku możesz utworzyć nowy profil z szablonu, wybierając przycisk poniżej.", + "dso-selector.claim.item.create-from-scratch": "Utwórz nowy", + "dso-selector.claim.item.not-mine-label": "Żaden nie jest mój", + "dso-selector.create.collection.head": "Nowa kolekcja", + "dso-selector.create.collection.sub-level": "Utwórz nową kolekcję w", + "dso-selector.create.community.head": "Nowy zbiór", + "dso-selector.create.community.sub-level": "Utwórz nowy zbiór", + "dso-selector.create.community.top-level": "Utwórz nowy nadrzędny zbiór", + "dso-selector.create.item.head": "Nowa pozycja", + "dso-selector.create.item.sub-level": "Utwórz nową pozycję w", + "dso-selector.create.submission.head": "Nowe zgłoszenie", + "dso-selector.edit.collection.head": "Edytuj kolekcję", + "dso-selector.edit.community.head": "Edytuj zbiór", + "dso-selector.edit.item.head": "Edytuj pozycję", + "dso-selector.error.title": "Wystąpił błąd podczas wyszukiwania typu {{ type }}", + "dso-selector.export-metadata.dspaceobject.head": "Eksportuj metadane z", + "dso-selector.no-results": "Nie znaleziono {{ type }}", + "dso-selector.placeholder": "Wyszukaj {{ type }}", + "dso-selector.select.collection.head": "Wybierz kolekcję", + "dso-selector.set-scope.community.head": "Wybierz wyszukiwanie zakresu", + "dso-selector.set-scope.community.button": "Wyszukaj w całym DSpace", + "dso-selector.set-scope.community.input-header": "Wyszukaj zbiór lub kolekcję", + "confirmation-modal.export-metadata.header": "Eksportuj metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.info": "Czy na pewno chcesz eksportować metadane z {{ dsoName }}", + "confirmation-modal.export-metadata.cancel": "Anuluj", + "confirmation-modal.export-metadata.confirm": "Eksportuj", + "confirmation-modal.delete-eperson.header": "Usuń użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Czy na pewno chcesz usunąć użytkownika \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.cancel": "Anuluj", + "confirmation-modal.delete-eperson.confirm": "Usuń", + "error.bitstream": "Wystąpił błąd podczas tworzenia plików", + "error.browse-by": "Wystąpił błąd podczas tworzenia pozycji", + "error.collection": "Wystąpił błąd podczas tworzenia kolekcji", + "error.collections": "Wystąpił błąd podczas tworzenia kolekcji", + "error.community": "Wystąpił błąd podczas tworzenia ziboru", + "error.identifier": "Nie znaleziono pozycji z podanym identyfikatorem", + "error.default": "Błąd", + "error.item": "Wystąpił błąd podczas tworzenia pozycji", + "error.items": "Wystąpił błąd podczas tworzenia pozycji", + "error.objects": "Wystąpił błąd podczas tworzenia obiektów", + "error.recent-submissions": "Wystąpił błąd podczas tworzenia ostatniego zgłoszenia", + "error.search-results": "Wystąpił błąd podczas tworzenia wyników wyszukiwania", + "error.sub-collections": "Wystąpił błąd podczas tworzenia podkolekcji", + "error.sub-communities": "Wystąpił błąd podczas tworzenia podzbiorów", + "error.submission.sections.init-form-error": "Wystąpił błąd w czasie inicjalizacji sekcji, sprawdź konfigurację. Szczegóły poniżej: <br> <br>", + "error.top-level-communities": "Błąd podczas pobierania nadrzędnego zbioru", + "error.validation.license.notgranted": "Musisz wyrazić tę zgodę, aby przesłać swoje zgłoszenie. Jeśli nie możesz wyrazić zgody w tym momencie, możesz zapisać swoją pracę i wrócić do niej później lub usunąć zgłoszenie.", + "error.validation.pattern": "Te dane wejściowe są ograniczone przez aktualny wzór: {{ pattern }}.", + "error.validation.filerequired": "Przesłanie pliku jest obowiązkowe", + "error.validation.required": "Pole jest wymagane", + "error.validation.NotValidEmail": "E-mail nie jest poprawny", + "error.validation.emailTaken": "E-mail jest już zarejestrowany", + "error.validation.groupExists": "Ta grupa już istnieje", + "file-section.error.header": "Błąd podczas uzyskiwania plików dla tej pozycji", + "footer.copyright": "copyright © 2002-{{ year }}", + "footer.link.dspace": "oprogramowanie DSpace", + "footer.link.lyrasis": "LYRASIS", + "footer.link.cookies": "Ustawienia plików cookies", + "footer.link.privacy-policy": "Polityka prywatności", + "footer.link.end-user-agreement": "Umowa użytkownika", + "forgot-email.form.header": "Nie pamiętam hasła", + "forgot-email.form.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "forgot-email.form.email": "Adres e-mail *", + "forgot-email.form.email.error.required": "Uzupełnij adres e-mail", + "forgot-email.form.email.error.pattern": "Uzupełnij prawidłowy adres e-mail", + "forgot-email.form.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "forgot-email.form.submit": "Wyślij", + "forgot-email.form.success.head": "Wysłano wiadomość weryfikacyjną", + "forgot-email.form.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "forgot-email.form.error.head": "Błąd podczas rejestracji adresu e-mail", + "forgot-email.form.error.content": "Wystąpił błąd poczas próby rejestracji tego adresu e-mail: {{ email }}", + "forgot-password.title": "Nie pamiętam hasła", + "forgot-password.form.head": "Nie pamiętam hasła", + "forgot-password.form.info": "Wpisz nowe hasło w polu poniżej i potwierdź je wpisując je ponownie w drugim polu. Hasło powinno mieć co najmniej sześć znaków.", + "forgot-password.form.card.security": "Bezpieczeństwo", + "forgot-password.form.identification.header": "Identifikacja", + "forgot-password.form.identification.email": "Adres e-mail: ", + "forgot-password.form.label.password": "Hasło", + "forgot-password.form.label.passwordrepeat": "Potwierdź hasło", + "forgot-password.form.error.empty-password": "Wpisz hasło poniżej.", + "forgot-password.form.error.matching-passwords": "Hasła nie są identyczne.", + "forgot-password.form.notification.error.title": "Błąd podczas próby ustawienia nowego hasła", + "forgot-password.form.notification.success.content": "Resetowanie hasła udało się. Zalogowano jako stworzony przed momemntem użytkownik.", + "forgot-password.form.notification.success.title": "Resetowanie hasła udane", + "forgot-password.form.submit": "Wpisz hasło", + "form.add": "Dodaj", + "form.add-help": "Wybierz ten przycisk, aby dodać aktualny wpis lub dodać następny", + "form.cancel": "Anuluj", + "form.clear": "Wyczyść", + "form.clear-help": "Kliknij tutaj, aby usunąć wybraną wartość", + "form.discard": "Odrzuć", + "form.drag": "Przeciągnij", + "form.edit": "Edytuj", + "form.edit-help": "Kliknij tutaj, aby edytować wybraną wartość", + "form.first-name": "Imię", + "form.last-name": "Nazwisko", + "form.loading": "Ładowanie...", + "form.lookup": "Przeglądaj", + "form.lookup-help": "Kliknij tutaj, aby zobaczyć istniejące powiązania", + "form.no-results": "Nie znaleziono rezultatów", + "form.no-value": "Nie wprowadzono wartości", + "form.remove": "Usuń", + "form.save": "Zapisz", + "form.save-help": "Zapisz zmiany", + "form.search": "Wyszukaj", + "form.search-help": "Kliknij tutaj, aby wyszukać w istniejących komentarzach", + "form.submit": "Zapisz", + "form.repeatable.sort.tip": "Upuść nową pozycję w nowym miejscu", + "grant-deny-request-copy.deny": "Nie przesyłaj kopii", + "grant-deny-request-copy.email.back": "Cofnij", + "grant-deny-request-copy.email.message": "Wiadomości", + "grant-deny-request-copy.email.message.empty": "Proszę wprowadzić wiadomość", + "grant-deny-request-copy.email.permissions.info": "W tym miejscu możesz przemyśleć ograniczenie dostępu do dokumentu, aby odpowiadać na mniej próśb o dostęp. Jeśli chcesz wystąpić do administratorów reposytorium o zniesienie restrykcji, zaznacz okienko poniżej.", + "grant-deny-request-copy.email.permissions.label": "Ustaw jako otwarty dostęp", + "grant-deny-request-copy.email.send": "Wyślij", + "grant-deny-request-copy.email.subject": "Temat", + "grant-deny-request-copy.email.subject.empty": "Wpisz temat", + "grant-deny-request-copy.grant": "Wyślij kopię", + "grant-deny-request-copy.header": "Prośba o przesłanie kopii dokumentu", + "grant-deny-request-copy.home-page": "Zabierz mnie na stronę główną", + "grant-deny-request-copy.intro1": "Jeśli jesteś jednym z autorów dokumentu <a href='{{ url }}'>{{ name }}</a>, wybierz jedną z poniższych opcji, aby odpowiedzieć zapytaniu użytkownika.", + "grant-deny-request-copy.intro2": "Po wybraniu opcji, zostaną wyświetlone sugerowane odpowiedzi, które można edytować.", + "grant-deny-request-copy.processed": "Ta prośba jest już procesowana. Możesz użyć przycisku poniżej, aby wrócić do strony głównej.", + "grant-request-copy.email.message": "Drogi użytkowniku {{ recipientName }},\nW odpowiedzi na Państwa zapytanie, miło mi poinformować, że w załączniku przesyłam kopię dokumentu, o który Państwo prosili: \"{{ itemUrl }}\" ({{ itemName }}), którego jestem autorem.\n\nPozdrawiam serdecznie,\n{{ authorName }} <{{ authorEmail }}>", + "grant-request-copy.email.subject": "Prośba o kopię dokumentu", + "grant-request-copy.error": "Wystąpił błąd", + "grant-request-copy.header": "Zezwól na wysłanie kopii dokumentu", + "grant-request-copy.intro": "To wiadomość zostanie wysłana do osoby, która wystąpiła o dostęp. Wskazane dokumenty zostaną dołączone jako załącznik.", + "grant-request-copy.success": "Prośba o dostęp do dokumentu została przyjęta", + "home.description": "", + "home.breadcrumbs": "Strona główna", + "home.search-form.placeholder": "Przeszukaj repozytorium...", + "home.title": "Strona główna", + "home.top-level-communities.head": "Zbiory w DSpace", + "home.top-level-communities.help": "Przeszukaj kolekcje", + "info.end-user-agreement.accept": "Przeczytałem/am i akceptuję umowę użytkownika", + "info.end-user-agreement.accept.error": "Błąd wystąpił podczas akceptowania umowy użytkownika", + "info.end-user-agreement.accept.success": "Udało się zaktualizować umowę użytkownika", + "info.end-user-agreement.breadcrumbs": "Umowa użytkownika", + "info.end-user-agreement.buttons.cancel": "Anuluj", + "info.end-user-agreement.buttons.save": "Zapisz", + "info.end-user-agreement.head": "Umowa użytkownika", + "info.end-user-agreement.title": "Umowa użytkownika", + "info.privacy.breadcrumbs": "Oświadczenie polityki prywatności", + "info.privacy.head": "Oświadczenie polityki prywatności", + "info.privacy.title": "Oświadczenie polityki prywatności", + "item.alerts.private": "Ta pozycja jest prywatna", + "item.alerts.withdrawn": "Ta pozycja została wycofana", + "item.edit.authorizations.heading": "Za pomocą tego edytora możesz przeglądać i zmieniać polityki dla danej pozycji, a także zmieniać polityki dla poszczególnych części pozycji: paczek i strumieni bitów. W skrócie, pozycja jest kontenerem pakietów, a pakiety są kontenerami strumieni bitów. Kontenery zazwyczaj mają polityki ADD/REMOVE/READ/WRITE, natomiast strumienie bitów mają tylko polityki READ/WRITE.", + "item.edit.authorizations.title": "Edytuj politykę tej pozycji", + "item.badge.private": "Prywatny status publikacji", + "item.badge.withdrawn": "Wycofane publikacje", + "item.bitstreams.upload.bundle": "Pakiet", + "item.bitstreams.upload.bundle.placeholder": "Wybierz pakiet", + "item.bitstreams.upload.bundle.new": "Utworz pakiet", + "item.bitstreams.upload.bundles.empty": "Ta pozycja nie zawiera żadnych pakietów, do których można przesłać strumień bitów.", + "item.bitstreams.upload.cancel": "Anuluj", + "item.bitstreams.upload.drop-message": "Upuść plik, aby przesłać", + "item.bitstreams.upload.item": "Pozycja: ", + "item.bitstreams.upload.notifications.bundle.created.content": "Udało się utworzyć nowy pakiet.", + "item.bitstreams.upload.notifications.bundle.created.title": "Utwórz pakiet", + "item.bitstreams.upload.notifications.upload.failed": "Zweryfikuj pliki przed spróbowaniem ponownie.", + "item.bitstreams.upload.title": "Prześlij strumień bitów", + "item.edit.bitstreams.bundle.edit.buttons.upload": "Prześlij", + "item.edit.bitstreams.bundle.displaying": "Obecnie wyświetlono {{ amount }} plików z {{ total }}.", + "item.edit.bitstreams.bundle.load.all": "Załaduj wszystkie ({{ total }})", + "item.edit.bitstreams.bundle.load.more": "Załaduj więcej", + "item.edit.bitstreams.bundle.name": "PACZKA: {{ name }}", + "item.edit.bitstreams.discard-button": "Odrzuć", + "item.edit.bitstreams.edit.buttons.download": "Pobierz", + "item.edit.bitstreams.edit.buttons.drag": "Przeciągnij", + "item.edit.bitstreams.edit.buttons.edit": "Edytuj", + "item.edit.bitstreams.edit.buttons.remove": "Usuń", + "item.edit.bitstreams.edit.buttons.undo": "Cofnij zmiany", + "item.edit.bitstreams.empty": "Ta pozycja nie zawiera żadnych strumieni bitów. Wybierz strumienie do załadowania, aby je utworzyć.", + "item.edit.bitstreams.headers.actions": "Akcje", + "item.edit.bitstreams.headers.bundle": "Paczka", + "item.edit.bitstreams.headers.description": "Opis", + "item.edit.bitstreams.headers.format": "Format", + "item.edit.bitstreams.headers.name": "Nazwa", + "item.edit.bitstreams.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby je przywrócić, wybierz przycisk 'Cofnij'", + "item.edit.bitstreams.notifications.discarded.title": "Zmiany odrzucone", + "item.edit.bitstreams.notifications.move.failed.title": "Błąd podczas przenoszenia plików", + "item.edit.bitstreams.notifications.move.saved.content": "Zmiany pozycji dla pliku tej pozycji oraz jego paczki zostały zapisane.", + "item.edit.bitstreams.notifications.move.saved.title": "Zmiana pozycji została zapisana", + "item.edit.bitstreams.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć ewentualnych konfliktów", + "item.edit.bitstreams.notifications.outdated.title": "Zmiany nieaktualne", + "item.edit.bitstreams.notifications.remove.failed.title": "Błąd podczas usuwania pliku", + "item.edit.bitstreams.notifications.remove.saved.content": "Twoje zmiany dotyczące usunięcia plików z tej pozycji zostały zapisane.", + "item.edit.bitstreams.notifications.remove.saved.title": "Zmiany dotyczące usunięcia zapisane", + "item.edit.bitstreams.reinstate-button": "Cofnij", + "item.edit.bitstreams.save-button": "Zapisz", + "item.edit.bitstreams.upload-button": "Prześlij", + "item.edit.delete.cancel": "Anuluj", + "item.edit.delete.confirm": "Usuń", + "item.edit.delete.description": "Czy jesteś pewien, że ta pozycja powinna zostać całkowicie usunięta? Ostrożnie: Teraz nie pozostanie po tej pozycji żaden ślad.", + "item.edit.delete.error": "Błąd wystąpił podczas usuwania pozycji", + "item.edit.delete.header": "Usuń pozycję: {{ id }}", + "item.edit.delete.success": "Ta pozycja została usunięta", + "item.edit.head": "Edytuj pozycję", + "item.edit.breadcrumbs": "Edytuj pozycję", + "item.edit.tabs.disabled.tooltip": "Nie masz dostępu do tej strony", + "item.edit.tabs.mapper.head": "Mapper kolekcji", + "item.edit.tabs.item-mapper.title": "Edytowanie pozycji - Mapper kolekcji", + "item.edit.item-mapper.buttons.add": "Mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.buttons.remove": "Usuń mapowanie pozycji do wybranych kolekcji", + "item.edit.item-mapper.cancel": "Anuluj", + "item.edit.item-mapper.description": "To jest narzędzie do mapowania elementów, które pozwala administratorom mapować tę pozycję do innych kolekcji. Możesz wyszukiwać kolekcje i je mapować lub przeglądać listę kolekcji, do których dana pozycja jest aktualnie zmapowana.", + "item.edit.item-mapper.head": "Mapper pozycji - Mapowanie pozycji do kolekcji", + "item.edit.item-mapper.item": "Pozycja: \"<b>{{name}}</b>\"", + "item.edit.item-mapper.no-search": "Wpisz zapytanie, które chcesz wyszukać", + "item.edit.item-mapper.notifications.add.error.content": "Wystąpiły błędy dla mapowania pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.add.error.head": "Błędy mapowania", + "item.edit.item-mapper.notifications.add.success.content": "Udało się zmapować elementy dla {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.add.success.head": "Mapowanie zakończone", + "item.edit.item-mapper.notifications.remove.error.content": "Wystąpiły błędy podczas usuwania mapowania do {{amount}} kolekcji.", + "item.edit.item-mapper.notifications.remove.error.head": "Usunięcie mapowania błędów", + "item.edit.item-mapper.notifications.remove.success.content": "Udało się usunąć mapowanie pozycji w {{amount}} kolekcjach.", + "item.edit.item-mapper.notifications.remove.success.head": "Usuwanie mapowania zakończone", + "item.edit.item-mapper.search-form.placeholder": "Przeszukaj kolekcje...", + "item.edit.item-mapper.tabs.browse": "Przeglądaj zmapowane kolekcje", + "item.edit.item-mapper.tabs.map": "Mapuj nowe kolekcje", + "item.edit.metadata.add-button": "Dodaj", + "item.edit.metadata.discard-button": "Odrzuć", + "item.edit.metadata.edit.buttons.edit": "Edytuj", + "item.edit.metadata.edit.buttons.remove": "Usuń", + "item.edit.metadata.edit.buttons.undo": "Cofnij zmiany", + "item.edit.metadata.edit.buttons.unedit": "Zatrzymaj edycję", + "item.edit.metadata.empty": "Ta pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby dodać metadane.", + "item.edit.metadata.headers.edit": "Edytuj", + "item.edit.metadata.headers.field": "Pole", + "item.edit.metadata.headers.language": "Język", + "item.edit.metadata.headers.value": "Wartość", + "item.edit.metadata.metadatafield.invalid": "Wybierz aktualne pole metadanych", + "item.edit.metadata.notifications.discarded.content": "Twoje zmiany zostały odrzucone. Aby wgrać je ponownie wybierz przycisk 'Cofnij'", + "item.edit.metadata.notifications.discarded.title": "Zmiany odrzucone", + "item.edit.metadata.notifications.error.title": "Wystąpił błąd", + "item.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Przed zapisaniem upewnij się, że wszystkie pola są wypełnione prawidłowo.", + "item.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadane", + "item.edit.metadata.notifications.outdated.content": "Pozycja została w międzyczasie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby zapobiec ewentualnym konfliktom", + "item.edit.metadata.notifications.outdated.title": "Zmiany nieaktualne", + "item.edit.metadata.notifications.saved.content": "Twoje zmiany metadanych tej pozycji zostały zapisane.", + "item.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", + "item.edit.metadata.reinstate-button": "Cofnij", + "item.edit.metadata.save-button": "Zapisz", + "item.edit.modify.overview.field": "Pole", + "item.edit.modify.overview.language": "Język", + "item.edit.modify.overview.value": "Wartość", + "item.edit.move.cancel": "Anuluj", + "item.edit.move.save-button": "Zapisz", + "item.edit.move.discard-button": "Odrzuć", + "item.edit.move.description": "Wybierz kolekcję, do której chcesz przenieść tę pozycję. Aby zawęzić listę wyświetlanych kolekcji, możesz wprowadzić zapytanie w polu wyszukiwania.", + "item.edit.move.error": "Wystąpił błąd podczas przenoszenia pozycji", + "item.edit.move.head": "Przenieś pozycję: {{id}}", + "item.edit.move.inheritpolicies.checkbox": "Dziedziczenie polityk", + "item.edit.move.inheritpolicies.description": "Dziedzczenie domyślnych polityk z kolekcji docelowej", + "item.edit.move.move": "Przenieś", + "item.edit.move.processing": "Przenoszenie...", + "item.edit.move.search.placeholder": "Wpisz zapytanie, aby wyszukać w kolekcjach", + "item.edit.move.success": "Pozycja została przeniesiona", + "item.edit.move.title": "Przenieś pozycję", + "item.edit.private.cancel": "Anuluj", + "item.edit.private.confirm": "Ukryj", + "item.edit.private.description": "Czy chcesz ukryć tę pozycję?", + "item.edit.private.error": "Wystąpił błąd podczas ukrywania pozycji", + "item.edit.private.header": "Ukryj pozycję: {{ id }}", + "item.edit.private.success": "Pozycja jest teraz ukryta", + "item.edit.public.cancel": "Anuluj", + "item.edit.public.confirm": "Upublicznij", + "item.edit.public.description": "Czy chcesz upublicznić tę pozycję?", + "item.edit.public.error": "Wystąpił błąd podczas upubliczniania pozycji", + "item.edit.public.header": "Upublicznij pozycję: {{ id }}", + "item.edit.public.success": "Pozycja jest teraz publiczna", + "item.edit.reinstate.cancel": "Anuluj", + "item.edit.reinstate.confirm": "Przywróć", + "item.edit.reinstate.description": "Czy chcesz przywrócić tę pozycję?", + "item.edit.reinstate.error": "Wystąpił błąd podczas przywracania pozycji", + "item.edit.reinstate.header": "Przywróć pozycję: {{ id }}", + "item.edit.reinstate.success": "Pozycja została przywrócona", + "item.edit.relationships.discard-button": "Odrzuć", + "item.edit.relationships.edit.buttons.add": "Dodaj", + "item.edit.relationships.edit.buttons.remove": "Usuń", + "item.edit.relationships.edit.buttons.undo": "Cofnij zmiany", + "item.edit.relationships.no-relationships": "Brak relacji", + "item.edit.relationships.notifications.discarded.content": "Twoje zmiany zostały cofnięte. Aby przywrócić zmiany wybierz przycisk 'Cofnij'", + "item.edit.relationships.notifications.discarded.title": "Zmiany zostały cofnięte", + "item.edit.relationships.notifications.failed.title": "Wystąpił błąd podczas edytowania relacji", + "item.edit.relationships.notifications.outdated.content": "Ta pozycja została właśnie zmieniona przez innego użytkownika. Twoje zmiany zostały cofnięte, aby uniknąć konfliktów", + "item.edit.relationships.notifications.outdated.title": "Zmiany są nieaktualne", + "item.edit.relationships.notifications.saved.content": "Twoje zmiany w relacjach tej pozycji zostały zapisane.", + "item.edit.relationships.notifications.saved.title": "Relacje zostały zapisane", + "item.edit.relationships.reinstate-button": "Cofnij", + "item.edit.relationships.save-button": "Zapisz", + "item.edit.relationships.no-entity-type": "Dodaj metadaną 'dspace.entity.type', aby umożliwić dodawanie relacji do pozycji", + "item.edit.return": "Cofnij", + "item.edit.tabs.bitstreams.head": "Pliki", + "item.edit.tabs.bitstreams.title": "Edycja pozycji - pliki", + "item.edit.tabs.curate.head": "Administruj", + "item.edit.tabs.curate.title": "Edytowanie pozycji - administruj", + "item.edit.tabs.metadata.head": "Metadane", + "item.edit.tabs.metadata.title": "Edycja pozycji - metadane", + "item.edit.tabs.relationships.head": "Relacje", + "item.edit.tabs.relationships.title": "Edycja pozycja - relacje", + "item.edit.tabs.status.buttons.authorizations.button": "Dostępy...", + "item.edit.tabs.status.buttons.authorizations.label": "Określu dostęp do pozycji", + "item.edit.tabs.status.buttons.delete.button": "Usuń permanentnie", + "item.edit.tabs.status.buttons.delete.label": "Usuń pozycję permanentnie", + "item.edit.tabs.status.buttons.mappedCollections.button": "Zmapowane kolekcje", + "item.edit.tabs.status.buttons.mappedCollections.label": "Zarządzaj mapowanymi kolekcjami", + "item.edit.tabs.status.buttons.move.button": "Przenieś...", + "item.edit.tabs.status.buttons.move.label": "Przenieś pozycję do innej kolekcji", + "item.edit.tabs.status.buttons.private.button": "Ukryj...", + "item.edit.tabs.status.buttons.private.label": "Ukry pozycję", + "item.edit.tabs.status.buttons.public.button": "Upublicznij...", + "item.edit.tabs.status.buttons.public.label": "Upublicznij pozycję", + "item.edit.tabs.status.buttons.reinstate.button": "Przywróć...", + "item.edit.tabs.status.buttons.reinstate.label": "Przywróć pozycję", + "item.edit.tabs.status.buttons.unauthorized": "You're not authorized to perform this action", + "item.edit.tabs.status.buttons.withdraw.button": "Wycofaj...", + "item.edit.tabs.status.buttons.withdraw.label": "Wycofaj z repozytorium", + "item.edit.tabs.status.description": "Witamy na stronie zarządzania pozycjami. Z tego miejsca możesz wycofać, przywrócić, przenieść lub usunąć daną pozycję. Możesz również aktualizować lub dodawać nowe metadane lub pliki..", + "item.edit.tabs.status.head": "Status", + "item.edit.tabs.status.labels.handle": "Identyfikator", + "item.edit.tabs.status.labels.id": "ID pozycji", + "item.edit.tabs.status.labels.itemPage": "Strona pozycji", + "item.edit.tabs.status.labels.lastModified": "Ostatnia modyfikacja", + "item.edit.tabs.status.title": "Edycja pozycji - Status", + "item.edit.tabs.versionhistory.head": "Historia wersji", + "item.edit.tabs.versionhistory.title": "Edycja pozycji - historia wersji", + "item.edit.tabs.versionhistory.under-construction": "Edytowanie lub dodawanie nowych wersji jest niedostępne w tego poziomu interfejsu.", + "item.edit.tabs.view.head": "Widok pozycji", + "item.edit.tabs.view.title": "Edycja pozycji - widok", + "item.edit.withdraw.cancel": "Anuluj", + "item.edit.withdraw.confirm": "Wycofaj", + "item.edit.withdraw.description": "Czy na pewno chcesz wycofać pozycję?", + "item.edit.withdraw.error": "Wystąpił błąd podczas wycofywania pozycji", + "item.edit.withdraw.header": "Wycofaj pozycję: {{ id }}", + "item.edit.withdraw.success": "Pozycja została wycofana", + "item.listelement.badge": "Pozycja", + "item.page.description": "Opis", + "item.page.journal-issn": "ISSN czasopisma", + "item.page.journal-title": "Tytuł czasopisma", + "item.page.publisher": "Wydawca", + "item.page.titleprefix": "Pozycja: ", + "item.page.volume-title": "Tytuł tomu", + "item.search.results.head": "Wyniki wyszukiwania pozycji", + "item.search.title": "Wyszukiwanie pozycji", + "item.page.abstract": "Abstrakt", + "item.page.author": "Autorzy", + "item.page.citation": "Cytowanie", + "item.page.collections": "Kolekcje", + "item.page.collections.loading": "Ładowanie...", + "item.page.collections.load-more": "Załaduj więcej", + "item.page.date": "Data", + "item.page.edit": "Edytuj pozycję", + "item.page.files": "Pliki", + "item.page.filesection.description": "Opis:", + "item.page.filesection.download": "Pobierz", + "item.page.filesection.format": "Format:", + "item.page.filesection.name": "Nazwa:", + "item.page.filesection.size": "Rozmiar:", + "item.page.journal.search.title": "Artykuły w czasopiśmie", + "item.page.link.full": "Zobacz szczegóły", + "item.page.link.simple": "Uproszczony widok", + "item.page.person.search.title": "Artykuły tego autora", + "item.page.related-items.view-more": "Pokaż o {{ amount }} więcej", + "item.page.related-items.view-less": "Ukryj {{ amount }}", + "item.page.relationships.isAuthorOfPublication": "Publikacje", + "item.page.relationships.isJournalOfPublication": "Publikacje", + "item.page.relationships.isOrgUnitOfPerson": "Autorzy", + "item.page.relationships.isOrgUnitOfProject": "Projekty naukowe", + "item.page.subject": "Słowa kluczowe", + "item.page.uri": "URI", + "item.page.bitstreams.view-more": "Pokaż więcej", + "item.page.bitstreams.collapse": "Pokaż mniej", + "item.page.filesection.original.bundle": "Oryginalne pliki", + "item.page.filesection.license.bundle": "Licencja", + "item.page.return": "Powrót", + "item.page.version.create": "Utwórz nową wersję", + "item.page.version.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.preview.dc.identifier.doi": "DOI", + "item.preview.dc.relation.ispartof": "Czasopismo lub seria", + "item.preview.dc.identifier.isbn": "ISBN", + "item.preview.dc.identifier.uri": "Identyfikator:", + "item.preview.dc.contributor.author": "Autorzy:", + "item.preview.dc.date.issued": "Data publikacji:", + "item.preview.dc.description.abstract": "Abstrakt:", + "item.preview.dc.identifier.other": "Inny identyfikator:", + "item.preview.dc.language.iso": "Język:", + "item.preview.dc.title": "Tytuł:", + "item.preview.dc.title.alternative": "Tytuł alternatywny", + "item.preview.dc.type": "Typ:", + "item.preview.dc.identifier": "Identyfikator:", + "item.preview.dc.relation.issn": "ISSN", + "item.preview.oaire.citation.issue": "Numer wydania", + "item.preview.oaire.citation.volume": "Numer tomu", + "item.preview.person.familyName": "Nazwisko:", + "item.preview.person.givenName": "Nazwa:", + "item.preview.person.identifier.orcid": "ORCID:", + "item.preview.project.funder.name": "Fundator:", + "item.preview.project.funder.identifier": "Identyfikator fundatora:", + "item.preview.oaire.awardNumber": "ID finansowania:", + "item.preview.dc.coverage.spatial": "Jurysdykcja:", + "item.preview.oaire.fundingStream": "Źródło finansowania:", + "item.select.confirm": "Potwierdź zaznaczone", + "item.select.empty": "Brak pozycji do wyświetlenia", + "item.select.table.author": "Autor", + "item.select.table.collection": "Kolekcja", + "item.select.table.title": "Tytuł", + "item.version.history.empty": "Jeszcze nie ma innych wersji tej pozycji.", + "item.version.history.head": "Poprzednie wersje", + "item.version.history.return": "Powrót", + "item.version.history.selected": "Wybrane wersje", + "item.version.history.selected.alert": "W tym momencie wyświetlono wersję {{version}} pozycji.", + "item.version.history.table.version": "Wersja", + "item.version.history.table.item": "Pozycja", + "item.version.history.table.editor": "Redaktor", + "item.version.history.table.date": "Data", + "item.version.history.table.summary": "Podsumowanie", + "item.version.history.table.workspaceItem": "Wersja robocza", + "item.version.history.table.workflowItem": "Pozycja workflow", + "item.version.history.table.actions": "Akcja", + "item.version.history.table.action.editWorkspaceItem": "Edytuj wersję roboczą pozycji", + "item.version.history.table.action.editSummary": "Edytuj podsumowanie", + "item.version.history.table.action.saveSummary": "Zapisz edycje podsumowania", + "item.version.history.table.action.discardSummary": "Odrzuć edycje podsumowania", + "item.version.history.table.action.newVersion": "Utwórz nową wersję z tej wersji", + "item.version.history.table.action.deleteVersion": "Wersja usunięta", + "item.version.history.table.action.hasDraft": "Nowa wersja nie może zostać utworzona, ponieważ istnieje już oczekujące na akceptację zgłoszenie dokumentu tego pliku", + "item.version.notice": "To nie jest najnowsza wersja tej pozycji. Najnowsza wersja jest dostępna <a href='{{destination}}'>tutaj</a>.", + "item.version.create.modal.header": "Nowa wersja", + "item.version.create.modal.text": "Utwórz nową wersję tej pozycji", + "item.version.create.modal.text.startingFrom": "zaczynając od wersji {{version}}", + "item.version.create.modal.button.confirm": "Utwórz", + "item.version.create.modal.button.confirm.tooltip": "Utwórz nową wersję", + "item.version.create.modal.button.cancel": "Anuluj", + "item.version.create.modal.button.cancel.tooltip": "Nie stwarzaj nowej wersji", + "item.version.create.modal.form.summary.label": "Podsumowanie", + "item.version.create.modal.form.summary.placeholder": "Wprowadź podsumowanie nowej wersji", + "item.version.create.notification.success": "Nowa wersja została utworzona z numerem {{version}}", + "item.version.create.notification.failure": "Nowa wersja nie została utworzona", + "item.version.create.notification.inProgress": "Nowa wersja nie może być utworzona, ponieważ propozycja innej wersji jest już złożona do zaakceptowania", + "item.version.delete.modal.header": "Usuń wersję", + "item.version.delete.modal.text": "Czy chcesz usunąć wersję {{version}}?", + "item.version.delete.modal.button.confirm": "Usuń", + "item.version.delete.modal.button.confirm.tooltip": "Usuń wersję", + "item.version.delete.modal.button.cancel": "Anuluj", + "item.version.delete.modal.button.cancel.tooltip": "Nie usuwaj tej wersji", + "item.version.delete.notification.success": "Wersja {{version}} została usunięta", + "item.version.delete.notification.failure": "Wersja {{version}} nie została usunięta", + "item.version.edit.notification.success": "Podsumowanie wersji {{version}} zostało zmienione", + "item.version.edit.notification.failure": "Podsumowanie wersji {{version}} nie zostało zmienione", + "journal.listelement.badge": "Czasopismo", + "journal.page.description": "Opis", + "journal.page.edit": "Edytuj tę pozycję", + "journal.page.editor": "Redaktor naczelny", + "journal.page.issn": "ISSN", + "journal.page.publisher": "Wydawca", + "journal.page.titleprefix": "Czasopismo: ", + "journal.search.results.head": "Wyniki wyszukiwania czasopism", + "journal.search.title": "Wyszukiwanie czasopism", + "journalissue.listelement.badge": "Numer czasopisma", + "journalissue.page.description": "Opis", + "journalissue.page.edit": "Edytuj pozycję", + "journalissue.page.issuedate": "Data wydania", + "journalissue.page.journal-issn": "ISSN czasopisma", + "journalissue.page.journal-title": "Tytuł czasopisma", + "journalissue.page.keyword": "Słowa kluczowe", + "journalissue.page.number": "Numer", + "journalissue.page.titleprefix": "Wydanie czasopisma: ", + "journalvolume.listelement.badge": "Numer tomu czasopisma", + "journalvolume.page.description": "Opis", + "journalvolume.page.edit": "Edytuj pozycję", + "journalvolume.page.issuedate": "Data wydania", + "journalvolume.page.titleprefix": "Numer tomu czasopisma: ", + "journalvolume.page.volume": "Numer wydania", + "iiifsearchable.listelement.badge": "Multimedia dokumentu", + "iiifsearchable.page.titleprefix": "Dokument: ", + "iiifsearchable.page.doi": "Stały link: ", + "iiifsearchable.page.issue": "Wydanie: ", + "iiifsearchable.page.description": "Opis: ", + "iiifviewer.fullscreen.notice": "Wyświetl na pełnym ekranie dla lepszego widoku.", + "iiif.listelement.badge": "Multimedia obrazu", + "iiif.page.titleprefix": "Obraz: ", + "iiif.page.doi": "Stały link: ", + "iiif.page.issue": "Numer wydania: ", + "iiif.page.description": "Opis: ", + "loading.bitstream": "Ładowanie pliku...", + "loading.bitstreams": "Ładowanie plików...", + "loading.browse-by": "Ładowanie pozycji...", + "loading.browse-by-page": "Ładowanie strony...", + "loading.collection": "Ładowanie kolekcji...", + "loading.collections": "Ładowanie kolekcji...", + "loading.content-source": "Ładowanie źródła treści...", + "loading.community": "Ładowanie zbioru...", + "loading.default": "Ładowanie...", + "loading.item": "Ładowanie pozycji...", + "loading.items": "Ładowanie pozycji...", + "loading.mydspace-results": "Ładowanie pozycji...", + "loading.objects": "Ładowanie...", + "loading.recent-submissions": "Ładowanie ostatnich zgłoszeń...", + "loading.search-results": "Ładowanie wyników wyszukiwania...", + "loading.sub-collections": "Ładowanie podkolekcji...", + "loading.sub-communities": "Ładowanie podzbioru...", + "loading.top-level-communities": "Ładowanie zbioru wyszego szczebla...", + "login.form.email": "Adres e-mail", + "login.form.forgot-password": "Nie pamiętasz hasła?", + "login.form.header": "Zaloguj się do DSpace", + "login.form.new-user": "Nie masz konta? Zarejestruj się.", + "login.form.or-divider": "lub", + "login.form.orcid": "Zaloguj za pomocą ORCID", + "login.form.oidc": "Zaloguj za pomocą OIDC", + "login.form.password": "Hasło", + "login.form.shibboleth": "Zaloguj za pomocą Shibboleth", + "login.form.submit": "Zaloguj się", + "login.title": "Zaloguj", + "login.breadcrumbs": "Zaloguj", + "logout.form.header": "Wyloguj się z DSpace", + "logout.form.submit": "Wyloguj się", + "logout.title": "Wylogowywanie", + "menu.header.admin": "Panel administracyjny", + "menu.header.image.logo": "Logo repozytorium", + "menu.header.admin.description": "Menu administratora", + "menu.section.access_control": "Uprawnienia", + "menu.section.access_control_authorizations": "Dostępy", + "menu.section.access_control_groups": "Grupy", + "menu.section.access_control_people": "Użytkownicy", + "menu.section.admin_search": "Wyszukiwanie administracyjne", + "menu.section.browse_community": "Ten zbiór", + "menu.section.browse_community_by_author": "Wg autorów", + "menu.section.browse_community_by_issue_date": "Wg daty wydania", + "menu.section.browse_community_by_title": "Wg tytułów", + "menu.section.browse_global": "Wszystko na DSpace", + "menu.section.browse_global_by_author": "Wg autorów", + "menu.section.browse_global_by_dateissued": "Wg daty wydania", + "menu.section.browse_global_by_subject": "Wg tematu", + "menu.section.browse_global_by_title": "Wg tytułu", + "menu.section.browse_global_communities_and_collections": "Zbiory i kolekcje", + "menu.section.control_panel": "Panel sterowania", + "menu.section.curation_task": "Zadanie administracyjne", + "menu.section.edit": "Edytuj", + "menu.section.edit_collection": "Kolekcja", + "menu.section.edit_community": "Zbiór", + "menu.section.edit_item": "Pozycja", + "menu.section.export": "Eksport", + "menu.section.export_collection": "Kolekcja", + "menu.section.export_community": "Zbiór", + "menu.section.export_item": "Pozycja", + "menu.section.export_metadata": "Metadane", + "menu.section.icon.access_control": "Sekcja menu Uprawnienia", + "menu.section.icon.admin_search": "Sekcja menu Wyszukiwanie administracyjne", + "menu.section.icon.control_panel": "Sekcja menu Panel sterowania", + "menu.section.icon.curation_tasks": "Sekcja menu Zadanie administracyjne", + "menu.section.icon.edit": "Sekcja menu Edycja", + "menu.section.icon.export": "Sekcja menu Eksport", + "menu.section.icon.find": "Sekcja menu Wyszukiwanie", + "menu.section.icon.import": "Sekcja menu Import", + "menu.section.icon.new": "Sekcja menu Dodaj", + "menu.section.icon.pin": "Przypnij boczny pasek", + "menu.section.icon.processes": "Sekcja menu Procesy", + "menu.section.icon.registries": "Sekcja menu Rejestry", + "menu.section.icon.statistics_task": "Sekcja menu Zadanie statystyczne", + "menu.section.icon.workflow": "Sekcja menu Zarządzanie workflow", + "menu.section.icon.unpin": "Odepnij boczny pasek", + "menu.section.import": "Import", + "menu.section.import_batch": "Import masowy (ZIP)", + "menu.section.import_metadata": "Metadane", + "menu.section.new": "Dodaj", + "menu.section.new_collection": "Kolekcja", + "menu.section.new_community": "Zbiór", + "menu.section.new_item": "Pozycja", + "menu.section.new_item_version": "Wersja pozycji", + "menu.section.new_process": "Proces", + "menu.section.pin": "Przypnij pasek boczny", + "menu.section.unpin": "Odepnij pasek boczny", + "menu.section.processes": "Procesy", + "menu.section.registries": "Rejestry", + "menu.section.registries_format": "Formaty", + "menu.section.registries_metadata": "Metadane", + "menu.section.statistics": "Statystyki", + "menu.section.statistics_task": "Zadanie statystyczne", + "menu.section.toggle.access_control": "Przełącz sekcję Uprawnienia", + "menu.section.toggle.control_panel": "Przełącz sekcję Panel sterowania", + "menu.section.toggle.curation_task": "Przełącz sekcję Zadanie kuratora", + "menu.section.toggle.edit": "Przełącz sekcję Edytuj", + "menu.section.toggle.export": "Przełącz sekcję Eksport", + "menu.section.toggle.find": "Przełącz sekcję Wyszukiwanie", + "menu.section.toggle.import": "Przełącz sekcję Import", + "menu.section.toggle.new": "Przełącz nową sekcję", + "menu.section.toggle.registries": "Przełącz sekcję Rejestry", + "menu.section.toggle.statistics_task": "Przełącz sekcję Zadanie statystyczne", + "menu.section.workflow": "Zarządzaj Workflow", + "mydspace.breadcrumbs": "Mój DSpace", + "mydspace.description": "", + "mydspace.messages.controller-help": "Wybierz tę opcję, aby przesłać wiadomość do zgłaszającego.", + "mydspace.messages.description-placeholder": "Wpisz swoją wiadomość tutaj...", + "mydspace.messages.hide-msg": "Ukryj wiadomość", + "mydspace.messages.mark-as-read": "Oznacz jako przeczytane", + "mydspace.messages.mark-as-unread": "Oznacz jako nieprzeczytane", + "mydspace.messages.no-content": "Brak treści.", + "mydspace.messages.no-messages": "Brak wiadomości.", + "mydspace.messages.send-btn": "Wysłano", + "mydspace.messages.show-msg": "Pokaż wiadomość", + "mydspace.messages.subject-placeholder": "Temat...", + "mydspace.messages.submitter-help": "Wybierz tę opcję, aby przesłać wiadomość do osoby kontrolującej.", + "mydspace.messages.title": "Wiadomości", + "mydspace.messages.to": "Do", + "mydspace.new-submission": "Nowe zgłoszenie", + "mydspace.new-submission-external": "Import medatanych z zewnętrznego źródła", + "mydspace.new-submission-external-short": "Import metadanych", + "mydspace.results.head": "Twoje zadania", + "mydspace.results.no-abstract": "Brak abstraktu", + "mydspace.results.no-authors": "Brak autorów", + "mydspace.results.no-collections": "Brak kolekcji", + "mydspace.results.no-date": "Brak daty", + "mydspace.results.no-files": "Brak plików", + "mydspace.results.no-results": "Brak pozycji do wyświetlenia", + "mydspace.results.no-title": "Brak tytułu", + "mydspace.results.no-uri": "Brak Uri", + "mydspace.search-form.placeholder": "Wyszukaj w mydspace...", + "mydspace.show.workflow": "Wszystkie zadania", + "mydspace.show.workspace": "Twoje zadania", + "mydspace.status.mydspaceArchived": "Zarchiwizowano", + "mydspace.status.mydspaceValidation": "Walidacja", + "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redaktora", + "mydspace.status.mydspaceWorkflow": "Workflow", + "mydspace.status.mydspaceWorkspace": "Wersja robocza", + "mydspace.title": "Mój DSpace", + "mydspace.upload.upload-failed": "Bład podczas tworzenia nowej wersji roboczej. Sprawdź poprawność plików i spróbuj ponownie.", + "mydspace.upload.upload-failed-manyentries": "Plik jest niemożliwy do przetworzenia. Wykryto wiele wejść, a dopuszczalne jest tylko jedno dla jednego pliku.", + "mydspace.upload.upload-failed-moreonefile": "Zapytanie niemożliwe do przetworzenia. Tylko jeden plik jest dopuszczalny.", + "mydspace.upload.upload-multiple-successful": "Utworzono {{qty}} przestrzeni roboczych.", + "mydspace.view-btn": "Widok", + "nav.browse.header": "Cały DSpace", + "nav.community-browse.header": "Wg zbiorów", + "nav.language": "Zmień język", + "nav.login": "Zaloguj", + "nav.logout": "Menu profilu użytkownika i wylogowywanie", + "nav.main.description": "Główny pasek nawigacji", + "nav.mydspace": "Mój DSpace", + "nav.profile": "Profil", + "nav.search": "Wyszukiwanie", + "nav.statistics.header": "Statystyki", + "nav.stop-impersonating": "Przestań impersonifikować użytkownika", + "nav.toggle": "Przełącz nawigację", + "nav.user.description": "Pasek profilu użytkownika", + "none.listelement.badge": "Pozycja", + "person.listelement.badge": "Osoba", + "person.listelement.no-title": "Nie znaleziono imienia", + "person.page.birthdate": "Data urodzenia", + "person.page.edit": "Edytuj pozycję", + "person.page.email": "Adres e-mail", + "person.page.firstname": "Imię", + "person.page.jobtitle": "Stanowisko", + "person.page.lastname": "Nazwisko", + "person.page.link.full": "Pokaż wszystkie metadane", + "person.page.orcid": "ORCID", + "person.page.orcid.create": "Utwórz ORCID ID", + "person.page.orcid.granted-authorizations": "Udzielone dostępy", + "person.page.orcid.grant-authorizations": "Udziel dostępu", + "person.page.orcid.link": "Połącz z ORCID ID", + "person.page.orcid.orcid-not-linked-message": "ORCID iD tego profilu ({{ orcid }}) nie jest połączony z bazą ORCID lub połączenie wygasło.", + "person.page.orcid.unlink": "Odepnij z ORCID", + "person.page.orcid.unlink.processing": "Procesowanie...", + "person.page.orcid.missing-authorizations": "Brak dostępów", + "person.page.orcid.missing-authorizations-message": "Brakuj następujących dostępów:", + "person.page.orcid.no-missing-authorizations-message": "Świetnie! To miejsce jest puste, co oznacza, że masz dostęp do wszystkich uprawnień, które są dostępne w Twojej instytucji.", + "person.page.orcid.no-orcid-message": "Brak przypisanego ORCID iD. Poprez wybranie przycisku poniżej możesz powiązać ten profil wraz z kontem ORCID.", + "person.page.orcid.profile-preferences": "Preferencje profilu", + "person.page.orcid.funding-preferences": "Preferencje finansowania", + "person.page.orcid.publications-preferences": "Preferencje publikacji", + "person.page.orcid.remove-orcid-message": "Jeśli chcesz usunąć Twój ORCID, skontaktuj się z administratorem repozytorium", + "person.page.orcid.save.preference.changes": "Aktualizuj ustawienia", + "person.page.orcid.sync-profile.affiliation": "Afiliacja", + "person.page.orcid.sync-profile.biographical": "Biografia", + "person.page.orcid.sync-profile.education": "Edukacja", + "person.page.orcid.sync-profile.identifiers": "Identyfikatory", + "person.page.orcid.sync-fundings.all": "Wszystkie źrodła finansowania", + "person.page.orcid.sync-fundings.mine": "Moje źrodła finansowania", + "person.page.orcid.sync-fundings.my_selected": "Wybrane źródła finansowania", + "person.page.orcid.sync-fundings.disabled": "Nieaktywne", + "person.page.orcid.sync-publications.all": "Wszystkie publikacje", + "person.page.orcid.sync-publications.mine": "Moje publikacje", + "person.page.orcid.sync-publications.my_selected": "Wybrane publikacje", + "person.page.orcid.sync-publications.disabled": "Nieaktywne", + "person.page.orcid.sync-queue.discard": "Odrzuć zmianę i nie synchronizuj z ORCID", + "person.page.orcid.sync-queue.discard.error": "Rekord kolejki ORCID nie został odrzucony", + "person.page.orcid.sync-queue.discard.success": "Rekord kolejki ORCID został odrzucony", + "person.page.orcid.sync-queue.empty-message": "Rejestr kolejki w ORCID jest pusty", + "person.page.orcid.sync-queue.description.affiliation": "Afiliacje", + "person.page.orcid.sync-queue.description.country": "Kraj", + "person.page.orcid.sync-queue.description.education": "Edukacja", + "person.page.orcid.sync-queue.description.external_ids": "Zewnętrzne identyfikatory", + "person.page.orcid.sync-queue.description.other_names": "Inne imiona", + "person.page.orcid.sync-queue.description.qualification": "Kwalifikacje", + "person.page.orcid.sync-queue.description.researcher_urls": "URL naukowca", + "person.page.orcid.sync-queue.description.keywords": "Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.insert": "Dodaj nowy wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.update": "Aktualizuj ten wpis w rejestrze ORCID", + "person.page.orcid.sync-queue.tooltip.delete": "Usuń ten wpis z rejestru ORCID", + "person.page.orcid.sync-queue.tooltip.publication": "Publikacja", + "person.page.orcid.sync-queue.tooltip.affiliation": "Afiliacja", + "person.page.orcid.sync-queue.tooltip.education": "Edukacja", + "person.page.orcid.sync-queue.tooltip.qualification": "Kwalifikacje", + "person.page.orcid.sync-queue.tooltip.other_names": "Inna nazwa", + "person.page.orcid.sync-queue.tooltip.country": "Kraj", + "person.page.orcid.sync-queue.tooltip.keywords": "Słowa kluczowe", + "person.page.orcid.sync-queue.tooltip.external_ids": "Zewnętrzny identyfikator", + "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL naukowca", + "person.page.orcid.sync-queue.send": "Synchronizuj z rejestrem ORCID", + "person.page.orcid.sync-queue.send.unauthorized-error.title": "Wysłanie zgłoszenia do ORCID nieudane z powodu braku uprawnień.", + "person.page.orcid.sync-queue.send.unauthorized-error.content": "Wybierz <a href='{{orcid}}'>here</a>, aby wystąpić o niezbędne uprawnienia. Jeśli problem wciąż występuje, skontaktuj się z administratorem", + "person.page.orcid.sync-queue.send.bad-request-error": "Wysłanie zgłoszenia do ORCID nie powiodło się ponieważ źródła wysłane do rejestru ORCID nie jest poprawne", + "person.page.orcid.sync-queue.send.error": "Wysłanie zgłoszenia do ORCID nie powiodło się", + "person.page.orcid.sync-queue.send.conflict-error": "Zgłoszenie do ORCID nie powiodło się, ponieważ ta pozycja jest już dodana do rejestru ORCID", + "person.page.orcid.sync-queue.send.not-found-warning": "Pozycja nie istnieje już w rejestrze ORCID.", + "person.page.orcid.sync-queue.send.success": "Zgłoszenie do ORCID zostało zakończone pomyślnie", + "person.page.orcid.sync-queue.send.validation-error": "Dane, które chcesz zsynchronizować z ORCID nie są poprawne", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Waluta jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Aby wysłać pozycję, należy podać przynajmniej jeden identyfikator", + "person.page.orcid.sync-queue.send.validation-error.title.required": "Tytuł jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.type.required": "Typ jest wymagany", + "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Data początkowa jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.funder.required": "Instytucja finansująca jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.required": "Instytucja jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Nazwa instytucji jest wymagana", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Aby wysłać instytucję, należy podać adres", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Aby wysłać adres, należy podać miasto", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Aby wysłać adres, należy podać kraj", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Wymagany jest identyfikator umożliwiający rozróżnienie instytucji. Obsługiwane identyfikatory to GRID, Ringgold, kod LEI oraz identyfikatory z rejestru instytucji finansujących Crossref.", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Należy uzupełnić wartość w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Należy uzupełnić źródło w identyfikatorze instytucji", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Źródło jednego z identyfikatorów organizcji jest niepoprawne. Wspierane źródła to RINGGOLD, GRID, LEI and FUNDREF", + "person.page.orcid.synchronization-mode": "Tryb synchronizacji", + "person.page.orcid.synchronization-mode.batch": "Wsad", + "person.page.orcid.synchronization-mode.label": "Tryb synchronizacji", + "person.page.orcid.synchronization-mode-message": "Włącz tryb 'Manual' synchronizacja, aby wyłaczyć tryb synchronizacji wsadowej, wtedy dane do rejestru ORCID będą musiały zostać wysłane ręcznie", + "person.page.orcid.synchronization-settings-update.success": "Opcje synchronizacji zostały zaktualizowane", + "person.page.orcid.synchronization-settings-update.error": "Opcje synchronizacji nie zostały zaktualizowane", + "person.page.orcid.synchronization-mode.manual": "Ręczna", + "person.page.orcid.scope.authenticate": "Uzyskaj swój ORCID iD", + "person.page.orcid.scope.read-limited": "Przeczytaj informacje o ustawieniach widoczności z firmami trzeciami", + "person.page.orcid.scope.activities-update": "Dodaj/aktualizuj swoje aktywności naukowe", + "person.page.orcid.scope.person-update": "Dodaj/aktualizuj inne informacje o Tobie", + "person.page.orcid.unlink.success": "Odłączenie Twojego profilu od rejestru ORCID powiodło się", + "person.page.orcid.unlink.error": "Wystąpił błąd podczas odłączania Twojego profilu od rejestru ORCID. Spróbuj ponownie", + "person.page.staffid": "ID pracownika", + "person.page.titleprefix": "Osoba: ", + "person.search.results.head": "Wyniki wyszukiwania użytkowników", + "person.search.title": "Wyniki wyszukiwania użytkowników", + "process.new.select-parameters": "Parametry", + "process.new.cancel": "Anuluj", + "process.new.submit": "Zapisz", + "process.new.select-script": "Skrypt", + "process.new.select-script.placeholder": "Wybierz skrypt...", + "process.new.select-script.required": "Skrypt jest wymagany", + "process.new.parameter.file.upload-button": "Wybierz plik...", + "process.new.parameter.file.required": "Proszę wybrać plik", + "process.new.parameter.string.required": "Wartość parametru jest wymagana", + "process.new.parameter.type.value": "wartość", + "process.new.parameter.type.file": "plik", + "process.new.parameter.required.missing": "Te parametry są wymagane, ale nie zostały uzupełnione:", + "process.new.notification.success.title": "Udało się", + "process.new.notification.success.content": "Udało się stworzyć proces", + "process.new.notification.error.title": "Błąd", + "process.new.notification.error.content": "Wystąpił błąd podczas tworzenia procesu", + "process.new.header": "Utwórz nowy proces", + "process.new.title": "Utwórz nowy proces", + "process.new.breadcrumbs": "Utwórz nowy proces", + "process.detail.arguments": "Argumenty", + "process.detail.arguments.empty": "Do tego procesu nie zostały przypisane żadne argumenty", + "process.detail.back": "Cofnij", + "process.detail.output": "Dane wyjściowe procesu", + "process.detail.logs.button": "Odzyskaj dane wyjściowe procesu", + "process.detail.logs.loading": "Odzyskiwanie", + "process.detail.logs.none": "Ten proces nie ma danych wyjściowych", + "process.detail.output-files": "Pliki", + "process.detail.output-files.empty": "Ten proces nie ma żadnych plików danych wyjściowych", + "process.detail.script": "Skrypt", + "process.detail.title": "Proces: {{ id }} - {{ name }}", + "process.detail.start-time": "Czas rozpoczęcia procesu", + "process.detail.end-time": "Czas zakończenia procesu", + "process.detail.status": "Status", + "process.detail.create": "Stwórz podobny proces", + "process.overview.table.finish": "Czas zakończenia (UTC)", + "process.overview.table.id": "Identyfikator procesu", + "process.overview.table.name": "Nazwa", + "process.overview.table.start": "Czas rozpoczęcia (UTC)", + "process.overview.table.status": "Status", + "process.overview.table.user": "Użytkownik", + "process.overview.title": "Przegląd procesów", + "process.overview.breadcrumbs": "Przegląd procesów", + "process.overview.new": "Nowy", + "profile.breadcrumbs": "Zaktualizuj profil", + "profile.card.identify": "Dane", + "profile.card.security": "Bezpieczeństwo", + "profile.form.submit": "Zaktualizuj profil", + "profile.groups.head": "Posiadane uprawnienia do kolekcji", + "profile.head": "Zaktualizuj profil", + "profile.metadata.form.error.firstname.required": "Imię jest wymagane", + "profile.metadata.form.error.lastname.required": "Nazwisko jest wymagane", + "profile.metadata.form.label.email": "Adres e-mail", + "profile.metadata.form.label.firstname": "Imię", + "profile.metadata.form.label.language": "Język", + "profile.metadata.form.label.lastname": "Nazwisko", + "profile.metadata.form.label.phone": "Telefon kontaktowy", + "profile.metadata.form.notifications.success.content": "Zmiany w profilu zostały zapisane.", + "profile.metadata.form.notifications.success.title": "Profil zapisany", + "profile.notifications.warning.no-changes.content": "Nie dokonano żadnych zmian w profilu.", + "profile.notifications.warning.no-changes.title": "Brak zmian", + "profile.security.form.error.matching-passwords": "Hasła nie są identyczne.", + "profile.security.form.info": "Możesz wprowadzić nowe hasło w polu poniżej i zatwierdzić poprzez ponowne wpisanie. Hasło musi mieć przynajmniej 6 znaków.", + "profile.security.form.label.password": "Hasło", + "profile.security.form.label.passwordrepeat": "Potwierdź hasło", + "profile.security.form.notifications.success.content": "Twoje zmiany w haśle zostały zapisane.", + "profile.security.form.notifications.success.title": "Hasło zapisane", + "profile.security.form.notifications.error.title": "Błąd podczas próby zmiany hasła", + "profile.security.form.notifications.error.not-same": "Hasła nie są identyczne.", + "profile.title": "Zaktualizuj profil", + "profile.card.researcher": "Profil naukowca", + "project.listelement.badge": "Projekt badawczy", + "project.page.contributor": "Autorzy", + "project.page.description": "Opis", + "project.page.edit": "Edytuj pozycję", + "project.page.expectedcompletion": "Spodziewany termin zakończenia", + "project.page.funder": "Instytucje finansujące", + "project.page.id": "ID", + "project.page.keyword": "Słowa kluczowe", + "project.page.status": "Status", + "project.page.titleprefix": "Projekt badawczy: ", + "project.search.results.head": "Wyniki wyszukiwania projektów", + "publication.listelement.badge": "Publikacja", + "publication.page.description": "Opis", + "publication.page.edit": "Edytuj pozycję", + "publication.page.journal-issn": "ISSN czasopisma", + "publication.page.journal-title": "Tytuł czasopisma", + "publication.page.publisher": "Wydawca", + "publication.page.titleprefix": "Publikacja: ", + "publication.page.volume-title": "Tytuł tomu", + "publication.search.results.head": "Wyniki wyszukiwania publikacji", + "publication.search.title": "Wyszukiwanie publikacji", + "media-viewer.next": "Nowy", + "media-viewer.previous": "Poprzedni", + "media-viewer.playlist": "Playlista", + "register-email.title": "Rejestracja nowego użytkownika", + "register-page.create-profile.header": "Stwórz profil", + "register-page.create-profile.identification.header": "Dane", + "register-page.create-profile.identification.email": "Adres e-mail", + "register-page.create-profile.identification.first-name": "Imię *", + "register-page.create-profile.identification.first-name.error": "Wpisz imię", + "register-page.create-profile.identification.last-name": "Nazwisko *", + "register-page.create-profile.identification.last-name.error": "Wpisz nazwisko", + "register-page.create-profile.identification.contact": "Telefon kontaktowy", + "register-page.create-profile.identification.language": "Język", + "register-page.create-profile.security.header": "Bezpieczeństwo", + "register-page.create-profile.security.info": "Wprowadź nowe hasło w polu poniżej i zatwierdź poprzez ponowne wpisanie w drugim polu. Hasło musi mieć przynajmniej 6 znaków.", + "register-page.create-profile.security.label.password": "Hasło *", + "register-page.create-profile.security.label.passwordrepeat": "Potwierdź hasło *", + "register-page.create-profile.security.error.empty-password": "Wprowadź hasło w polu poniżej.", + "register-page.create-profile.security.error.matching-passwords": "Hasła nie są identyczne.", + "register-page.create-profile.submit": "Rejestracja zakończona", + "register-page.create-profile.submit.error.content": "Coś się nie udało podczas rejestracji nowego użytkownika.", + "register-page.create-profile.submit.error.head": "Rejestracja nie powiodła się", + "register-page.create-profile.submit.success.content": "Rejestracja powiodła się. Zalogowano jako stworzony użytkownik.", + "register-page.create-profile.submit.success.head": "Rejestracja zakończona", + "register-page.registration.header": "Rejestracja nowego użytkownika", + "register-page.registration.info": "Zarejestruj się, aby otrzymywać wiadomości o nowych pozycjach w obserowanych kolekcjach, a także przesyłać nowe pozycje do repozytorium.", + "register-page.registration.email": "Adres e-mail *", + "register-page.registration.email.error.required": "Wypełnij adres e-mail", + "register-page.registration.email.error.pattern": "Wypełnij poprawny adres e-mail", + "register-page.registration.email.hint": "Ten adres e-mail będzie zweryfikowany i będziesz go używać jako swój login.", + "register-page.registration.submit": "Zarejestruj się", + "register-page.registration.success.head": "Wiadomość weryfikacyjna zostałą wysłana", + "register-page.registration.success.content": "Wiadomość została wysłana na adres e-mail {{ email }}. Zawiera ona unikatowy link i dalsze instrukcje postępowania.", + "register-page.registration.error.head": "Błąd podczas próby rejestracji adresu e-mail", + "register-page.registration.error.content": "Błąd podczas próby rejestracji adresu e-mail: {{ email }}", + "relationships.add.error.relationship-type.content": "Nie znaleziono dopasowania dla typu relacji {{ type }} pomiędzy dwoma pozycjami", + "relationships.add.error.server.content": "Błąd serwera", + "relationships.add.error.title": "Nie można dodać relacji", + "relationships.isAuthorOf": "Autorzy", + "relationships.isAuthorOf.Person": "Autorzy (osoby)", + "relationships.isAuthorOf.OrgUnit": "Autorzy (jednostki organizacyjne)", + "relationships.isIssueOf": "Numery czasopisma", + "relationships.isJournalIssueOf": "Numer czasopisma", + "relationships.isJournalOf": "Czasopisma", + "relationships.isOrgUnitOf": "Jednostki organizacyjne", + "relationships.isPersonOf": "Autorzy", + "relationships.isProjectOf": "Projekty badawcze", + "relationships.isPublicationOf": "Publikacje", + "relationships.isPublicationOfJournalIssue": "Artykuły", + "relationships.isSingleJournalOf": "Czasopismo", + "relationships.isSingleVolumeOf": "Tom czasopisma", + "relationships.isVolumeOf": "Tomy czasopisma", + "relationships.isContributorOf": "Autorzy", + "relationships.isContributorOf.OrgUnit": "Autor (Jednostka organizacyjna)", + "relationships.isContributorOf.Person": "Autor", + "relationships.isFundingAgencyOf.OrgUnit": "Instytucja finansująca", + "repository.image.logo": "Logo repozytorium", + "repository.title.prefix": "DSpace Angular :: ", + "researcher.profile.action.processing": "Procesowanie...", + "researcher.profile.associated": "Przypisanie profilu badacza", + "researcher.profile.create.new": "Utwórz nowy", + "researcher.profile.create.success": "Profil badacza został utworzony", + "researcher.profile.create.fail": "Wystąpił błąd poczas tworzenia profilu badacza.", + "researcher.profile.delete": "Usuń", + "researcher.profile.expose": "Ujawnij", + "researcher.profile.hide": "Ukryj", + "researcher.profile.not.associated": "Profil badacza nie został jeszcze przypisany", + "researcher.profile.view": "Widok", + "researcher.profile.private.visibility": "PRYWATNY", + "researcher.profile.public.visibility": "PUBLICZNY", + "researcher.profile.status": "Status:", + "researcherprofile.claim.not-authorized": "Nie masz uprawnień, aby wystąpić o tę pozycję. Aby otrzymać więcej szczegółów, skontaktuj się z administratorami.", + "researcherprofile.error.claim.body": "Wystąpił błąd podczas wystąpienia z prośbą o przypisanie profilu. Spróbuj ponownie później.", + "researcherprofile.error.claim.title": "Błąd", + "researcherprofile.success.claim.body": "Wystąpienie z prośbą o przypisanie profilu udane", + "researcherprofile.success.claim.title": "Sukces", + "repository.title.prefixDSpace": "DSpace Angular ::", + "resource-policies.add.button": "Dodaj", + "resource-policies.add.for.": "Dodaj nową politykę", + "resource-policies.add.for.bitstream": "Dodaj nową politykę dla plików", + "resource-policies.add.for.bundle": "Dodaj nową politykę paczek", + "resource-policies.add.for.item": "Dodaj nową politykę pozycji", + "resource-policies.add.for.community": "Dodaj nową politykę zbioru", + "resource-policies.add.for.collection": "Dodaj nową politykę kolekcji", + "resource-policies.create.page.heading": "Utwórz nową politykę zasobu dla ", + "resource-policies.create.page.failure.content": "Wystąpił błąd podczas dodawania polityki zasobów.", + "resource-policies.create.page.success.content": "Działanie powiodło się", + "resource-policies.create.page.title": "Utwórz nową politykę zasobu", + "resource-policies.delete.btn": "Usuń zaznaczone", + "resource-policies.delete.btn.title": "Usuń zaznaczone polityki zasobów", + "resource-policies.delete.failure.content": "Wystąpił błąd podczas usuwania wybranych polityk zasobów.", + "resource-policies.delete.success.content": "Działanie powiodło się", + "resource-policies.edit.page.heading": "Edytuj politykę zasobu ", + "resource-policies.edit.page.failure.content": "Wystąpił błąd poczas edytowania polityki zasobu.", + "resource-policies.edit.page.success.content": "Działanie udało się", + "resource-policies.edit.page.title": "Edytuj politykę zasobu", + "resource-policies.form.action-type.label": "Wybierz ten typ akcji", + "resource-policies.form.action-type.required": "Musisz wybrać akcję polityki zasobu.", + "resource-policies.form.eperson-group-list.label": "Użytkownik lub grupa, która otrzyma uprawnienia.", + "resource-policies.form.eperson-group-list.select.btn": "Wybierz", + "resource-policies.form.eperson-group-list.tab.eperson": "Wyszukaj użytkownika", + "resource-policies.form.eperson-group-list.tab.group": "Wyszukaj grupę", + "resource-policies.form.eperson-group-list.table.headers.action": "Akcja", + "resource-policies.form.eperson-group-list.table.headers.id": "ID", + "resource-policies.form.eperson-group-list.table.headers.name": "Nazwa", + "resource-policies.form.date.end.label": "Data zakończenia", + "resource-policies.form.date.start.label": "Data rozpoczęcia", + "resource-policies.form.description.label": "Opis", + "resource-policies.form.name.label": "Nazwa", + "resource-policies.form.policy-type.label": "Wybierz typ polityki", + "resource-policies.form.policy-type.required": "Musisz wybrać typ polityki zasobu.", + "resource-policies.table.headers.action": "Akcja", + "resource-policies.table.headers.date.end": "Data zakończenia", + "resource-policies.table.headers.date.start": "Data rozpoczęcia", + "resource-policies.table.headers.edit": "Edytuj", + "resource-policies.table.headers.edit.group": "Edytuj grupę", + "resource-policies.table.headers.edit.policy": "Edytuj politykę", + "resource-policies.table.headers.eperson": "Użytkownik", + "resource-policies.table.headers.group": "Grupa", + "resource-policies.table.headers.id": "ID", + "resource-policies.table.headers.name": "Nazwa", + "resource-policies.table.headers.policyType": "typ", + "resource-policies.table.headers.title.for.bitstream": "Polityki dla plików", + "resource-policies.table.headers.title.for.bundle": "Polityki dla paczek", + "resource-policies.table.headers.title.for.item": "Polityki dla pozycji", + "resource-policies.table.headers.title.for.community": "Polityki dla zbioru", + "resource-policies.table.headers.title.for.collection": "Polityki dla kolekcji", + "search.description": "", + "search.switch-configuration.title": "Pokaż", + "search.title": "Szukaj", + "search.breadcrumbs": "Szukaj", + "search.search-form.placeholder": "Szukaj w repozytorium...", + "search.filters.applied.f.author": "Autor", + "search.filters.applied.f.dateIssued.max": "Data zakończenia", + "search.filters.applied.f.dateIssued.min": "Data rozpoczęcia", + "search.filters.applied.f.dateSubmitted": "Data zgłoszenia", + "search.filters.applied.f.discoverable": "Ukryty", + "search.filters.applied.f.entityType": "Typ pozycji", + "search.filters.applied.f.has_content_in_original_bundle": "Ma przypisane pliki", + "search.filters.applied.f.itemtype": "Typ", + "search.filters.applied.f.namedresourcetype": "Status", + "search.filters.applied.f.subject": "Temat", + "search.filters.applied.f.submitter": "Zgłaszający", + "search.filters.applied.f.jobTitle": "Stanowisko", + "search.filters.applied.f.birthDate.max": "Data zakończenia tworzenia", + "search.filters.applied.f.birthDate.min": "Data rozpoczęcia tworzenia", + "search.filters.applied.f.withdrawn": "Wycofane", + "search.filters.filter.author.head": "Autor", + "search.filters.filter.author.placeholder": "Autor", + "search.filters.filter.author.label": "Wyszukaj autora", + "search.filters.filter.birthDate.head": "Data urodzenia", + "search.filters.filter.birthDate.placeholder": "Data urodzenia", + "search.filters.filter.birthDate.label": "Wyszukaj datę urodzenia", + "search.filters.filter.collapse": "Ukryj filtr", + "search.filters.filter.creativeDatePublished.head": "Data opublikowania", + "search.filters.filter.creativeDatePublished.placeholder": "Data opublikowania", + "search.filters.filter.creativeDatePublished.label": "Wyszukaj datę opublikowania", + "search.filters.filter.creativeWorkEditor.head": "Redaktor", + "search.filters.filter.creativeWorkEditor.placeholder": "Redaktor", + "search.filters.filter.creativeWorkEditor.label": "Wyszukaj redaktora", + "search.filters.filter.creativeWorkKeywords.head": "Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.placeholder": "Słowo kluczowe", + "search.filters.filter.creativeWorkKeywords.label": "Wyszukaj temat", + "search.filters.filter.creativeWorkPublisher.head": "Wydawca", + "search.filters.filter.creativeWorkPublisher.placeholder": "Wydawca", + "search.filters.filter.creativeWorkPublisher.label": "Wyszukaj wydawcę", + "search.filters.filter.dateIssued.head": "Data", + "search.filters.filter.dateIssued.max.placeholder": "Data maksymalna", + "search.filters.filter.dateIssued.max.label": "Koniec", + "search.filters.filter.dateIssued.min.placeholder": "Data minimalna", + "search.filters.filter.dateIssued.min.label": "Start", + "search.filters.filter.dateSubmitted.head": "Data zgłoszenia", + "search.filters.filter.dateSubmitted.placeholder": "Data zgłoszenia", + "search.filters.filter.dateSubmitted.label": "Wyszukaj datę zgłoszenia", + "search.filters.filter.discoverable.head": "Ukryty", + "search.filters.filter.withdrawn.head": "Wycofane", + "search.filters.filter.entityType.head": "Typ pozycji", + "search.filters.filter.entityType.placeholder": "Typ pozycji", + "search.filters.filter.entityType.label": "Wyszukaj typ pozycji", + "search.filters.filter.expand": "Rozwiń filtr", + "search.filters.filter.has_content_in_original_bundle.head": "Ma przypisane pliki", + "search.filters.filter.itemtype.head": "Typ", + "search.filters.filter.itemtype.placeholder": "Typ", + "search.filters.filter.itemtype.label": "Wyszukaj typ", + "search.filters.filter.jobTitle.head": "Stanowisko", + "search.filters.filter.jobTitle.placeholder": "Stanowisko", + "search.filters.filter.jobTitle.label": "Wyszukaj stanowisko", + "search.filters.filter.knowsLanguage.head": "Znajomość języka", + "search.filters.filter.knowsLanguage.placeholder": "Znajomość języka", + "search.filters.filter.knowsLanguage.label": "Wyszukaj wg znajomości języka", + "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.namedresourcetype.label": "Wyszukaj status", + "search.filters.filter.objectpeople.head": "Osoby", + "search.filters.filter.objectpeople.placeholder": "Osoby", + "search.filters.filter.objectpeople.label": "Wyszukaj użytkowników", + "search.filters.filter.organizationAddressCountry.head": "Kraj", + "search.filters.filter.organizationAddressCountry.placeholder": "Kraj", + "search.filters.filter.organizationAddressCountry.label": "Wyszukaj kraj", + "search.filters.filter.organizationAddressLocality.head": "Miasto", + "search.filters.filter.organizationAddressLocality.placeholder": "Miasto", + "search.filters.filter.organizationAddressLocality.label": "Wyszukaj miasto", + "search.filters.filter.organizationFoundingDate.head": "Data założenia", + "search.filters.filter.organizationFoundingDate.placeholder": "Data założenia", + "search.filters.filter.organizationFoundingDate.label": "Wyszukaj datę założenia", + "search.filters.filter.scope.head": "Zakres", + "search.filters.filter.scope.placeholder": "Filtr zakresu", + "search.filters.filter.scope.label": "Wyszukaj filtr zakresu", + "search.filters.filter.show-less": "Pokaż mniej", + "search.filters.filter.show-more": "Pokaż więcej", + "search.filters.filter.subject.head": "Temat", + "search.filters.filter.subject.placeholder": "Temat", + "search.filters.filter.subject.label": "Wyszukaj temat", + "search.filters.filter.submitter.head": "Zgłaszający", + "search.filters.filter.submitter.placeholder": "Zgłaszający", + "search.filters.filter.submitter.label": "Wyszukaj zgłaszającego", + "search.filters.entityType.JournalIssue": "Numer czasopisma", + "search.filters.entityType.JournalVolume": "Tom czasopisma", + "search.filters.entityType.OrgUnit": "Jednostka organizacyjna", + "search.filters.has_content_in_original_bundle.true": "Tak", + "search.filters.has_content_in_original_bundle.false": "Nie", + "search.filters.discoverable.true": "Nie", + "search.filters.discoverable.false": "Tak", + "search.filters.withdrawn.true": "Tak", + "search.filters.withdrawn.false": "Nie", + "search.filters.head": "Filtry", + "search.filters.reset": "Resetuj filtry", + "search.filters.search.submit": "Zastosuj", + "search.form.search": "Wyszukaj", + "search.form.search_dspace": "W repozytorium", + "search.form.scope.all": "W całym DSpace", + "search.results.head": "Wyniki wyszukiwania", + "default.search.results.head": "Wyniki wyszukiwania", + "search.results.no-results": "Twoj wyszukiwanie nie zwróciło żadnych rezultatów. Masz problem ze znalezieniem tego czego szukasz? Spróbuj użyć", + "search.results.no-results-link": "fraz podobnych do Twojego wyszukiwania", + "search.results.empty": "Twoje wyszukiwanie nie zwróciło żadnych rezultatów.", + "search.sidebar.close": "Wróć do wyników wyszukiwania", + "search.sidebar.filters.title": "Filtry", + "search.sidebar.open": "Narzędzia wyszukiwania", + "search.sidebar.results": "wyniki", + "search.sidebar.settings.rpp": "Wyników na stronie", + "search.sidebar.settings.sort-by": "Sortuj według", + "search.sidebar.settings.title": "Ustawienia", + "search.view-switch.show-detail": "Wyświetl widok szczegółowy", + "search.view-switch.show-grid": "Wyświetl jako siatkę", + "search.view-switch.show-list": "Wyświetl jako listę", + "sorting.ASC": "Rosnąco", + "sorting.DESC": "Malejąco", + "sorting.dc.title.ASC": "Tytułami rosnąco", + "sorting.dc.title.DESC": "Tytułami malejąco", + "sorting.score.ASC": "Najmniej trafne", + "sorting.score.DESC": "Najbardziej trafne", + "sorting.dc.date.issued.ASC": "Data wydania rosnąco", + "sorting.dc.date.issued.DESC": "Data wydania malejąco", + "sorting.dc.date.accessioned.ASC": "Data dostępu rosnąco", + "sorting.dc.date.accessioned.DESC": "Data dostępu malejąco", + "sorting.lastModified.ASC": "Ostatnia modyfikacja rosnąco", + "sorting.lastModified.DESC": "Ostatnia modyfikacja malejąco", + "statistics.title": "Statystyki", + "statistics.header": "Statystyki dla {{ scope }}", + "statistics.breadcrumbs": "Statystyki", + "statistics.page.no-data": "Brak dostępnych danych", + "statistics.table.no-data": "Brak dostępnych danych", + "statistics.table.header.views": "Wyświetlenia", + "submission.edit.breadcrumbs": "Edytuj zgłoszenie", + "submission.edit.title": "Edytuj zgłoszenie", + "submission.general.cancel": "Anuluj", + "submission.general.cannot_submit": "Nie masz uprawnień, aby utworzyć nowe zgłoszenie.", + "submission.general.deposit": "Deponuj", + "submission.general.discard.confirm.cancel": "Anuluj", + "submission.general.discard.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.general.discard.confirm.submit": "Tak, na pewno", + "submission.general.discard.confirm.title": "Odrzuć zgłoszenie", + "submission.general.discard.submit": "Odrzuć", + "submission.general.info.saved": "Zapisane", + "submission.general.info.pending-changes": "Niezapisane zmiany", + "submission.general.save": "Zapisz", + "submission.general.save-later": "Zapisz wersję roboczą", + "submission.import-external.page.title": "Importuj metdane z zewnętrznego źródła", + "submission.import-external.title": "Importuj metadane z zewnętrznego źródła", + "submission.import-external.title.Journal": "Importuj czasopismo z zewnętrznego źródła", + "submission.import-external.title.JournalIssue": "Importuj numer czasopisma z zewnętrznego źródła", + "submission.import-external.title.JournalVolume": "Importuj tom czasopisma z zewnętrznego źródła", + "submission.import-external.title.OrgUnit": "Importuj wydawcę z zewnętrznego źródła", + "submission.import-external.title.Person": "Importuj osobę z zewnętrznego źródła", + "submission.import-external.title.Project": "Importuj projekt z zewnętrznego źródła", + "submission.import-external.title.Publication": "Importuj publikację z zewnętrznego źródła", + "submission.import-external.title.none": "Importuj metadane z zewnętrznego źródła", + "submission.import-external.page.hint": "Enter a query above to find items from the web to import in to DSpace.", + "submission.import-external.back-to-my-dspace": "Powrót do MyDSpace", + "submission.import-external.search.placeholder": "Wyszukaj zewnętrzne źródła danych", + "submission.import-external.search.button": "Szukaj", + "submission.import-external.search.button.hint": "Zacznij wpisywać frazę, aby wyszukać", + "submission.import-external.search.source.hint": "Wybierz zewnętrzne źródło", + "submission.import-external.source.ads": "NASA/ADS", + "submission.import-external.source.arxiv": "arXiv", + "submission.import-external.source.cinii": "CiNii", + "submission.import-external.source.crossref": "CrossRef", + "submission.import-external.source.loading": "ładowanie...", + "submission.import-external.source.sherpaJournal": "Czasopisma w SHERPA", + "submission.import-external.source.sherpaJournalIssn": "Czasopisma w SHERPA wg ISSN", + "submission.import-external.source.sherpaPublisher": "Wydawcy w SHERPA", + "submission.import-external.source.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.import-external.source.orcid": "ORCID", + "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.pubmed": "Pubmed", + "submission.import-external.source.pubmedeu": "Pubmed Europe", + "submission.import-external.source.lcname": "Nazwy Biblioteki Kongresu", + "submission.import-external.source.scielo": "SciELO", + "submission.import-external.source.scopus": "Scopus", + "submission.import-external.source.vufind": "VuFind", + "submission.import-external.source.wos": "Web Of Science", + "submission.import-external.source.epo": "Europejski Urząd Patentowy (EPO)", + "submission.import-external.preview.title.Journal": "Podgląd czasopisma", + "submission.import-external.preview.title.OrgUnit": "Podgląd organizacji", + "submission.import-external.preview.title.Person": "Podgląd osoby", + "submission.import-external.preview.title.Project": "Podgląd projektu", + "submission.import-external.preview.title.Publication": "Podgląd publikacji", + "submission.import-external.preview.subtitle": "Metadane poniżej zostały zaimportowane z zewnętrznego źródła. Niektóre pola zostaną uzupełnione automatycznie, kiedy rozpoczniesz zgłaszanie pozycji.", + "submission.import-external.preview.button.import": "Rozpocznij zgłoszenie", + "submission.import-external.preview.error.import.title": "Błąd zgłoszenia", + "submission.import-external.preview.error.import.body": "Wystąpił błąd podczas procesu importowania pozycji z zewnętrznego źródła.", + "submission.sections.describe.relationship-lookup.close": "Zamknij", + "submission.sections.describe.relationship-lookup.external-source.added": "Udało się dodać wpis do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importuj zdalny tom czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Nowy typ danych dodany!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Projekt", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Importuj zdalnego autora", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Importuj zdalną osobę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Importuj zdalny produkt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Importuj zdalną aparaturę badawczą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Importuj zdalne wydarzenie", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Importuj zdalną instytucję finansującą", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Importuj zdalnego wydawcę", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Importuj zdalnie patent", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Importuj zdalnie projekt", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Importuj zdalnie publikację", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Udało się dodać autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Udało się zaimportować i dodać zewnętrznego autora do selekcji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Nadrzędność", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Importuj jako nową, lokalną, nadrzędną pozycję", + "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Anuluj", + "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Wybierz kolekcję do zaimportowania nowych pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Importuj jako nowy lokalny typ danych", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Importuj z LC Name", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Importuj z ORCID", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Importuj z Sherpa Journal", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Importuj z Sherpa Publisher", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Importuj z PubMed", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Importuj z arXiv", + "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Import", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Importuj zdalne czasopismo", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Successfully added local journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Successfully imported and added external journal to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Udało się dodać lokalne czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Udało się zaimportować i dodać czasopismo zewnętrzne do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Importuj zdalny numer czasopisma", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Udało się dodać lokalny numer czasopismo do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Udało się zaimportować i dodać zewnętrzny numer czasopisma do zaznaczenia", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Wybierz lokalne powiązanie:", + "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Odznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Odznacz stronę", + "submission.sections.describe.relationship-lookup.search-tab.loading": "Ładowanie...", + "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Wyszukaj zapytanie", + "submission.sections.describe.relationship-lookup.search-tab.search": "Zastosuj", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Wyszukaj...", + "submission.sections.describe.relationship-lookup.search-tab.select-all": "Zaznacz wszystko", + "submission.sections.describe.relationship-lookup.search-tab.select-page": "Zaznacz stronę", + "submission.sections.describe.relationship-lookup.selected": "Zaznacz {{ size }} pozycji", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Czasopisma lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Projekty lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Publikacje lokalne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Autorzy lokalni ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Lokalne jednostki organizacyjne ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Lokalne paczki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Lokalne pliki danych ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Lokalne czasopisma ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Lokalne numery czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Lokalne tomy czasopism ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "Sherpa Journals ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "Sherpa Publishers ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC Names ({{ 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": "Wyszukaj instytucje finansujące", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Wyszukaj finansowanie", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Wyszukaj jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Projekty", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Finansowanie OpenAIRE API", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Projekt", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Projekty", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Instytucja finansująca projekt", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Wyszukaj...", + "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Aktualne zaznaczenie ({{ count }})", + "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalIssue": "Numery czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.JournalVolume": "Tomy czasopisma", + "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Czasopisma", + "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Autorzy", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.Project": "Projekty", + "submission.sections.describe.relationship-lookup.title.Publication": "Publikacje", + "submission.sections.describe.relationship-lookup.title.Person": "Autorzy", + "submission.sections.describe.relationship-lookup.title.OrgUnit": "Jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.title.DataPackage": "Paczki danych", + "submission.sections.describe.relationship-lookup.title.DataFile": "Pliki danych", + "submission.sections.describe.relationship-lookup.title.Funding Agency": "Instytucja finansująca", + "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Finansowanie", + "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Nadrzędna jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Przełącz na listę rozwijaną", + "submission.sections.describe.relationship-lookup.selection-tab.settings": "Ustawienia", + "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Twoje zaznaczenie jest puste.", + "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Wybrane tomy czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Wybrane projekty", + "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Wybrane publikacje", + "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Wybrani autorzy", + "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Wybrane jednostki organizacyjne", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Wybrane pakiety danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Wybrane pliki danych", + "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Wybrane czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Wybrany tom czasopisma", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Wybrane instytucje finansujące", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Wybrane finansowanie", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Wybrany numer wydania", + "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Wybrana jednostka organizacyjna", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.selection-tab.title": "Wyniki wyszukiwania", + "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Czy chcesz zapisać \"{{ value }}\" jako wariant imienia dla tego użytkownika, aby Ty lub inni użytkownicy mogli używać tego wariantu w przyszłych zgłoszeniach?. Jeśli nie, nadal możesz użyć tego wariantu w tym zgłoszeniu.", + "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Zapisz nowy wariant imienia", + "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Użyj tylko w tym zgłoszeniu", + "submission.sections.ccLicense.type": "Typ licencji", + "submission.sections.ccLicense.select": "Wybierz typ licencji…", + "submission.sections.ccLicense.change": "Zmień typ licencji…", + "submission.sections.ccLicense.none": "Brak dostępnych licencji", + "submission.sections.ccLicense.option.select": "Wybierz opcję…", + "submission.sections.ccLicense.link": "Wybrano licencję:", + "submission.sections.ccLicense.confirmation": "Udzielam powyższej licencji", + "submission.sections.general.add-more": "Dodaj więcej", + "submission.sections.general.collection": "Kolekcja", + "submission.sections.general.deposit_error_notice": "Wystąpił błąd podczas zgłaszania pozycji. Spróbuj ponownie później.", + "submission.sections.general.deposit_success_notice": "Udało się wprowadzić pozycję.", + "submission.sections.general.discard_error_notice": "Wystąpił błąd podczas odrzucania pozycji. Spróbuj ponownie później.", + "submission.sections.general.discard_success_notice": "Udało się odrzucić pozycję.", + "submission.sections.general.metadata-extracted": "Nowe metadane zostany rozpakowane i dodane do sekcji <strong>{{sectionId}}</strong>.", + "submission.sections.general.metadata-extracted-new-section": "Nowa sekcja <strong>{{sectionId}}</strong> została dodana do zgłoszenia.", + "submission.sections.general.no-collection": "Nie znaleziono kolekcji", + "submission.sections.general.no-sections": "Opcje niedostępne", + "submission.sections.general.save_error_notice": "Wystąpił błąd podczas zapisywania numeru. Spróbuj ponownie później. Po odświeżeniu strony niezapisane zmiany mogą zostać utracone.", + "submission.sections.general.save_success_notice": "Udało się zapisać zgłoszenie.", + "submission.sections.general.search-collection": "Szukaj kolekcji", + "submission.sections.general.sections_not_valid": "Niektóre sekcje są niekompletne.", + "submission.sections.submit.progressbar.CClicense": "Licencja Creative Commons", + "submission.sections.submit.progressbar.describe.recycle": "Odzyskaj", + "submission.sections.submit.progressbar.describe.stepcustom": "Opisz", + "submission.sections.submit.progressbar.describe.stepone": "Opisz", + "submission.sections.submit.progressbar.describe.steptwo": "Opisz", + "submission.sections.submit.progressbar.detect-duplicate": "Potencjalne duplikaty", + "submission.sections.submit.progressbar.license": "Zdeponuj licencję", + "submission.sections.submit.progressbar.upload": "Prześlij pliki", + "submission.sections.status.errors.title": "Błędy", + "submission.sections.status.valid.title": "Poprawność", + "submission.sections.status.warnings.title": "Ostrzeżenia", + "submission.sections.status.errors.aria": "ma błędy", + "submission.sections.status.valid.aria": "jest poprawne", + "submission.sections.status.warnings.aria": "ma ostrzeżenia", + "submission.sections.toggle.open": "Otwórz sekcję", + "submission.sections.toggle.close": "Zamknij sekcję", + "submission.sections.toggle.aria.open": "Rozwiń sekcję {{sectionHeader}}", + "submission.sections.toggle.aria.close": "Zwiń sekcję {{sectionHeader}}", + "submission.sections.upload.delete.confirm.cancel": "Anuluj", + "submission.sections.upload.delete.confirm.info": "Czy na pewno? To działanie nie może zostać cofnięte.", + "submission.sections.upload.delete.confirm.submit": "Tak, na pewno", + "submission.sections.upload.delete.confirm.title": "Usuń plik", + "submission.sections.upload.delete.submit": "Usuń", + "submission.sections.upload.download.title": "Pobierz plik", + "submission.sections.upload.drop-message": "Upuść pliki, aby załączyć je do tej pozycji", + "submission.sections.upload.edit.title": "Edytuj plik", + "submission.sections.upload.form.access-condition-label": "Typ dostępu", + "submission.sections.upload.form.date-required": "Data jest wymagana.", + "submission.sections.upload.form.date-required-from": "Data przyznania dostępu od jest wymagana.", + "submission.sections.upload.form.date-required-until": "Data przyznania dostępu do jest wymagana.", + "submission.sections.upload.form.from-label": "Pozwól na dostęp od", + "submission.sections.upload.form.from-placeholder": "Od", + "submission.sections.upload.form.group-label": "Grupa", + "submission.sections.upload.form.group-required": "Grupa jest wymagana", + "submission.sections.upload.form.until-label": "Pozwól na dostęp do", + "submission.sections.upload.form.until-placeholder": "Do", + "submission.sections.upload.header.policy.default.nolist": "Pliki wgrane do kolekcji {{collectionName}} będą dostępne dla poniższych grup:", + "submission.sections.upload.header.policy.default.withlist": "Zwróć uwagę na to, że pliki w kolekcji {{collectionName}} będą dostępne dla poniższych grup, z wyjątkiem tych, które zostały wyłączone z dostępu:", + "submission.sections.upload.info": "Tutaj znajdują się wszystkie pliki dodane w tym momencie do pozycji. Możesz zaktualizować metadane pliku i warunki dostępu lub <strong>przesłać dodatkowe pliki, przeciągając i opuszczając je gdziekolwiek na tej stronie</strong>", + "submission.sections.upload.no-entry": "Nie", + "submission.sections.upload.no-file-uploaded": "Pliki nie zostały jeszcze wgrane.", + "submission.sections.upload.save-metadata": "Zapisz metadane", + "submission.sections.upload.undo": "Anuluj", + "submission.sections.upload.upload-failed": "Przesyłanie nieudane", + "submission.sections.upload.upload-successful": "Przesyłanie udane", + "submission.submit.breadcrumbs": "Nowe zgłoszenie", + "submission.submit.title": "Nowe zgłoszenie", + "submission.workflow.generic.delete": "Usuń", + "submission.workflow.generic.delete-help": "Jeśli chcesz odrzucić tę pozycję, wybierz \"Delete\". Będzie wymagane potwierdzenie tej decyzji.", + "submission.workflow.generic.edit": "Edytuj", + "submission.workflow.generic.edit-help": "Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.generic.view": "Podgląd", + "submission.workflow.generic.view-help": "Wybierz tę opcję, aby wyświetlić metadane pozycji.", + "submission.workflow.tasks.claimed.approve": "Zatwierdź", + "submission.workflow.tasks.claimed.approve_help": "Jeśli ta pozycja ma zostać zatwierdzona i wprowadzona do kolekcji, wybierz \"Approve\".", + "submission.workflow.tasks.claimed.edit": "Edytuj", + "submission.workflow.tasks.claimed.edit_help": "Wybierz tę opcję, aby zmienić metadane pozycji.", + "submission.workflow.tasks.claimed.reject.reason.info": "Proszę wpisać powód odrzucenia zgłoszenia w poniższe pole, wskazując, czy zgłaszający może poprawić problem i ponownie przesłać zgłoszenie.", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Opisz powód odrzucenia zgłoszenia", + "submission.workflow.tasks.claimed.reject.reason.submit": "Odrzuć pozycję", + "submission.workflow.tasks.claimed.reject.reason.title": "Powód", + "submission.workflow.tasks.claimed.reject.submit": "Odrzuć", + "submission.workflow.tasks.claimed.reject_help": "Jeśli po przejrzeniu pozycji stwierdzono, że nie nadaje się ona do włączenia do kolekcji, wybierz opcję \"Reject\". Zostaniesz wtedy poproszony o określenie powodu odrzucenia, i wskazanie czy zgłaszający powinien wprowadzić zmiany i przesłać ponownie pozycję.", + "submission.workflow.tasks.claimed.return": "Cofnij do puli zadań", + "submission.workflow.tasks.claimed.return_help": "Cofnij zadanie do puli, aby inny użytkownik mógł się go podjąć.", + "submission.workflow.tasks.generic.error": "Podczas działania wystąpił błąd...", + "submission.workflow.tasks.generic.processing": "Procesowanie...", + "submission.workflow.tasks.generic.submitter": "Zgłaszający", + "submission.workflow.tasks.generic.success": "Udało się", + "submission.workflow.tasks.pool.claim": "Podejmij pracę", + "submission.workflow.tasks.pool.claim_help": "Przypisz to zadanie do siebie.", + "submission.workflow.tasks.pool.hide-detail": "Ukryj szczegóły", + "submission.workflow.tasks.pool.show-detail": "Pokaż szczegóły", + "thumbnail.default.alt": "Miniatura", + "thumbnail.default.placeholder": "Brak miniatury", + "thumbnail.project.alt": "Logo projektu", + "thumbnail.project.placeholder": "Obraz zastępczy projketu", + "thumbnail.orgunit.alt": "Logo jednostki organizacyjnej", + "thumbnail.orgunit.placeholder": "Obraz zastępczy jednostki organizacyjnej", + "thumbnail.person.alt": "Zdjęcie profilowe", + "thumbnail.person.placeholder": "Brak zdjęcia profilowego", + "title": "DSpace", + "vocabulary-treeview.header": "Widok drzewka", + "vocabulary-treeview.load-more": "Pokaż więcej", + "vocabulary-treeview.search.form.reset": "Resetuj", + "vocabulary-treeview.search.form.search": "Szukaj", + "vocabulary-treeview.search.no-result": "Brak pozycji do wyświetlenia", + "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", + "vocabulary-treeview.tree.description.srsc": "Kategorie tematów badań", + "uploader.browse": "wyszukaj na swoim urządzeniu", + "uploader.drag-message": "Przeciągnij i upuść pliki tutaj", + "uploader.delete.btn-title": "Usuń", + "uploader.or": ", lub ", + "uploader.processing": "Procesowanie", + "uploader.queue-length": "Długość kolejki", + "virtual-metadata.delete-item.info": "Wybierz typy, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "virtual-metadata.delete-item.modal-head": "Wirtualne metadane tego powiązania", + "virtual-metadata.delete-relationship.modal-head": "Wybierz pozycje, dla których chcesz zapisać wirtualne metadane jako rzeczywiste metadane", + "workflowAdmin.search.results.head": "Zarządzaj procesami", + "workflow-item.edit.breadcrumbs": "Edytuj pozycję procesu", + "workflow-item.edit.title": "Edytuj pozycję procesu", + "workflow-item.delete.notification.success.title": "Usunięte", + "workflow-item.delete.notification.success.content": "Ten element procesu został usunięty", + "workflow-item.delete.notification.error.title": "Coś poszło nie tak", + "workflow-item.delete.notification.error.content": "Ten element procesu nie mógł zostać usunięty", + "workflow-item.delete.title": "Usuń element procesu", + "workflow-item.delete.header": "Usuń element procesu", + "workflow-item.delete.button.cancel": "Anuluj", + "workflow-item.delete.button.confirm": "Usuń", + "workflow-item.send-back.notification.success.title": "SOdeślij do zgłaszającego", + "workflow-item.send-back.notification.success.content": "Ten element procesu został odesłany do zgłaszającego", + "workflow-item.send-back.notification.error.title": "Coś poszło nie tak", + "workflow-item.send-back.notification.error.content": "Ten element procesu nie mógł zostać odesłany do zgłaszającego", + "workflow-item.send-back.title": "Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.header": "Odeślij element procesu do zgłaszającego", + "workflow-item.send-back.button.cancel": "Anuluj", + "workflow-item.send-back.button.confirm": "Odeślij", + "workflow-item.view.breadcrumbs": "Widok procesu", + "idle-modal.header": "Sesja wkrótce wygaśnie", + "idle-modal.info": "Ze względów bezpieczeństwa sesja wygaśnie po {{ timeToExpire }} minutach nieaktywności. Twoja sesja wkrótce wygaśnie. Czy chcesz ją przedłużyć albo wylogować się?", + "idle-modal.log-out": "Wyloguj", + "idle-modal.extend-session": "Wydłuż sesję", + "workspace.search.results.head": "Twoje zadania", + "orgunit.listelement.badge": "Jednostka organizacyjna", + "orgunit.page.city": "Miasto", + "orgunit.page.country": "Kraj", + "orgunit.page.dateestablished": "Data założenia", + "orgunit.page.description": "Opis", + "orgunit.page.edit": "Edytuj pozycję", + "orgunit.page.id": "ID", + "orgunit.page.titleprefix": "Jednostka organizacyjna: ", + "pagination.options.description": "Opcje strony", + "pagination.results-per-page": "Wyników na stronę", + "pagination.showing.detail": "{{ range }} z {{ total }}", + "pagination.showing.label": "Teraz wyświetlane ", + "pagination.sort-direction": "Opcje sortowania", + "cookies.consent.purpose.sharing": "Udostępnianie", + "item.preview.dc.identifier.issn": "ISSN", + "500.page-internal-server-error": "Usługa niedostępna", + "500.help": "Serwer jest tymczasowo niezdolny do obsługi Twojego żądania z powodu przestoju konserwacyjnego lub problemów z przepustowością. Prosimy spróbować ponownie później.", + "500.link.home-page": "Zabierz mnie na stronę główną", + "error-page.description.401": "brak autoryzacji", + "error-page.description.403": "brak dostępu", + "error-page.description.500": "usługa niedostępna", + "error-page.description.404": "nie znaleziono strony", + "error-page.orcid.generic-error": "Podczas logowania za pomocą ORCID wystąpił błąd. Upewnij się, że udostępniłeś DSpace adres e-mail swojego konta ORCID. Jeśli błąd nadal występuje, skontaktuj się z administratorem", + "access-status.embargo.listelement.badge": "Embargo", + "access-status.metadata.only.listelement.badge": "Tylko metadane", + "access-status.open.access.listelement.badge": "Open Access", + "access-status.restricted.listelement.badge": "Brak dostępu", + "access-status.unknown.listelement.badge": "Nieznane", + "admin.access-control.groups.table.edit.buttons.remove": "Usuń \"{{name}}\"", + "admin.metadata-import.page.validateOnly": "Tylko waliduj", + "admin.metadata-import.page.validateOnly.hint": "Po wybraniu tej opcji przesłany plik CSV zostanie poddany walidacji. Otrzymasz raport o wykrytych zmianach, ale żadne zmiany nie zostaną zapisane.", + "bitstream.edit.form.iiifLabel.label": "Etykieta canvyIIIF", + "bitstream.edit.form.iiifLabel.hint": "Etykieta dla tego obrazu. Jeśli nie została dostarczona, zostanie użyta domyślna etykieta.", + "bitstream.edit.form.iiifToc.label": "Spis treści IIIF", + "bitstream.edit.form.iiifToc.hint": "Dodanie tekstu tutaj zapoczątkuje nowy zakres spisu treści.", + "bitstream.edit.form.iiifWidth.label": "Szerokość canvy IIIF", + "bitstream.edit.form.iiifWidth.hint": "Szerokość canvy jest zwykle równa szerokości obrazu.", + "bitstream.edit.form.iiifHeight.label": "Wysokość canvy IIIF", + "bitstream.edit.form.iiifHeight.hint": "Wysokość canvy jest zwykle równa szerokości obrazu.", + "browse.back.all-results": "Wszystkie wyniki wyszukiwania", + "pagination.next.button": "Następny", + "pagination.previous.button": "Poprzedni", + "pagination.next.button.disabled.tooltip": "Brak więcej stron z wynikami wyszukiwania", + "browse.startsWith": ", zaczyna się od {{ startsWith }}", + "browse.title.page": "Przeszukiwanie {{ collection }} wg {{ field }} {{ value }}", + "collection.edit.item.authorizations.load-bundle-button": "Załaduj więcej paczek", + "collection.edit.item.authorizations.load-more-button": "Załaduj więcej", + "collection.edit.item.authorizations.show-bitstreams-button": "Pokaż polityki plików dla paczek", + "comcol-role.edit.create.error.title": "Nie udało się utworzyć grupy dla roli '{{ role }}'", + "curation.form.submit.error.invalid-handle": "Nie ustalono identyfikatora dla tego obiektu", + "confirmation-modal.delete-profile.header": "Usuń profil", + "confirmation-modal.delete-profile.info": "Czy na pewno chcesz usunąć profil", + "confirmation-modal.delete-profile.cancel": "Anuluj", + "confirmation-modal.delete-profile.confirm": "Usuń", + "error.invalid-search-query": "Zapytanie nie jest poprawne. Wejdź na <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.html\" target=\"_blank\">Solr query syntax</a>, aby dowiedzieć się o najlepszych praktykach i dodatkowych informacjach o tym błędzie.", + "feed.description": "Aktualności", + "footer.link.feedback": "Prześlij uwagi", + "form.group-collapse": "Zwiń", + "form.group-collapse-help": "Kliknij tutaj, aby zwinąć", + "form.group-expand": "Rozwiń", + "form.group-expand-help": "Kliknij tutaj, aby rozwinąć", + "health.breadcrumbs": "Stan systemu", + "health-page.heading": "Stan systemu", + "health-page.info-tab": "Informacje", + "health-page.status-tab": "Status", + "health-page.error.msg": "Serwis stanu systemu jest tymczasowo niedostępny", + "health-page.property.status": "Kod statusu", + "health-page.section.db.title": "Baza danych", + "health-page.section.geoIp.title": "GeoIp", + "health-page.section.solrAuthorityCore.title": "Autentykacja", + "health-page.section.solrOaiCore.title": "OAI", + "health-page.section.solrSearchCore.title": "Wyszukiwarka", + "health-page.section.solrStatisticsCore.title": "Statystyki", + "health-page.section-info.app.title": "Backend aplikacji", + "health-page.section-info.java.title": "Java", + "health-page.status": "Status", + "health-page.status.ok.info": "operacyjny", + "health-page.status.error.info": "Wykryte problemy", + "health-page.status.warning.info": "Wykryte potencjalne problemy", + "health-page.title": "Stan systemu", + "health-page.section.no-issues": "Nie wykryto żadnych problemów", + "info.feedback.breadcrumbs": "Uwagi", + "info.feedback.head": "Uwagi", + "info.feedback.title": "Uwagi", + "info.feedback.info": "Dziękujemy za podzielenie się opinią na temat systemu DSpace. Doceniamy Twój wkład w lepsze działanie systemu!", + "info.feedback.email_help": "Ten adres zostanie użyty, aby przesłać odpowiedź na uwagi.", + "info.feedback.send": "Prześlij uwagi", + "info.feedback.comments": "Komentarz", + "info.feedback.email-label": "Twoj adres e-mail", + "info.feedback.create.success": "Uwagi przesłane!", + "info.feedback.error.email.required": "Poprawny adres e-mail jest wymagany", + "info.feedback.error.message.required": "Treść komentarza jest wymagana", + "info.feedback.page-label": "Strona", + "info.feedback.page_help": "Ta strona odnosi się do uwag.", + "item.orcid.return": "Powrót", + "item.truncatable-part.show-more": "Pokaż więcej", + "item.truncatable-part.show-less": "Pokaż mniej", + "item.page.orcid.title": "ORCID", + "item.page.orcid.tooltip": "Otwórz ustawienia ORCID", + "item.page.claim.button": "Podejmij pracę", + "item.page.claim.tooltip": "Podejmij pracę jako profil", + "item.version.create.modal.submitted.header": "Tworzenie nowej wersji...", + "item.version.create.modal.submitted.text": "Nowa wersja została utworzona. Mogło to trwać chwilę, jeśli pozycja ma wiele powiązań.", + "journal-relationships.search.results.head": "Wyniki wyszukiwania czasopism", + "menu.section.icon.health": "Sekcja menu Stan systemu", + "menu.section.health": "Stan systemu", + "metadata-export-search.tooltip": "Eksportuj wyniki wyszukiwania w formacie CSV", + "metadata-export-search.submit.success": "Eksport rozpoczął się", + "metadata-export-search.submit.error": "Eksport nie rozpoczął się", + "person.page.name": "Nazwa", + "person-relationships.search.results.head": "Wyniki wyszukiwania osób", + "profile.special.groups.head": "Autoryzacja do specjalnych grup, do których należysz", + "project-relationships.search.results.head": "Wyniki wyszukiwania projektów", + "publication-relationships.search.results.head": "Wyniki wyszukiwania publikacji", + "resource-policies.edit.page.target-failure.content": "Wystąpił błąd podczas edycji (użytkownika lub grupy) związany z polityką zasobu.", + "resource-policies.edit.page.other-failure.content": "Wystąpił błąd podczas edycji polityki zasobu. Użytkownik lub grupa zostały zaktualizowane pomyślnie.", + "resource-policies.form.eperson-group-list.modal.header": "Nie można zmienić typu", + "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Nie można zastąpić użytkownika grupą.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Nie można zastąpić grupy użytkownikiem.", + "resource-policies.form.eperson-group-list.modal.text2": "Usuń obecną polityke zasobu i stwórz nową o określonym typie.", + "resource-policies.form.eperson-group-list.modal.close": "Ok", + "search.results.view-result": "Widok", + "default-relationships.search.results.head": "Wyniki wyszukiwania", + "statistics.table.title.TotalVisits": "Wyświetlnia ogółem", + "statistics.table.title.TotalVisitsPerMonth": "Wyświetlenia w miesiącu", + "statistics.table.title.TotalDownloads": "Pobrania", + "statistics.table.title.TopCountries": "Wyświetlenia wg krajów", + "statistics.table.title.TopCities": "Wyświetlenia wg miast", + "submission.import-external.preview.title": "Podgląd pozycji", + "submission.import-external.preview.title.none": "Podgląd pozycji", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Import pozycji zdalnie", + "submission.sections.general.cannot_deposit": "Nie można zakończyć deponowania, ponieważ w formularzu wystąpiły błędy.<br>Aby zakończyć deponowanie, wypełnij wszystkie obowiązkowe pola.", + "submission.sections.submit.progressbar.accessCondition": "Warunki dostępu do pozycji", + "submission.sections.submit.progressbar.sherpapolicy": "Polityki Sherpa", + "submission.sections.submit.progressbar.sherpaPolicies": "Informacje o polityce open access wydawcy.", + "submission.sections.status.info.title": "Dodatkowe informacje", + "submission.sections.status.info.aria": "Dodatkowe informacje", + "submission.sections.upload.form.access-condition-hint": "Wybierz w jaki sposób pliki dla tej pozycji po jest zdeponowaniu będą mogły być udostępnione", + "submission.sections.upload.form.from-hint": "Wybierz datę, od której ma zostać zastosowany warunek dostępu", + "submission.sections.upload.form.until-hint": "Wybierz datę, do której ma zostać zastosowany warunek dostępu", + "submission.sections.accesses.form.discoverable-description": "Jeśli checkbox jest zaznaczony, pozycja będzie wyświetlana w wynikach wyszukiwania. Jeśli checkbox jest odznaczony, dostęp do pozycji będzie dostępny tylko przez bezpośredni link, pozycja nie będzie wyświetlana w wynikach wyszukiwania.", + "submission.sections.accesses.form.discoverable-label": "Niemożliwe do wyszukania", + "submission.sections.accesses.form.access-condition-label": "Typ warunku dostępu", + "submission.sections.accesses.form.access-condition-hint": "Wybierz warunek dostępu, aby przypisać go do pozycji, kiedy zostanie zdeponowany.", + "submission.sections.accesses.form.date-required": "Data jest wymagana.", + "submission.sections.accesses.form.date-required-from": "Początkowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.date-required-until": "Końcowa data przyznania dostępu jest wymagana.", + "submission.sections.accesses.form.from-label": "Udziel dostępu od", + "submission.sections.accesses.form.from-hint": "Wybierz datę, od kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.from-placeholder": "Od", + "submission.sections.accesses.form.group-label": "Grupa", + "submission.sections.accesses.form.group-required": "Grupa jest wymagana.", + "submission.sections.accesses.form.until-label": "Udziel dostępu do", + "submission.sections.accesses.form.until-hint": "Wybierz datę, do kiedy zostanie przyznany dostęp do tej pozycji", + "submission.sections.accesses.form.until-placeholder": "Do", + "submission.sections.sherpa.publication.information": "Informacje o publikacji", + "submission.sections.sherpa.publication.information.title": "Tytuł", + "submission.sections.sherpa.publication.information.issns": "Numery ISSN", + "submission.sections.sherpa.publication.information.url": "URL", + "submission.sections.sherpa.publication.information.publishers": "Wydawca", + "submission.sections.sherpa.publication.information.romeoPub": "Wydawca Romeo", + "submission.sections.sherpa.publication.information.zetoPub": "Wydawca Zeto", + "submission.sections.sherpa.publisher.policy": "Polityka wydawnicza", + "submission.sections.sherpa.publisher.policy.description": "Poniższe informacje zostały znalezione za pośrednictwem Sherpa Romeo. W oparciu o politykę Twojego wydawcy, zawiera ona porady dotyczące tego, czy embargo może być konieczne i/lub jakie pliki możesz przesłać. Jeśli masz pytania, skontaktuj się z administratorem strony poprzez formularz.", + "submission.sections.sherpa.publisher.policy.openaccess": "Rodzaje Open Access dozwolone przez politykę wydawniczą tego czasopisma są wymienione poniżej. Kliknij na wybrany rodzaj, aby przejść do szczegółowego widoku", + "submission.sections.sherpa.publisher.policy.more.information": "Aby uzuyskać więcej informacji, kliknij tutaj:", + "submission.sections.sherpa.publisher.policy.version": "Wersja", + "submission.sections.sherpa.publisher.policy.embargo": "Embargo", + "submission.sections.sherpa.publisher.policy.noembargo": "Brak embargo", + "submission.sections.sherpa.publisher.policy.nolocation": "Brak", + "submission.sections.sherpa.publisher.policy.license": "Licencja", + "submission.sections.sherpa.publisher.policy.prerequisites": "Wymagania wstępne", + "submission.sections.sherpa.publisher.policy.location": "Lokalizacja", + "submission.sections.sherpa.publisher.policy.conditions": "Wymagania", + "submission.sections.sherpa.publisher.policy.refresh": "Odśwież", + "submission.sections.sherpa.record.information": "Informacje o rekordzie", + "submission.sections.sherpa.record.information.id": "ID", + "submission.sections.sherpa.record.information.date.created": "Data utworzenia", + "submission.sections.sherpa.record.information.date.modified": "Ostatnia modyfikacja", + "submission.sections.sherpa.record.information.uri": "URI", + "submission.sections.sherpa.error.message": "Wystąpił błąd podczas pobierania informacji z Sherpa", + "submission.workspace.generic.view": "Podgląd", + "submission.workspace.generic.view-help": "Wybierz tę opcje, aby zobaczyć metadane.", + "workflow.search.results.head": "Zadania na workflow", + "workspace-item.view.breadcrumbs": "Widok wersji roboczej", + "workspace-item.view.title": "Widok wersji roboczej", + "researcher.profile.change-visibility.fail": "Wystąpił niespodziewany błąd podczas zmiany widoczności profilu", + "person.page.orcid.link.processing": "Łączenie profilu z ORCID...", + "person.page.orcid.link.error.message": "Coś poszło nie tak podczas łączenia z ORCID. Jeśli problem będzie się powtarzał, skontaktuj się z administratorem.", + "person.page.orcid.sync-queue.table.header.type": "Typ", + "person.page.orcid.sync-queue.table.header.description": "Opis", + "person.page.orcid.sync-queue.table.header.action": "Akcja", + "person.page.orcid.sync-queue.tooltip.project": "Projekt", + "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Niewłaściwy dwuznakowy kod kraju ISO 3166", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Wymagana data publikacji to co najmniej rok po 1900", + "person.page.orcid.synchronization-mode-funding-message": "Wybierz, czy chcesz wysłać swoje projekty na swoją listę informacji o projektach w profilu ORCID.", + "person.page.orcid.synchronization-mode-publication-message": "Wybierz, czy chcesz wysłać swoje publikacje na swoją listę informacji o publikacjach w profilu ORCID.", + "person.page.orcid.synchronization-mode-profile-message": "Wybierz, czy chcesz wysłać swoje dane bibliograficzne lub osobiste identyfikatory do swojego profilu ORCID.", + "person.orcid.sync.setting": "Ustawienia synchronizacji z ORCID", + "person.orcid.registry.queue": "Kolejka rejestru z ORCID", + "person.orcid.registry.auth": "Autoryzacje z ORCID", + "home.recent-submissions.head": "Najnowsze publikacje", + "submission.sections.sherpa-policy.title-empty": "Nie wybrano ISSN i informacje o polityce wydawniczej czasopisma są niedostępne", + "admin.batch-import.breadcrumbs": "Import zbiorczy", + "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", + "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", + "admin.batch-import.page.error.addFile": "Najpierw wybierz plik (ZIP)", + "admin.batch-import.page.header": "Import masowy", + "admin.batch-import.page.help": "Wybierz kolekcję do zaimportowania kolekcji. Potem, upuść lub przeszukaj plik SAF, który zawiera pozycje do importu", + "admin.batch-import.page.remove": "usuń", + "admin.batch-import.page.validateOnly.hint": "Jeśli wybrano, importowany plik ZIP będzie walidowany. Otrzymasz raport ze zmianami, ale żadne zmiany nie zostaną wykonane zapisane.", + "collection.form.correctionSubmissionDefinition": "Wzór zgłoszenia do prośby o korektę", + "comcol-role.edit.delete.error.title": "Nie udało się usunąć roli '{{ role }}' dla grup", + "confirmation-modal.export-batch.header": "Eksport maasowy (ZIP) {{ dsoName }}", + "confirmation-modal.export-batch.info": "Czy na pewno chcesz wyeksportować plik ZIP z {{ dsoName }}", + "dso-selector.export-batch.dspaceobject.head": "Eksport masowy (ZIP) z", + "menu.section.export_batch": "Eksport masowy (ZIP)", + "nav.user-profile-menu-and-logout": "Profil użytkownika i wylogowywanie", + "process.detail.actions": "Akcje", + "process.detail.delete.body": "Czy na pewno chcesz usunąć bieżący proces?", + "process.detail.delete.button": "Usuń proces", + "process.detail.delete.cancel": "Anuluj", + "process.detail.delete.confirm": "Usuń proces", + "process.detail.delete.error": "Nie udało się usunąć procesu", + "process.detail.delete.header": "Usuń proces", + "process.detail.delete.success": "Proces został usunięty.", + "admin.batch-import.title": "Masowy import", + "admin.metadata-import.page.button.select-collection": "Wybierz kolekcję", + "admin.registries.bitstream-formats.table.id": "ID", + "admin.registries.schema.fields.table.id": "ID", + "cookies.consent.app.description.google-recaptcha": "Podczas rejestracji i odzyskiwania hasła używamy narzędzia google reCAPTCHA", + "cookies.consent.app.disable-all.description": "Przełącz, aby zaakceptować lub odrzucić wszystkie", + "cookies.consent.app.disable-all.title": "Akceptowacja lub odrzucenie wszystkich", + "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + "cookies.consent.content-modal.service": "usługa", + "cookies.consent.content-modal.services": "usługi", + "cookies.consent.content-notice.description.no-privacy": "Zbieramy i przetwarzamy Twoje dane w celu: <strong>autentykacji, ustawień preferencji i zgód oraz do celów statystycznych</strong>.", + "cookies.consent.content-notice.title": "Zgoda na ciasteczka", + "cookies.consent.ok": "Zgadzam się", + "cookies.consent.purpose.registration-password-recovery": "Rejestracja i odzyskiwanie hasła", + "cookies.consent.save": "Zapisz", + "curation-task.task.citationpage.label": "Generuj stronę z cytowaniem", + "dso-selector.import-batch.dspaceobject.head": "Import masowy z", + "orgunit.listelement.no-title": "Brak tytyłu", + "process.bulk.delete.error.body": "Proces z ID {{processId}} nie może być usunięty. Pozostałe procesy zostaną usunięte.", + "process.bulk.delete.error.head": "Błąd podczas usuwania procesu", + "process.bulk.delete.success": "{{count}} proces/y został/y usunięte", + "process.overview.delete": "Usuń {{count}} proces/y", + "process.overview.delete.body": "Czy na pewno usunąć {{count}} proces/y?", + "process.overview.delete.clear": "Wyczyść selekcję procesów do usunięcia", + "process.overview.delete.header": "Usuń procesy", + "process.overview.delete.processing": "{{count}} procesów zostanie usuniętych. Poczekaj, gdy usuwanie się zakończy. Może to zająć chwilę.", + "process.overview.table.actions": "Akcje", + "profile.security.form.label.current-password": "Aktualne hasło", + "profile.security.form.notifications.error.change-failed": "Wystąpił błąd podczas próby zmiany hasła. Sprawdź czy aktualne hasło jest prawidłowe.", + "profile.security.form.notifications.error.general": "Uzupełnij wymagane pola dla bezpieczeństwa na formularzu", + "register-page.registration.error.recaptcha": "Wystąpił błąd podczas próby autentykacji przez reCAPTCHA", + "register-page.registration.google-recaptcha.must-accept-cookies": "Aby się zarejestrować, musisz zaakceptować ciasteczka dla <b>rejestracji i odzyskiwania hasła</b> (Google reCaptcha).", + "register-page.registration.google-recaptcha.notification.message.error": "Wystąpił błąd podczas weryfikacji reCaptcha", + "register-page.registration.google-recaptcha.notification.message.expired": "Weryfikacja wygasła. Zweryfikuj ponownie.", + "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + "register-page.registration.google-recaptcha.open-cookie-settings": "Otwórz ustawienia plików cookies", + "search.results.response.500": "Wystąpił błąd podczas wysyłania zapytania. Spróbuj ponownie później", + "submission.sections.license.granted-label": "Potwierdzam akceptację powyższej licencji", + "submission.sections.license.notgranted": "Najpierw musisz zaakceptować licencję", + "submission.sections.license.required": "Najpierw musisz zaakceptować licencję", + "confirmation-modal.export-batch.confirm": "Eksportuj", + "confirmation-modal.export-batch.cancel": "Anuluj", + "admin.access-control.bulk-access.breadcrumbs": "Zbiorcza edycja dostępu do osiągnięć", + "administrativeBulkAccess.search.results.head": "Wyniki wyszukiwania", + "admin.access-control.bulk-access": "Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access.title": "Zbiorcza edycja dostępu do osiągnięć", + "admin.access-control.bulk-access-browse.header": "Krok 1: Wybierz pozycje", + "admin.access-control.bulk-access-browse.search.header": "Wyszukaj", + "admin.access-control.bulk-access-browse.selected.header": "Obecny wybór({{number}})", + "admin.access-control.bulk-access-settings.header": "Krok 2: Działanie do wykonania", + "admin.access-control.groups.form.tooltip.editGroupPage": "Na tej stronie można edytować opcje grupy i przypisane do niej osoby. W górnej sekcji można edytować nazwę i opis grupy, chyba że jest to grupa administratorów dla zbioru i kolekcji. W tym przypadku nazwa i opis grupy są generowane automatycznie i nie można ich edytować. W kolejnych sekcjach można edytować przypisanie użytkowników do grupy. Szczegóły na [stronie](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group).", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Aby dodać lub usunąć użytkownika do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj paska wyszukiwania poniżej, aby wyszukać użytkowników (użyj listy rozwijanej po lewej stronie paska wyszukiwania, aby wybrać, czy chcesz wyszukiwać według imienia i nazwiska, czy według adresu e-mail). Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może mieć kilka stron: użyj strzałek pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Aby dodać lub usunąć podgrupę do/z tej grupy, kliknij przycisk 'Przeglądaj wszystko' lub użyj wyszukiwarki poniżej, aby wyszukać użytkowników. Następnie kliknij ikonę plusa przy każdym użytkowniku, którego chcesz dodać do poniższej listy, lub ikonę kosza przy każdym użytkowniku, którego chcesz usunąć. Poniższa lista może składać się z kilku stron: użyj przycisków pod listą, aby przejść do kolejnych stron. Gdy wszystkie zmiany zostaną wprowadzone, zapisz je, klikając przycisk 'Zapisz' w górnej sekcji.", + "admin.workflow.item.workspace": "Przestrzeń robocza", + "admin.workflow.item.policies": "Polityki", + "admin.workflow.item.supervision": "Recenzja", + "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", + "admin.metadata-import.page.error.addFileUrl": "Najpierw wpisz URL pliku!", + "admin.metadata-import.page.toggle.upload": "Prześlij", + "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.urlMsg": "Wpisz URL pliku ZIP, aby wykonać import masowy", + "advanced-workflow-action.rating.form.rating.label": "Ocena", + "advanced-workflow-action.rating.form.rating.error": "Ta pozycja musi zostać oceniona", + "advanced-workflow-action.rating.form.review.label": "Recenzja", + "advanced-workflow-action.rating.form.review.error": "Musisz wpisać tekst recenzji", + "advanced-workflow-action.rating.description": "Wybierz ocenę poniżej", + "advanced-workflow-action.rating.description-requiredDescription": "Wybierz ocenę poniżej i wpisz uzasadnienie", + "advanced-workflow-action.select-reviewer.description-single": "Wybierz recenzenta przed zdeponowaniem pozycji", + "advanced-workflow-action.select-reviewer.description-multiple": "Wybierz jednego lub więcej recenzentów przed zdeponowaniem pozycji", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "Użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Dodaj użytkownika", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Przeglądaj wszystko", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Aktualni użytkownicy", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadane", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "Adres e-mail (dokładny)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Wyszukaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nazwa", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Tożsamość", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Adres e-mail", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.netid": "NetID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Usuń / Dodaj", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Usuń użytkownika z nazwę \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Dodano użytkownika o nazwie: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Nie dodano użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Nie usunięto użytkownika: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Dodano użytkownika \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Brak aktywnej grupy, najpierw wpisz nazwę.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "W tej grupie nie ma użytkowników, wyszukaj ich i dodaj.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nie znaleziono żadnych użytkowników", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Recenzent nie jest wybrany.", + "bitstream.edit.notifications.error.primaryBitstream.title": "Wystąpił błąd podczas zapisu pliku.", + "browse.comcol.by.srsc": "Wg słów kluczowych", + "browse.metadata.srsc.breadcrumbs": "Przeglądaj wg słów kluczowych", + "browse.startsWith.input": "Filtr", + "browse.taxonomy.button": "Przeglądaj", + "search.browse.item-back": "Powrót do wyników wyszukiwania", + "claimed-approved-search-result-list-element.title": "Zaakceptowano", + "claimed-declined-search-result-list-element.title": "Odrzucono i przesłano do deponującego", + "claimed-declined-task-search-result-list-element.title": "Odrzucono i przesłano do recenzenta", + "collection.edit.tabs.access-control.head": "Dostępy", + "collection.edit.tabs.access-control.title": "Edycja kolekcji - dostępy", + "collection.listelement.badge": "Kolekcja", + "community.edit.tabs.access-control.head": "Dostępy", + "community.edit.tabs.access-control.title": "Edycja zbioru - dostępy", + "comcol-role.edit.scorereviewers.name": "Ocena recenzenta", + "comcol-role.edit.scorereviewers.description": "Recenzenci mogą oceniać zdeponowane pozycje, co określi, czy pozycja zostanie przyjęta lub odrzucona.", + "curation-task.task.register-doi.label": "Rejestracja DOI", + "dso.name.unnamed": "Bez nazwy", + "dso-selector.create.community.or-divider": "lub", + "dso-selector.set-scope.community.or-divider": "lub", + "dso-selector.results-could-not-be-retrieved": "Wystąpił błąd, proszę odświeżyć stronę", + "supervision-group-selector.header": "Wybór grupy recenzenckiej", + "supervision-group-selector.select.type-of-order.label": "Wybierz typ funkcji", + "supervision-group-selector.select.type-of-order.option.none": "BRAK", + "supervision-group-selector.select.type-of-order.option.editor": "REDAKTOR", + "supervision-group-selector.select.type-of-order.option.observer": "OBSERWATOR", + "supervision-group-selector.select.group.label": "Wybierz grupę", + "supervision-group-selector.button.cancel": "Anuluj", + "supervision-group-selector.button.save": "Zapisz", + "supervision-group-selector.select.type-of-order.error": "Wybierz typ funkcji", + "supervision-group-selector.select.group.error": "Wybierz grupę", + "supervision-group-selector.notification.create.success.title": "Grupa recenzencka został dodana dla grupy {{ name }}", + "supervision-group-selector.notification.create.failure.title": "Błąd", + "supervision-group-selector.notification.create.already-existing": "Funkcja recenzenta już jest przypisana do tej grupy", + "confirmation-modal.delete-subscription.header": "Usuń subksrypcje", + "confirmation-modal.delete-subscription.info": "Czy na pewno chcesz usunąć subskrypcję: \"{{ dsoName }}\"", + "confirmation-modal.delete-subscription.cancel": "Anuluj", + "confirmation-modal.delete-subscription.confirm": "Usuń", + "error.validation.metadata.name.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.name.max-length": "To pole nie może zawierać więcej niż 32 znaki", + "error.validation.metadata.namespace.max-length": "To pole nie może zawierać więcej niż 256 znaków", + "error.validation.metadata.element.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji. Zamiast tego This field cannot contain dots, commas or spaces. Zamiast tego może użyć pól z notacji SNEQ", + "error.validation.metadata.element.max-length": "To pole nie może zawierać więcej niż 64 znaki", + "error.validation.metadata.qualifier.invalid-pattern": "To pole nie może zawierać kropek, przecinków i spacji", + "error.validation.metadata.qualifier.max-length": "To pole nie może zawierać więcej niż 64 znaki", + "forgot-email.form.email.error.not-email-form": "Wpisz prawidłowy adres e-mail", + "form.other-information.email": "Adres e-mail", + "form.other-information.first-name": "Imię", + "form.other-information.insolr": "Solr Index", + "form.other-information.institution": "Instytucja", + "form.other-information.last-name": "Nazwisko", + "form.other-information.orcid": "ORCID", + "form.create": "Utwórz", + "info.end-user-agreement.hosting-country": "Stany Zjednoczone", + "item.edit.identifiers.doi.status.UNKNOWN": "Nieznane", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "W kolejce do rejestracji", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "W kolejce do rezerwacji", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Zarejestrowane", + "item.edit.identifiers.doi.status.IS_RESERVED": "Zarezerwowane", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Zarezerwowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Zarejestrowane (aktualizacja w kolejce)", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "W kolejce do aktualizacji i rejestracji", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "Zakolejkowane do usunięcia", + "item.edit.identifiers.doi.status.DELETED": "Usunięte", + "item.edit.identifiers.doi.status.PENDING": "Oczekujące (niezarejestrowane)", + "item.edit.identifiers.doi.status.MINTED": "Rezerwowanie nazwy (niezarejestrowane)", + "item.edit.tabs.status.buttons.register-doi.label": "Zarejestruj nowe lub oczekujące DOI", + "item.edit.tabs.status.buttons.register-doi.button": "Rejestruj DOI...", + "item.edit.register-doi.header": "Zarejestruj nowe lub oczekujące DOI", + "item.edit.register-doi.description": "Zweryfikuj poniższe identyfikatory i metadane pozycji i rozpocznij rejestrację DOI lub anuluj", + "item.edit.register-doi.confirm": "Zatwierdź", + "item.edit.register-doi.cancel": "Anuluj", + "item.edit.register-doi.success": "DOI jest w kolejce do rejestracji.", + "item.edit.register-doi.error": "Wystąpił błąd poczas rejestracji DOI", + "item.edit.register-doi.to-update": "To DOI zostało zarezerwowane i będzie znajdować się w kolejce do rejestracji", + "item.edit.metadata.edit.buttons.confirm": "Zatwierdź", + "item.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", + "item.edit.metadata.edit.buttons.virtual": "To pole przechowuje wirutalne wartości metadanych, np. wartość pobraną z encji, z którą jest połączona ta pozycja. Dodaj lub usuń relację w zakładce 'Relacje' ", + "item.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidcji pól metadanych", + "item.edit.metadata.reset-order-button": "Cofnij zamianę kolejności", + "item.edit.curate.title": "Zarządzaj pozycją: {{item}}", + "item.edit.tabs.access-control.head": "Dostęp", + "item.edit.tabs.access-control.title": "Edycja pozycji - dostęp", + "workflow-item.search.result.delete-supervision.modal.header": "Usuń zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.info": "Czy na pewno usunąć zadanie dla recenzenta", + "workflow-item.search.result.delete-supervision.modal.cancel": "Anuluj", + "workflow-item.search.result.delete-supervision.modal.confirm": "Usuń", + "workflow-item.search.result.notification.deleted.success": "Usunięto zadanie dla recenzenta \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Nie usunięto zadania dla recenzenta \"{{name}}\"", + "workflow-item.search.result.list.element.supervised-by": "Recenzja:", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Usuń grupę recenzencką", + "item.preview.dc.subject": "Słowo kluczowe:", + "item.preview.dc.publisher": "Wydawca:", + "itemtemplate.edit.metadata.add-button": "Dodaj", + "itemtemplate.edit.metadata.discard-button": "Cofnij", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Zatwierdź", + "itemtemplate.edit.metadata.edit.buttons.drag": "Przeciągnij, aby zmienić kolejność", + "itemtemplate.edit.metadata.edit.buttons.edit": "Edytuj", + "itemtemplate.edit.metadata.edit.buttons.remove": "Usuń", + "itemtemplate.edit.metadata.edit.buttons.undo": "Cofnij zmiany", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Nie edytuj", + "itemtemplate.edit.metadata.empty": "To pozycja nie zawiera żadnych metadanych. Wybierz Dodaj, aby je wprowadzić.", + "itemtemplate.edit.metadata.headers.edit": "Edytuj", + "itemtemplate.edit.metadata.headers.field": "Pole", + "itemtemplate.edit.metadata.headers.language": "Język", + "itemtemplate.edit.metadata.headers.value": "Wartość", + "itemtemplate.edit.metadata.metadatafield.error": "Wystąpił błąd podczas walidowania pola metadanych", + "itemtemplate.edit.metadata.metadatafield.invalid": "Wybierz odpowiednie pole metadanych", + "itemtemplate.edit.metadata.notifications.discarded.content": "Twoje zmiany nie zostały zachowane. Aby spróbować wprowadzić je ponownie wybierz Cofnij", + "itemtemplate.edit.metadata.notifications.discarded.title": "Zmiany nie zostały zachowane", + "itemtemplate.edit.metadata.notifications.error.title": "Wystąpił błąd", + "itemtemplate.edit.metadata.notifications.invalid.content": "Twoje zmiany nie zostały zapisane. Upewnij się, że wszystkie pola zostały wypełnione prawidłowo.", + "itemtemplate.edit.metadata.notifications.invalid.title": "Nieprawidłowe metadan", + "itemtemplate.edit.metadata.notifications.outdated.content": "Wzór dla pozycji, na którą w tym momencie pracujesz, został zmodyfikowany przez innego użytkownika. Twoje zmiany zostały odrzucone, aby uniknąć konfliktów pomiędzy wersjami.", + "itemtemplate.edit.metadata.notifications.outdated.title": "Zmiany zostały odrzucone", + "itemtemplate.edit.metadata.notifications.saved.content": "Zmiany w metadanych wzoru pozycji zostały zapisane.", + "itemtemplate.edit.metadata.notifications.saved.title": "Metadane zostały zapisane", + "itemtemplate.edit.metadata.reinstate-button": "Cofnij", + "itemtemplate.edit.metadata.reset-order-button": "Cofnij zmianę kolejności", + "itemtemplate.edit.metadata.save-button": "Zapisz", + "menu.section.access_control_bulk": "Zbiorowe zarządzanie dostępem", + "menu.section.browse_global_by_srsc": "Wg słów kluczowych", + "mydspace.show.supervisedWorkspace": "Pozycje recenzowane", + "mydspace.status.mydspaceArchived": "Opublikowano", + "mydspace.status.mydspaceValidation": "Walidacja", + "mydspace.status.mydspaceWaitingController": "Oczekiwanie na redakctora", + "mydspace.status.mydspaceWorkflow": "Redakcja", + "mydspace.status.mydspaceWorkspace": "Przestrzeń robocza", + "nav.context-help-toggle": "Przełącz pomoc kontekstową", + "nav.search.button": "Wpisz wyszukiwaną frazę", + "nav.subscriptions": "Subksrypcje", + "process.new.notification.error.max-upload.content": "Plik jest większy niż maksymalny dozwolony rozmiar pliku", + "register-page.registration.email.error.not-email-form": "Wprowadź poprawny adres e-mail", + "register-page.registration.email.error.not-valid-domain": "Użyj adresu e-mail z domeny: {{ domains }}", + "register-page.registration.error.maildomain": "Tego adresu e-mail nie możesz zarejestrować, ponieważ nie ma go na liście domen. Dozwolone domeny to: {{ domains }}", + "register-page.registration.info.maildomain": "Konta mogą być założone dla adresów e-mail z domeną", + "repository.title": "Repozytorium DSpace", + "search.filters.applied.f.supervisedBy": "Recenzent", + "search.filters.filter.show-tree": "Przeglądaj {{ name }} strukturę recenzentów", + "search.filters.filter.supervisedBy.head": "Recenzent", + "search.filters.filter.supervisedBy.placeholder": "Recenzent", + "search.filters.filter.supervisedBy.label": "Wyszukaj recenzenta", + "statistics.table.no-name": "(nazwa obiektu nie może zostać załadowana)", + "submission.import-external.source.datacite": "DataCite", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publikacje autora", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publikacje", + "submission.sections.identifiers.info": "Te identyfikatory zostaną utworzone dla pozycji:", + "submission.sections.identifiers.no_handle": "Do tej pozycji nie zostały przypisane żadne Handle", + "submission.sections.identifiers.no_doi": "Do tej pozycji nie zostały przypisane żadne DOI", + "submission.sections.identifiers.handle_label": "Handle: ", + "submission.sections.identifiers.doi_label": "DOI: ", + "submission.sections.identifiers.otherIdentifiers_label": "Inne identyfikatory: ", + "submission.sections.submit.progressbar.identifiers": "Identyfikatory", + "submission.workflow.generic.submit_select_reviewer": "Wybierz recenzenta", + "submission.workflow.generic.submit_select_reviewer-help": "", + "submission.workflow.generic.submit_score": "Wynik", + "submission.workflow.generic.submit_score-help": "", + "submission.workflow.tasks.claimed.decline": "Odrzuć", + "submission.workflow.tasks.claimed.decline_help": "", + "submitter.empty": "n.d.", + "subscriptions.title": "Subskrypcje", + "subscriptions.item": "Subskrypcje pozycji", + "subscriptions.collection": "Subskrypcje kolekcji", + "subscriptions.community": "Subskrypcje zbiorów", + "subscriptions.subscription_type": "Typ subksrypcji", + "subscriptions.frequency": "Częstotliwość subskrypcji", + "subscriptions.frequency.D": "Codziennie", + "subscriptions.frequency.M": "Co miesiąc", + "subscriptions.frequency.W": "Co tydzień", + "subscriptions.tooltip": "Subskrybuj", + "subscriptions.modal.title": "Subksrypcje", + "subscriptions.modal.type-frequency": "Rodzaj i częstotliwość subksrypcji", + "subscriptions.modal.close": "Zamknij", + "subscriptions.modal.delete-info": "Aby usunąć tę subksrypcję przejdź do strony 'Subskrypcje', która znajduje się w profilu użytkownika", + "subscriptions.modal.new-subscription-form.type.content": "Zawartość", + "subscriptions.modal.new-subscription-form.frequency.D": "Codziennie", + "subscriptions.modal.new-subscription-form.frequency.W": "Co tydzień", + "subscriptions.modal.new-subscription-form.frequency.M": "Co miesiąc", + "subscriptions.modal.new-subscription-form.submit": "Zapisz", + "subscriptions.modal.new-subscription-form.processing": "Ładowanie...", + "subscriptions.modal.create.success": "Zasubskrybowano {{ type }}", + "subscriptions.modal.delete.success": "Subskrypcja została anulowana", + "subscriptions.modal.update.success": "Twoja subskrypcja {{ type }} została zaktualizowana", + "subscriptions.modal.create.error": "Wystąpił bład podczas tworzenia subskrypcji", + "subscriptions.modal.delete.error": "Wystąpił bład podczas usuwania subskrypcji", + "subscriptions.modal.update.error": "Wystąpił bład podczas aktualizacji subskrypcji", + "subscriptions.table.dso": "Słowo kluczowe", + "subscriptions.table.subscription_type": "Typ subskrypcji", + "subscriptions.table.subscription_frequency": "Częstotliwość subskrypcji", + "subscriptions.table.action": "Akcja", + "subscriptions.table.edit": "Edytuj", + "subscriptions.table.delete": "Usuń", + "subscriptions.table.not-available": "Niedostępne", + "subscriptions.table.not-available-message": "Ta pozycja została usunięta lun nie masz do niej dostępu, aby ją wyswietlić", + "subscriptions.table.empty.message": "Ta pozycja nie ma w tym momencie żadnych subksrypcji. Aby zasubkrybować i otrzymywać aktualizacje o tym zbiorze lub kolekcji, wybierz przycisk subskrypcji na stronie pozycji.", + "vocabulary-treeview.info": "Wybierz słowo kluczowe, aby dodać je do filtra", + "supervisedWorkspace.search.results.head": "Pozycje recenzowane", + "supervision.search.results.head": "Status zadań: Szkic i redakcja", + "workspace-item.delete.breadcrumbs": "Usunięto wersję roboczą", + "workspace-item.delete.header": "Usuń wersję roboczą", + "workspace-item.delete.button.confirm": "Usuń", + "workspace-item.delete.button.cancel": "Anuluj", + "workspace-item.delete.notification.success.title": "Usunięto", + "workspace-item.delete.title": "Wersja robocza została usunieta", + "workspace-item.delete.notification.error.title": "Coś poszło nie tak", + "workspace-item.delete.notification.error.content": "Wersja robocza nie może zostać usunieta", + "workflow-item.advanced.title": "Zaawansowane workflow", + "workflow-item.selectrevieweraction.notification.success.title": "Wybrany recenzent", + "workflow-item.selectrevieweraction.notification.success.content": "Recenzent został przypisany", + "workflow-item.selectrevieweraction.notification.error.title": "Coś poszło nie tak", + "workflow-item.selectrevieweraction.notification.error.content": "Nie udało się wybrać recenzenta dla pozycji", + "workflow-item.selectrevieweraction.title": "Wybierz recenzenta", + "workflow-item.selectrevieweraction.header": "Wybierz recenzenta", + "workflow-item.selectrevieweraction.button.cancel": "Anuluj", + "workflow-item.selectrevieweraction.button.confirm": "Zatwierdź", + "workflow-item.scorereviewaction.notification.success.title": "Ocena recenzji", + "workflow-item.scorereviewaction.notification.success.content": "Ocena tej pozycji została zapisana", + "workflow-item.scorereviewaction.notification.error.title": "Coś poszło nie tak", + "workflow-item.scorereviewaction.notification.error.content": "Nie można ocenić tej pozycji", + "workflow-item.scorereviewaction.title": "Oceń pozycję", + "workflow-item.scorereviewaction.header": "Oceń pozycję", + "workflow-item.scorereviewaction.button.cancel": "Anuluj", + "workflow-item.scorereviewaction.button.confirm": "Potwierdź", + "listable-notification-object.default-message": "Ta pozycja nie może być odzyskana", + "system-wide-alert-banner.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert-banner.countdown.prefix": "W", + "system-wide-alert-banner.countdown.days": "{{days}} dni,", + "system-wide-alert-banner.countdown.hours": "{{hours}} godziny", + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minut:", + "menu.section.system-wide-alert": "Alert systemowy", + "system-wide-alert.form.header": "Alert systemowy", + "system-wide-alert-form.retrieval.error": "Coś poszło nie tak podczas odzyskiwania alertu systemowego", + "system-wide-alert.form.cancel": "Anuluj", + "system-wide-alert.form.save": "Zapisz", + "system-wide-alert.form.label.active": "AKTYWNE", + "system-wide-alert.form.label.inactive": "NIEAKTYWNE", + "system-wide-alert.form.error.message": "Alert systemowy musi zawierać wiadomość", + "system-wide-alert.form.label.message": "Alert systemowy", + "system-wide-alert.form.label.countdownTo.enable": "Wprowadź licznik czasowy", + "system-wide-alert.form.label.countdownTo.hint": "Wskazówka: Wpisz wartość licznika czasu. Kiedy licznik jest włączony, alert systemowy zostanie wyświetlony o wybranym czasie. Kiedy odliczanie zostanie zakończone, alert systemowy zostanie wyłączony. Serwer NIE zostanie zatrzymany automatycznie.", + "system-wide-alert.form.label.preview": "Podgląd alertu systemowego", + "system-wide-alert.form.update.success": "Alert systemowy został zaktualizowany", + "system-wide-alert.form.update.error": "Coś poszło nie tak podczas aktualizacji alertu systemowego", + "system-wide-alert.form.create.success": "Alert systemowy został utworzony", + "system-wide-alert.form.create.error": "Coś poszło nie tak podczas tworzenia alertu systemowego", + "admin.system-wide-alert.breadcrumbs": "Alerty systemowe", + "admin.system-wide-alert.title": "Alerty systemowe", + "item-access-control-title": "Ta strona pozwala na zmianę dostępów metadanych pozycji i plików do nich dołączonych.", + "collection-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w tej kolekcji. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "community-access-control-title": "Ta strona pozwala na zmianę warunków dostępu dla wszystkich pozycji w każdej kolekcji w tym zbiorze. Zmiany mogą być wykonywane zarówno na metadanych pozycji jak i plikach do nich dołączonych.", + "access-control-item-header-toggle": "Metadane pozycji", + "access-control-bitstream-header-toggle": "Pliki", + "access-control-mode": "Tryb", + "access-control-access-conditions": "Warunki dostępu", + "access-control-no-access-conditions-warning-message": "W tym momencie żadne warunki dostępu nie zostały określone. Jeśli zadanie zostanie rozpoczęte, obecne warunki dostępu zostaną zastąpione domyślnymi warunkami dostępu z nadrzędnej kolekcji.", + "access-control-replace-all": "Zastąp warunki dostępu", + "access-control-add-to-existing": "Dodaj do już istniejących", + "access-control-limit-to-specific": "Ogranicz zmiany do wybranych plików", + "access-control-process-all-bitstreams": "Zaktualizuj wszystkie pliki dla tej pozycji", + "access-control-bitstreams-selected": "wybrane pliki", + "access-control-cancel": "Anuluj", + "access-control-execute": "Wykonaj", + "access-control-add-more": "Dodaj więcej", + "access-control-select-bitstreams-modal.title": "Wybierz pliki", + "access-control-select-bitstreams-modal.no-items": "Brak pozycji do wyświetlenia.", + "access-control-select-bitstreams-modal.close": "Zamknij", + "access-control-option-label": "Typ warunków dostępu", + "access-control-option-note": "Wybierz warunki dostępu, które chcesz przypisać do zaznaczonych pozycji.", + "access-control-option-start-date": "Dostęp od", + "access-control-option-start-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", + "access-control-option-end-date": "Dostęp do", + "access-control-option-end-date-note": "Wybierz datę, kiedy wybrane warunki dostępu mają obowiązywać", } From 6709c3bb5ffe4f4c056debb1295ce499a6ea6932 Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" <mwood@iu.edu> Date: Tue, 22 Aug 2023 14:38:04 -0400 Subject: [PATCH 103/282] Graceful shutdown on SIGINT (e.g. from 'pm2 stop'). --- package.json | 1 + server.ts | 23 +++++++++-- yarn.lock | 107 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 977a4bdc5ec..beb40f0991d 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "fast-json-patch": "^3.1.1", "filesize": "^6.1.0", "http-proxy-middleware": "^1.0.5", + "http-terminator": "^3.2.0", "isbot": "^3.6.10", "js-cookie": "2.2.1", "js-yaml": "^4.1.0", diff --git a/server.ts b/server.ts index 23327c2058e..fbe2e4ea6d5 100644 --- a/server.ts +++ b/server.ts @@ -32,6 +32,7 @@ import isbot from 'isbot'; import { createCertificate } from 'pem'; import { createServer } from 'https'; import { json } from 'body-parser'; +import { createHttpTerminator } from 'http-terminator'; import { readFileSync } from 'fs'; import { join } from 'path'; @@ -487,7 +488,7 @@ function saveToCache(req, page: any) { */ function hasNotSucceeded(statusCode) { const rgx = new RegExp(/^20+/); - return !rgx.test(statusCode) + return !rgx.test(statusCode); } function retrieveHeaders(response) { @@ -525,12 +526,20 @@ function serverStarted() { * @param keys SSL credentials */ function createHttpsServer(keys) { - createServer({ + const listener = createServer({ key: keys.serviceKey, cert: keys.certificate }, app).listen(environment.ui.port, environment.ui.host, () => { serverStarted(); }); + + // Graceful shutdown when signalled + const terminator = createHttpTerminator({server: listener}); + process.on('SIGINT', ()=> { + console.debug('Closing HTTPS server on signal'); + terminator.terminate().catch(e => { console.error(e); }); + console.debug('HTTPS server closed'); + }); } function run() { @@ -539,9 +548,17 @@ function run() { // Start up the Node server const server = app(); - server.listen(port, host, () => { + const listener = server.listen(port, host, () => { serverStarted(); }); + + // Graceful shutdown when signalled + const terminator = createHttpTerminator({server: listener}); + process.on('SIGINT', ()=> { + console.debug('Closing HTTP server on signal'); + terminator.terminate().catch(e => { console.error(e); }); + console.debug('HTTP server closed.'); + }); } function start() { diff --git a/yarn.lock b/yarn.lock index e53a070d167..7d888f015a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1761,6 +1761,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b" integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng== +"@fastify/deepmerge@^1.0.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@fastify/deepmerge/-/deepmerge-1.3.0.tgz#8116858108f0c7d9fd460d05a7d637a13fe3239a" + integrity sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A== + "@fortawesome/fontawesome-free@^6.4.0": version "6.4.0" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz#1ee0c174e472c84b23cb46c995154dc383e3b4fe" @@ -3061,9 +3066,9 @@ ajv-keywords@^5.0.0: dependencies: fast-deep-equal "^3.1.3" -ajv@8.12.0, ajv@^8.8.0: +ajv@8.12.0, ajv@^8.10.0, ajv@^8.8.0: version "8.12.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== dependencies: fast-deep-equal "^3.1.1" @@ -3538,6 +3543,11 @@ boolbase@^1.0.0: resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== +boolean@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" + integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== + bootstrap@^4.6.1: version "4.6.2" resolved "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz" @@ -4641,6 +4651,11 @@ del@^2.2.0: pinkie-promise "^2.0.0" rimraf "^2.2.8" +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" @@ -5579,6 +5594,18 @@ fast-json-stable-stringify@2.1.0, fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-json-stringify@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-5.8.0.tgz#b229ed01ac5f92f3b82001a916c31324652f46d7" + integrity sha512-VVwK8CFMSALIvt14U8AvrSzQAwN/0vaVRiFFUVlpnXSnDGrSkOAO5MtzyN8oQNjLd5AqTW5OZRgyjoNuAuR3jQ== + dependencies: + "@fastify/deepmerge" "^1.0.0" + ajv "^8.10.0" + ajv-formats "^2.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^2.1.0" + rfdc "^1.2.0" + fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" @@ -5589,6 +5616,18 @@ fast-memoize@^2.5.1: resolved "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz" integrity sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw== +fast-printf@^1.6.9: + version "1.6.9" + resolved "https://registry.yarnpkg.com/fast-printf/-/fast-printf-1.6.9.tgz#212f56570d2dc8ccdd057ee93d50dd414d07d676" + integrity sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg== + dependencies: + boolean "^3.1.4" + +fast-uri@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-2.2.0.tgz#519a0f849bef714aad10e9753d69d8f758f7445a" + integrity sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg== + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz" @@ -6021,9 +6060,9 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: +globalthis@^1.0.2, globalthis@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== dependencies: define-properties "^1.1.3" @@ -6372,6 +6411,16 @@ http-signature@~1.3.6: jsprim "^2.0.2" sshpk "^1.14.1" +http-terminator@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/http-terminator/-/http-terminator-3.2.0.tgz#bc158d2694b733ca4fbf22a35065a81a609fb3e9" + integrity sha512-JLjck1EzPaWjsmIf8bziM3p9fgR1Y3JoUKAkyYEbZmFrIvJM6I8vVJfBGWlEtV9IWOvzNnaTtjuwZeBY2kwB4g== + dependencies: + delay "^5.0.0" + p-wait-for "^3.2.0" + roarr "^7.0.4" + type-fest "^2.3.3" + https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" @@ -8609,6 +8658,11 @@ ospath@^1.2.2: resolved "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz" integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" @@ -8652,11 +8706,25 @@ p-retry@^4.5.0: "@types/retry" "0.12.0" retry "^0.13.1" +p-timeout@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +p-wait-for@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-wait-for/-/p-wait-for-3.2.0.tgz#640429bcabf3b0dd9f492c31539c5718cb6a3f1f" + integrity sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA== + dependencies: + p-timeout "^3.0.0" + pacote@15.1.0: version "15.1.0" resolved "https://registry.npmjs.org/pacote/-/pacote-15.1.0.tgz" @@ -9894,9 +9962,9 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rfdc@^1.3.0: +rfdc@^1.2.0, rfdc@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.6.3: @@ -9913,6 +9981,18 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +roarr@^7.0.4: + version "7.15.1" + resolved "https://registry.yarnpkg.com/roarr/-/roarr-7.15.1.tgz#e4d93105c37b5ea7dd1200d96a3500f757ddc39f" + integrity sha512-0ExL9rjOXeQPvQvQo8IcV8SR2GTXmDr1FQFlY2HiAV+gdVQjaVZNOx9d4FI2RqFFsd0sNsiw2TRS/8RU9g0ZfA== + dependencies: + boolean "^3.1.4" + fast-json-stringify "^5.8.0" + fast-printf "^1.6.9" + globalthis "^1.0.2" + safe-stable-stringify "^2.4.3" + semver-compare "^1.0.0" + rtl-css-js@^1.13.1: version "1.16.1" resolved "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz" @@ -9995,6 +10075,11 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +safe-stable-stringify@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" @@ -10114,6 +10199,11 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== + semver@7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" @@ -11058,6 +11148,11 @@ type-fest@^0.21.3: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^2.3.3: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" From 4449737aed9b96c13ba6a34e2ff72feb1aaebe92 Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" <mwood@iu.edu> Date: Tue, 22 Aug 2023 15:46:55 -0400 Subject: [PATCH 104/282] Properly await termination. --- server.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/server.ts b/server.ts index fbe2e4ea6d5..47284175a4d 100644 --- a/server.ts +++ b/server.ts @@ -535,10 +535,12 @@ function createHttpsServer(keys) { // Graceful shutdown when signalled const terminator = createHttpTerminator({server: listener}); - process.on('SIGINT', ()=> { - console.debug('Closing HTTPS server on signal'); - terminator.terminate().catch(e => { console.error(e); }); - console.debug('HTTPS server closed'); + process.on('SIGINT', () => { + void (async ()=> { + console.debug('Closing HTTPS server on signal'); + await terminator.terminate().catch(e => { console.error(e); }); + console.debug('HTTPS server closed'); + })(); }); } @@ -554,10 +556,12 @@ function run() { // Graceful shutdown when signalled const terminator = createHttpTerminator({server: listener}); - process.on('SIGINT', ()=> { - console.debug('Closing HTTP server on signal'); - terminator.terminate().catch(e => { console.error(e); }); - console.debug('HTTP server closed.'); + process.on('SIGINT', () => { + void (async () => { + console.debug('Closing HTTP server on signal'); + await terminator.terminate().catch(e => { console.error(e); }); + console.debug('HTTP server closed.');return undefined; + })(); }); } From bf9b2b82e1d1d6cd7a901b674d8df92af073794c Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" <mwood@iu.edu> Date: Tue, 22 Aug 2023 17:07:20 -0400 Subject: [PATCH 105/282] Document a modified method as required by PR guidelines. --- server.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server.ts b/server.ts index 47284175a4d..4d2ee500bee 100644 --- a/server.ts +++ b/server.ts @@ -544,6 +544,9 @@ function createHttpsServer(keys) { }); } +/** + * Create an HTTP server with the configured port and host. + */ function run() { const port = environment.ui.port || 4000; const host = environment.ui.host || '/'; From b51fd465361c4317fc97990aff7a6b34bd79bf61 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 22 Aug 2023 16:32:55 -0500 Subject: [PATCH 106/282] Replace mentions of demo7.dspace.org and api7.dspace.org with demo or sandbox --- README.md | 6 +++--- config/config.example.yml | 2 +- config/config.yml | 2 +- docker/README.md | 4 ++-- docker/docker-compose-dist.yml | 2 +- docs/Configuration.md | 4 ++-- src/app/core/services/browser-hard-redirect.service.ts | 4 ++-- src/app/core/services/hard-redirect.service.ts | 4 ++-- src/app/core/services/server-hard-redirect.service.ts | 4 ++-- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 689c64a2925..ebc24f8b918 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,8 @@ DSPACE_UI_SSL => DSPACE_SSL The same settings can also be overwritten by setting system environment variables instead, E.g.: ```bash -export DSPACE_HOST=api7.dspace.org -export DSPACE_UI_PORT=4200 +export DSPACE_HOST=demo.dspace.org +export DSPACE_UI_PORT=4000 ``` The priority works as follows: **environment variable** overrides **variable in `.env` file** overrides external config set by `DSPACE_APP_CONFIG_PATH` overrides **`config.(prod or dev).yml`** @@ -288,7 +288,7 @@ E2E tests (aka integration tests) use [Cypress.io](https://www.cypress.io/). Con The test files can be found in the `./cypress/integration/` folder. Before you can run e2e tests, two things are REQUIRED: -1. You MUST be running the DSpace backend (i.e. REST API) locally. The e2e tests will *NOT* succeed if run against our demo REST API (https://api7.dspace.org/server/), as that server is uncontrolled and may have content added/removed at any time. +1. You MUST be running the DSpace backend (i.e. REST API) locally. The e2e tests will *NOT* succeed if run against our demo/sandbox REST API (https://demo.dspace.org/server/ or https://sandbox.dspace.org/server/), as those sites may have content added/removed at any time. * After starting up your backend on localhost, make sure either your `config.prod.yml` or `config.dev.yml` has its `rest` settings defined to use that localhost backend. * If you'd prefer, you may instead use environment variables as described at [Configuring](#configuring). For example: ``` diff --git a/config/config.example.yml b/config/config.example.yml index ea38303fa36..b7ea190c556 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -22,7 +22,7 @@ ui: # 'synced' with the 'dspace.server.url' setting in your backend's local.cfg. rest: ssl: true - host: api7.dspace.org + host: sandbox.dspace.org port: 443 # NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript nameSpace: /server diff --git a/config/config.yml b/config/config.yml index b5eecd112f0..109db60ca92 100644 --- a/config/config.yml +++ b/config/config.yml @@ -1,5 +1,5 @@ rest: ssl: true - host: api7.dspace.org + host: sandbox.dspace.org port: 443 nameSpace: /server diff --git a/docker/README.md b/docker/README.md index 08801137b07..d0cee3f52a5 100644 --- a/docker/README.md +++ b/docker/README.md @@ -101,8 +101,8 @@ and the backend at http://localhost:8080/server/ ## Run DSpace Angular dist build with DSpace Demo site backend -This allows you to run the Angular UI in *production* mode, pointing it at the demo backend -(https://api7.dspace.org/server/). +This allows you to run the Angular UI in *production* mode, pointing it at the demo or sandbox backend +(https://demo.dspace.org/server/ or https://sandbox.dspace.org/server/). ``` docker-compose -f docker/docker-compose-dist.yml pull diff --git a/docker/docker-compose-dist.yml b/docker/docker-compose-dist.yml index a9ee4a2656c..38278085cd0 100644 --- a/docker/docker-compose-dist.yml +++ b/docker/docker-compose-dist.yml @@ -24,7 +24,7 @@ services: # This is because Server Side Rendering (SSR) currently requires a public URL, # see this bug: https://github.com/DSpace/dspace-angular/issues/1485 DSPACE_REST_SSL: 'true' - DSPACE_REST_HOST: api7.dspace.org + DSPACE_REST_HOST: sandbox.dspace.org DSPACE_REST_PORT: 443 DSPACE_REST_NAMESPACE: /server image: dspace/dspace-angular:${DSPACE_VER:-latest}-dist diff --git a/docs/Configuration.md b/docs/Configuration.md index 62fa444cc0f..01fd83c94d1 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -48,7 +48,7 @@ dspace-angular connects to your DSpace installation by using its REST endpoint. ```yaml rest: ssl: true - host: api7.dspace.org + host: demo.dspace.org port: 443 nameSpace: /server } @@ -57,7 +57,7 @@ rest: Alternately you can set the following environment variables. If any of these are set, it will override all configuration files: ``` DSPACE_REST_SSL=true - DSPACE_REST_HOST=api7.dspace.org + DSPACE_REST_HOST=demo.dspace.org DSPACE_REST_PORT=443 DSPACE_REST_NAMESPACE=/server ``` diff --git a/src/app/core/services/browser-hard-redirect.service.ts b/src/app/core/services/browser-hard-redirect.service.ts index 4ef9548899d..827e83f0b7d 100644 --- a/src/app/core/services/browser-hard-redirect.service.ts +++ b/src/app/core/services/browser-hard-redirect.service.ts @@ -38,8 +38,8 @@ export class BrowserHardRedirectService extends HardRedirectService { /** * Get the origin of the current URL * i.e. <scheme> "://" <hostname> [ ":" <port> ] - * e.g. if the URL is https://demo7.dspace.org/search?query=test, - * the origin would be https://demo7.dspace.org + * e.g. if the URL is https://demo.dspace.org/search?query=test, + * the origin would be https://demo.dspace.org */ getCurrentOrigin(): string { return this.location.origin; diff --git a/src/app/core/services/hard-redirect.service.ts b/src/app/core/services/hard-redirect.service.ts index 826c7e4fa98..e6104cefb9c 100644 --- a/src/app/core/services/hard-redirect.service.ts +++ b/src/app/core/services/hard-redirect.service.ts @@ -25,8 +25,8 @@ export abstract class HardRedirectService { /** * Get the origin of the current URL * i.e. <scheme> "://" <hostname> [ ":" <port> ] - * e.g. if the URL is https://demo7.dspace.org/search?query=test, - * the origin would be https://demo7.dspace.org + * e.g. if the URL is https://demo.dspace.org/search?query=test, + * the origin would be https://demo.dspace.org */ abstract getCurrentOrigin(): string; } diff --git a/src/app/core/services/server-hard-redirect.service.ts b/src/app/core/services/server-hard-redirect.service.ts index 8c45cc864b5..d71318d7b8e 100644 --- a/src/app/core/services/server-hard-redirect.service.ts +++ b/src/app/core/services/server-hard-redirect.service.ts @@ -69,8 +69,8 @@ export class ServerHardRedirectService extends HardRedirectService { /** * Get the origin of the current URL * i.e. <scheme> "://" <hostname> [ ":" <port> ] - * e.g. if the URL is https://demo7.dspace.org/search?query=test, - * the origin would be https://demo7.dspace.org + * e.g. if the URL is https://demo.dspace.org/search?query=test, + * the origin would be https://demo.dspace.org */ getCurrentOrigin(): string { return this.req.protocol + '://' + this.req.headers.host; From 596006de82b3918f2aa8e56e8fb18b250a06d0cd Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 23 Aug 2023 17:05:42 -0500 Subject: [PATCH 107/282] Enable new skip merge commit feature --- .github/workflows/port_merged_pull_request.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml index 50faf3f8867..109835d14d3 100644 --- a/.github/workflows/port_merged_pull_request.yml +++ b/.github/workflows/port_merged_pull_request.yml @@ -39,6 +39,8 @@ jobs: # Copy all labels from original PR to (newly created) port PR # NOTE: The labels matching 'label_pattern' are automatically excluded copy_labels_pattern: '.*' + # Skip any merge commits in the ported PR. This means only non-merge commits are cherry-picked to the new PR + merge_commits: 'skip' # Use a personal access token (PAT) to create PR as 'dspace-bot' user. # A PAT is required in order for the new PR to trigger its own actions (for CI checks) github_token: ${{ secrets.PR_PORT_TOKEN }} \ No newline at end of file From 9e46b5310b5038fb3433db2bdd829d48c8107a70 Mon Sep 17 00:00:00 2001 From: Alan Orth <alan.orth@gmail.com> Date: Thu, 24 Aug 2023 15:01:37 +0300 Subject: [PATCH 108/282] config/config.example.yml: fix example syntax As of DSpace Angular 7.2 the syntax has changed from TypeScript to YAML. --- config/config.example.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index b7ea190c556..d2734bd28e1 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -292,33 +292,33 @@ themes: # # # A theme with a handle property will match the community, collection or item with the given # # handle, and all collections and/or items within it - # - name: 'custom', - # handle: '10673/1233' + # - name: custom + # handle: 10673/1233 # # # A theme with a regex property will match the route using a regular expression. If it # # matches the route for a community or collection it will also apply to all collections # # and/or items within it - # - name: 'custom', - # regex: 'collections\/e8043bc2.*' + # - name: custom + # regex: collections\/e8043bc2.* # # # A theme with a uuid property will match the community, collection or item with the given # # ID, and all collections and/or items within it - # - name: 'custom', - # uuid: '0958c910-2037-42a9-81c7-dca80e3892b4' + # - name: custom + # uuid: 0958c910-2037-42a9-81c7-dca80e3892b4 # # # The extends property specifies an ancestor theme (by name). Whenever a themed component is not found # # in the current theme, its ancestor theme(s) will be checked recursively before falling back to default. - # - name: 'custom-A', - # extends: 'custom-B', + # - name: custom-A + # extends: custom-B # # Any of the matching properties above can be used - # handle: '10673/34' + # handle: 10673/34 # - # - name: 'custom-B', - # extends: 'custom', - # handle: '10673/12' + # - name: custom-B + # extends: custom + # handle: 10673/12 # # # A theme with only a name will match every route - # name: 'custom' + # name: custom # # # This theme will use the default bootstrap styling for DSpace components # - name: BASE_THEME_NAME From 88a7088b47a09c9927a869ebf67e9c174dd1f713 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 25 Aug 2023 13:18:10 -0600 Subject: [PATCH 109/282] =?UTF-8?q?=F0=9F=90=9B=20go=20to=20first=20page?= =?UTF-8?q?=20after=20submit=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/shared/search-form/search-form.component.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts index 151ded6f9e9..95a063bdd67 100644 --- a/src/app/shared/search-form/search-form.component.ts +++ b/src/app/shared/search-form/search-form.component.ts @@ -114,7 +114,14 @@ export class SearchFormComponent implements OnChanges { * @param data Updated parameters */ updateSearch(data: any) { - const queryParams = Object.assign({}, data); + const goToFirstPage = { 'spc.page': 1 }; + + const queryParams = Object.assign( + { + ...goToFirstPage + }, + data + ); void this.router.navigate(this.getSearchLinkParts(), { queryParams: queryParams, From 044230209c3c0d817da9628802b8ef6d0b6aab86 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 25 Aug 2023 13:20:37 -0600 Subject: [PATCH 110/282] =?UTF-8?q?=E2=9C=85=20add=20first=20page=20condit?= =?UTF-8?q?ion=20when=20search=20submit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search-form/search-form.component.spec.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/shared/search-form/search-form.component.spec.ts b/src/app/shared/search-form/search-form.component.spec.ts index 584b7c5584c..1fe1ea83160 100644 --- a/src/app/shared/search-form/search-form.component.spec.ts +++ b/src/app/shared/search-form/search-form.component.spec.ts @@ -28,6 +28,7 @@ describe('SearchFormComponent', () => { const searchService = new SearchServiceStub(); const paginationService = new PaginationServiceStub(); const searchConfigService = { paginationID: 'test-id' }; + const firstPage = { 'spc.page': 1 }; const dspaceObjectService = { findById: () => createSuccessfulRemoteDataObject$(undefined), }; @@ -104,16 +105,16 @@ describe('SearchFormComponent', () => { const scope = 'MCU'; let searchQuery = {}; - it('should navigate to the search page even when no parameters are provided', () => { + it('should navigate to the search first page even when no parameters are provided', () => { comp.updateSearch(searchQuery); expect(router.navigate).toHaveBeenCalledWith(comp.getSearchLinkParts(), { - queryParams: searchQuery, + queryParams: { ...searchQuery, ...firstPage }, queryParamsHandling: 'merge' }); }); - it('should navigate to the search page with parameters only query if only query is provided', () => { + it('should navigate to the search first page with parameters only query if only query is provided', () => { searchQuery = { query: query }; @@ -121,12 +122,12 @@ describe('SearchFormComponent', () => { comp.updateSearch(searchQuery); expect(router.navigate).toHaveBeenCalledWith(comp.getSearchLinkParts(), { - queryParams: searchQuery, + queryParams: { ...searchQuery, ...firstPage }, queryParamsHandling: 'merge' }); }); - it('should navigate to the search page with parameters only query if only scope is provided', () => { + it('should navigate to the search first page with parameters only query if only scope is provided', () => { searchQuery = { scope: scope }; @@ -134,7 +135,7 @@ describe('SearchFormComponent', () => { comp.updateSearch(searchQuery); expect(router.navigate).toHaveBeenCalledWith(comp.getSearchLinkParts(), { - queryParams: searchQuery, + queryParams: {...searchQuery, ...firstPage}, queryParamsHandling: 'merge' }); }); From 68a3323fcaf9b97d260f5032c9eb2fa5f6096bc2 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Mon, 28 Aug 2023 13:53:19 -0500 Subject: [PATCH 111/282] Update to latest cypress --- package.json | 2 +- yarn.lock | 49 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 977a4bdc5ec..f5335d7e239 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "compression-webpack-plugin": "^9.2.0", "copy-webpack-plugin": "^6.4.1", "cross-env": "^7.0.3", - "cypress": "12.10.0", + "cypress": "12.17.4", "cypress-axe": "^1.4.0", "deep-freeze": "0.0.1", "eslint": "^8.39.0", diff --git a/yarn.lock b/yarn.lock index e53a070d167..a7c8af6c043 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1551,10 +1551,10 @@ resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz" integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== -"@cypress/request@^2.88.10": - version "2.88.11" - resolved "https://registry.npmjs.org/@cypress/request/-/request-2.88.11.tgz" - integrity sha512-M83/wfQ1EkspjkE2lNWNV5ui2Cv7UCv1swW1DqljahbzLVWltcsexQh8jYtuS/vzFXP+HySntGM83ZXA9fn17w== +"@cypress/request@2.88.12": + version "2.88.12" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.12.tgz#ba4911431738494a85e93fb04498cb38bc55d590" + integrity sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -1571,7 +1571,7 @@ performance-now "^2.1.0" qs "~6.10.3" safe-buffer "^5.1.2" - tough-cookie "~2.5.0" + tough-cookie "^4.1.3" tunnel-agent "^0.6.0" uuid "^8.3.2" @@ -2457,11 +2457,16 @@ resolved "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz" integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== -"@types/node@*", "@types/node@>=10.0.0", "@types/node@^14.14.31", "@types/node@^14.14.9": +"@types/node@*", "@types/node@>=10.0.0", "@types/node@^14.14.9": version "14.18.42" resolved "https://registry.npmjs.org/@types/node/-/node-14.18.42.tgz" integrity sha512-xefu+RBie4xWlK8hwAzGh3npDz/4VhF6icY/shU+zv/1fNn+ZVG7T7CRwe9LId9sAYRPxI+59QBPuKL3WpyGRg== +"@types/node@^16.18.39": + version "16.18.46" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.46.tgz#9f2102d0ba74a318fcbe170cbff5463f119eab59" + integrity sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" @@ -4437,14 +4442,14 @@ cypress-axe@^1.4.0: resolved "https://registry.yarnpkg.com/cypress-axe/-/cypress-axe-1.4.0.tgz#e67482bfe9e740796bf77c7823f19781a8a2faff" integrity sha512-Ut7NKfzjyKm0BEbt2WxuKtLkIXmx6FD2j0RwdvO/Ykl7GmB/qRQkwbKLk3VP35+83hiIr8GKD04PDdrTK5BnyA== -cypress@12.10.0: - version "12.10.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.10.0.tgz#b6264f77c214d63530ebac2b33c4d099bd40b715" - integrity sha512-Y0wPc221xKKW1/4iAFCphkrG2jNR4MjOne3iGn4mcuCaE7Y5EtXL83N8BzRsAht7GYfWVjJ/UeTqEdDKHz39HQ== +cypress@12.17.4: + version "12.17.4" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.17.4.tgz#b4dadf41673058493fa0d2362faa3da1f6ae2e6c" + integrity sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ== dependencies: - "@cypress/request" "^2.88.10" + "@cypress/request" "2.88.12" "@cypress/xvfb" "^1.2.4" - "@types/node" "^14.14.31" + "@types/node" "^16.18.39" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" arch "^2.2.0" @@ -4477,9 +4482,10 @@ cypress@12.10.0: minimist "^1.2.8" ospath "^1.2.2" pretty-bytes "^5.6.0" + process "^0.11.10" proxy-from-env "1.0.0" request-progress "^3.0.0" - semver "^7.3.2" + semver "^7.5.3" supports-color "^8.1.1" tmp "~0.2.1" untildify "^4.0.0" @@ -9267,6 +9273,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz" @@ -10131,7 +10142,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: +semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -10912,6 +10923,16 @@ tough-cookie@^4.0.0, tough-cookie@^4.1.2: universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" From 50899f1d1b16e322e323507ad7dd42e5173cfbe5 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Mon, 28 Aug 2023 13:55:05 -0500 Subject: [PATCH 112/282] Update to latest axe-core --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f5335d7e239..707e9f0edf2 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,7 @@ "@types/sanitize-html": "^2.9.0", "@typescript-eslint/eslint-plugin": "^5.59.1", "@typescript-eslint/parser": "^5.59.1", - "axe-core": "^4.7.0", + "axe-core": "^4.7.2", "compression-webpack-plugin": "^9.2.0", "copy-webpack-plugin": "^6.4.1", "cross-env": "^7.0.3", diff --git a/yarn.lock b/yarn.lock index a7c8af6c043..58ddfaca4b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3363,10 +3363,10 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axe-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" - integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== +axe-core@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" + integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== axios@0.21.4: version "0.21.4" From 158ebb0e3268a314e18bc4855457166d8b57f2e8 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 11:41:03 -0500 Subject: [PATCH 113/282] Reenable accessibility check fixed in #2251 --- cypress/e2e/community-list.cy.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cypress/e2e/community-list.cy.ts b/cypress/e2e/community-list.cy.ts index 7b60b59dbc9..d91260eca1f 100644 --- a/cypress/e2e/community-list.cy.ts +++ b/cypress/e2e/community-list.cy.ts @@ -13,13 +13,6 @@ describe('Community List Page', () => { cy.get('[data-test="expand-button"]').click({ multiple: true }); // Analyze <ds-community-list-page> for accessibility issues - // Disable heading-order checks until it is fixed - testA11y('ds-community-list-page', - { - rules: { - 'heading-order': { enabled: false } - } - } as Options - ); + testA11y('ds-community-list-page'); }); }); From 339ed63734d4192fb37a12e67b0395aa1669acdb Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 11:43:36 -0500 Subject: [PATCH 114/282] Enable excessibility checking of login menu, and remove unnecessary exclusion from header --- cypress/e2e/header.cy.ts | 3 +-- cypress/e2e/login-modal.cy.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/header.cy.ts b/cypress/e2e/header.cy.ts index 236208db686..1a9b841eb7d 100644 --- a/cypress/e2e/header.cy.ts +++ b/cypress/e2e/header.cy.ts @@ -11,8 +11,7 @@ describe('Header', () => { testA11y({ include: ['ds-header'], exclude: [ - ['#search-navbar-container'], // search in navbar has duplicative ID. Will be fixed in #1174 - ['.dropdownLogin'] // "Log in" link has color contrast issues. Will be fixed in #1149 + ['#search-navbar-container'] // search in navbar has duplicative ID. Will be fixed in #1174 ], }); }); diff --git a/cypress/e2e/login-modal.cy.ts b/cypress/e2e/login-modal.cy.ts index b169634cfa0..d29c13c2f96 100644 --- a/cypress/e2e/login-modal.cy.ts +++ b/cypress/e2e/login-modal.cy.ts @@ -1,4 +1,5 @@ import { TEST_ADMIN_PASSWORD, TEST_ADMIN_USER, TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; +import { testA11y } from 'cypress/support/utils'; const page = { openLoginMenu() { @@ -123,4 +124,15 @@ describe('Login Modal', () => { cy.location('pathname').should('eq', '/forgot'); cy.get('ds-forgot-email').should('exist'); }); + + it('should pass accessibility tests', () => { + cy.visit('/'); + + page.openLoginMenu(); + + cy.get('ds-log-in').should('exist'); + + // Analyze <ds-log-in> for accessibility issues + testA11y('ds-log-in'); + }); }); From ba244bf6b14bfed06f1b1052cc6407f2537a175b Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 11:44:03 -0500 Subject: [PATCH 115/282] Fix heading order issue with item page & update accessibility tests to prove it now passes --- cypress/e2e/item-page.cy.ts | 20 ++++++++++--------- .../item-page-title-field.component.html | 4 ++-- .../metadata-field-wrapper.component.html | 2 +- .../metadata-field-wrapper.component.scss | 3 +++ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cypress/e2e/item-page.cy.ts b/cypress/e2e/item-page.cy.ts index 9eed711776e..9dba6eb8cea 100644 --- a/cypress/e2e/item-page.cy.ts +++ b/cypress/e2e/item-page.cy.ts @@ -1,4 +1,3 @@ -import { Options } from 'cypress-axe'; import { TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; @@ -19,13 +18,16 @@ describe('Item Page', () => { cy.get('ds-item-page').should('be.visible'); // Analyze <ds-item-page> for accessibility issues - // Disable heading-order checks until it is fixed - testA11y('ds-item-page', - { - rules: { - 'heading-order': { enabled: false } - } - } as Options - ); + testA11y('ds-item-page'); + }); + + it('should pass accessibility tests on full item page', () => { + cy.visit(ENTITYPAGE + '/full'); + + // <ds-full-item-page> tag must be loaded + cy.get('ds-full-item-page').should('be.visible'); + + // Analyze <ds-full-item-page> for accessibility issues + testA11y('ds-full-item-page'); }); }); diff --git a/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.html b/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.html index 15960bdc9d7..85975d45335 100644 --- a/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.html +++ b/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.html @@ -1,6 +1,6 @@ -<h2 class="item-page-title-field"> +<h1 class="item-page-title-field"> <div *ngIf="item.firstMetadataValue('dspace.entity.type') as type" class="d-inline"> {{ type.toLowerCase() + '.page.titleprefix' | translate }} </div> <span class="dont-break-out">{{ dsoNameService.getName(item) }}</span> -</h2> +</h1> diff --git a/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html index d69f87883bb..7748e385ca4 100644 --- a/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html +++ b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.html @@ -1,5 +1,5 @@ <div class="simple-view-element" [class.d-none]="hideIfNoTextContent && content.textContent.trim().length === 0"> - <h5 class="simple-view-element-header" *ngIf="label">{{ label }}</h5> + <h2 class="simple-view-element-header" *ngIf="label">{{ label }}</h2> <div #content class="simple-view-element-body"> <ng-content></ng-content> </div> diff --git a/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss index 75dfd09d0d9..bf17d63d6c6 100644 --- a/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss +++ b/src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component.scss @@ -2,4 +2,7 @@ .simple-view-element { margin-bottom: 15px; } + .simple-view-element-header { + font-size: 1.25rem; + } } From 91d8b7e4f7187b68f70c1cf2906f4e6e8d8af2b9 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 14:58:49 -0500 Subject: [PATCH 116/282] Update ng2-nouislider and nouislider to latest versions --- package.json | 4 ++-- src/styles/_vendor.scss | 2 +- yarn.lock | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 707e9f0edf2..31d1b7cf28e 100644 --- a/package.json +++ b/package.json @@ -116,12 +116,12 @@ "morgan": "^1.10.0", "ng-mocks": "^14.10.0", "ng2-file-upload": "1.4.0", - "ng2-nouislider": "^1.8.3", + "ng2-nouislider": "^2.0.0", "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", "ngx-ui-switch": "^14.0.3", - "nouislider": "^14.6.3", + "nouislider": "^15.7.1", "pem": "1.14.7", "prop-types": "^15.8.1", "react-copy-to-clipboard": "^5.1.0", diff --git a/src/styles/_vendor.scss b/src/styles/_vendor.scss index 9d9842b9b30..b2b94c28269 100644 --- a/src/styles/_vendor.scss +++ b/src/styles/_vendor.scss @@ -1,5 +1,5 @@ // node_modules imports meant for all the themes @import '~node_modules/bootstrap/scss/bootstrap.scss'; -@import '~node_modules/nouislider/distribute/nouislider.min'; +@import '~node_modules/nouislider/dist/nouislider.min'; @import '~node_modules/ngx-ui-switch/ui-switch.component.scss'; diff --git a/yarn.lock b/yarn.lock index 58ddfaca4b7..44625c4bd01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8197,10 +8197,12 @@ ng2-file-upload@1.4.0: dependencies: tslib "^1.9.0" -ng2-nouislider@^1.8.3: - version "1.8.3" - resolved "https://registry.npmjs.org/ng2-nouislider/-/ng2-nouislider-1.8.3.tgz" - integrity sha512-Vl8tHCcJ/ioJLAs2t6FBC35sZq1P/O5ZdqdFwYxOCOMVbILGWNg+2gWZIjFstvv9pqb/mVvVUYe6qGG/mA/RBQ== +ng2-nouislider@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-2.0.0.tgz#a62fd6cf3f1561be19a2691c2f68d21a46dc6006" + integrity sha512-NGbF/0w0+bZqclpSPFOlWIeVJaVwRRYFJzD1x8PClbw9GIeo7fCHoBzZ81y7K7FTJg6to+cgjSTFETPZG/Dizg== + dependencies: + tslib "^2.3.0" ngx-infinite-scroll@^15.0.0: version "15.0.0" @@ -8343,10 +8345,10 @@ normalize-url@^4.5.0: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== -nouislider@^14.6.3: - version "14.7.0" - resolved "https://registry.npmjs.org/nouislider/-/nouislider-14.7.0.tgz" - integrity sha512-4RtQ1+LHJKesDCNJrXkQcwXAWCrC2aggdLYMstS/G5fEWL+fXZbUA9pwVNHFghMGuFGRATlDLNInRaPeRKzpFQ== +nouislider@^15.7.1: + version "15.7.1" + resolved "https://registry.yarnpkg.com/nouislider/-/nouislider-15.7.1.tgz#77d55e47d9b4cd771728515713df43b489db9705" + integrity sha512-5N7C1ru/i8y3dg9+Z6ilj6+m1EfabvOoaRa7ztpxBSKKRZso4vA52DGSbBJjw5XLtFr/LZ9SgGAXqyVtlVHO5w== npm-bundled@^3.0.0: version "3.0.0" From 2a881791ba76091d2f85d0b068f926043ef33bc9 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 15:01:21 -0500 Subject: [PATCH 117/282] Fix accessibility of date sliders by adding aria-labels --- cypress/e2e/my-dspace.cy.ts | 6 +--- cypress/e2e/search-page.cy.ts | 6 +--- .../search-range-filter.component.html | 10 +++---- .../search-range-filter.component.ts | 29 +++++++++++++++++++ 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/cypress/e2e/my-dspace.cy.ts b/cypress/e2e/my-dspace.cy.ts index 79786c298a3..af4aab41f36 100644 --- a/cypress/e2e/my-dspace.cy.ts +++ b/cypress/e2e/my-dspace.cy.ts @@ -22,15 +22,11 @@ describe('My DSpace page', () => { testA11y( { include: ['ds-my-dspace-page'], - exclude: [ - ['nouislider'] // Date filter slider is missing ARIA labels. Will be fixed by #1175 - ], }, { rules: { - // Search filters fail these two "moderate" impact rules + // Search filters fail this "moderate" impact rules 'heading-order': { enabled: false }, - 'landmark-unique': { enabled: false } } } as Options ); diff --git a/cypress/e2e/search-page.cy.ts b/cypress/e2e/search-page.cy.ts index 24519cc236a..0d4f70ef037 100644 --- a/cypress/e2e/search-page.cy.ts +++ b/cypress/e2e/search-page.cy.ts @@ -30,15 +30,11 @@ describe('Search Page', () => { testA11y( { include: ['ds-search-page'], - exclude: [ - ['nouislider'] // Date filter slider is missing ARIA labels. Will be fixed by #1175 - ], }, { rules: { - // Search filters fail these two "moderate" impact rules + // Search filters fail this "moderate" impact rule 'heading-order': { enabled: false }, - 'landmark-unique': { enabled: false } } } as Options ); diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.html index 7834c4c5571..251e5ac420b 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.html @@ -9,8 +9,8 @@ </span> <input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'" class="form-control" (blur)="onSubmit()" - aria-label="Mininum value" - [placeholder]="'search.filters.filter.' + filterConfig.name + '.min.placeholder' | translate" + [attr.aria-label]="minLabel" + [placeholder]="minLabel" /> </label> </div> @@ -21,8 +21,8 @@ </span> <input type="text" [(ngModel)]="range[1]" [name]="filterConfig.paramName + '.max'" class="form-control" (blur)="onSubmit()" - aria-label="Maximum value" - [placeholder]="'search.filters.filter.' + filterConfig.name + '.max.placeholder' | translate" + [attr.aria-label]="maxLabel" + [placeholder]="maxLabel" /> </label> </div> @@ -33,7 +33,7 @@ </form> <ng-container *ngIf="shouldShowSlider()"> - <nouislider [connect]="true" [min]="min" [max]="max" [step]="1" + <nouislider [connect]="true" [config]="config" [min]="min" [max]="max" [step]="1" [dsDebounce]="250" (onDebounce)="onSubmit()" (keydown)="startKeyboardControl()" (keyup)="stopKeyboardControl()" [(ngModel)]="range" ngDefaultControl> diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 938f67412e4..ed20e63c52f 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -2,6 +2,7 @@ import { BehaviorSubject, combineLatest as observableCombineLatest, Subscription import { map, startWith } from 'rxjs/operators'; import { isPlatformBrowser } from '@angular/common'; import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; import { FilterType } from '../../../models/filter-type.model'; import { renderFacetFor } from '../search-filter-type-decorator'; @@ -53,11 +54,27 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple */ min = 1950; + /** + * i18n Label to use for minimum field + */ + minLabel: string; + /** * Fallback maximum for the range */ max = new Date().getUTCFullYear(); + /** + * i18n Label to use for maximum field + */ + maxLabel: string; + + /** + * Base configuration for nouislider + * https://refreshless.com/nouislider/slider-options/ + */ + config = {}; + /** * The current range of the filter */ @@ -78,6 +95,7 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple protected filterService: SearchFilterService, protected router: Router, protected rdbs: RemoteDataBuildService, + private translateService: TranslateService, @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, @Inject(IN_PLACE_SEARCH) public inPlaceSearch: boolean, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @@ -96,6 +114,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple super.ngOnInit(); this.min = yearFromString(this.filterConfig.minValue) || this.min; this.max = yearFromString(this.filterConfig.maxValue) || this.max; + this.minLabel = this.translateService.instant('search.filters.filter.' + this.filterConfig.name + '.min.placeholder'); + this.maxLabel = this.translateService.instant('search.filters.filter.' + this.filterConfig.name + '.max.placeholder'); const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX).pipe(startWith(undefined)); const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX).pipe(startWith(undefined)); this.sub = observableCombineLatest(iniMin, iniMax).pipe( @@ -105,6 +125,15 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple return [minimum, maximum]; }) ).subscribe((minmax) => this.range = minmax); + + // Default/base config for nouislider + this.config = { + // Ensure draggable handles have labels + handleAttributes: [ + { 'aria-label': this.minLabel }, + { 'aria-label': this.maxLabel }, + ], + }; } /** From 70a7bbe3cbdd24abaf7f6f791ef60e88a3ae8922 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 15:01:51 -0500 Subject: [PATCH 118/282] Minor fixes to cypress tests --- cypress/e2e/community-list.cy.ts | 1 - cypress/e2e/pagenotfound.cy.ts | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/community-list.cy.ts b/cypress/e2e/community-list.cy.ts index d91260eca1f..c371f6ceae7 100644 --- a/cypress/e2e/community-list.cy.ts +++ b/cypress/e2e/community-list.cy.ts @@ -1,4 +1,3 @@ -import { Options } from 'cypress-axe'; import { testA11y } from 'cypress/support/utils'; describe('Community List Page', () => { diff --git a/cypress/e2e/pagenotfound.cy.ts b/cypress/e2e/pagenotfound.cy.ts index 43e3c3af242..d02aa8541c3 100644 --- a/cypress/e2e/pagenotfound.cy.ts +++ b/cypress/e2e/pagenotfound.cy.ts @@ -1,8 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + describe('PageNotFound', () => { it('should contain element ds-pagenotfound when navigating to page that doesnt exist', () => { // request an invalid page (UUIDs at root path aren't valid) cy.visit('/e9019a69-d4f1-4773-b6a3-bd362caa46f2', { failOnStatusCode: false }); cy.get('ds-pagenotfound').should('be.visible'); + + // Analyze <ds-pagenotfound> for accessibility issues + testA11y('ds-pagenotfound'); }); it('should not contain element ds-pagenotfound when navigating to existing page', () => { From 276d80895e38225fcbde38cab01d79cd31a34e9b Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 29 Aug 2023 15:10:12 -0500 Subject: [PATCH 119/282] Fix heading order accessibility issue in search filters/facets --- cypress/e2e/my-dspace.cy.ts | 12 +----------- cypress/e2e/search-page.cy.ts | 12 +----------- .../search-filter/search-filter.component.html | 4 ++-- .../shared/sidebar/sidebar-dropdown.component.html | 2 +- src/themes/dspace/styles/_global-styles.scss | 2 +- 5 files changed, 6 insertions(+), 26 deletions(-) diff --git a/cypress/e2e/my-dspace.cy.ts b/cypress/e2e/my-dspace.cy.ts index af4aab41f36..13f4a1b5471 100644 --- a/cypress/e2e/my-dspace.cy.ts +++ b/cypress/e2e/my-dspace.cy.ts @@ -19,17 +19,7 @@ describe('My DSpace page', () => { cy.get('.filter-toggle').click({ multiple: true }); // Analyze <ds-my-dspace-page> for accessibility issues - testA11y( - { - include: ['ds-my-dspace-page'], - }, - { - rules: { - // Search filters fail this "moderate" impact rules - 'heading-order': { enabled: false }, - } - } as Options - ); + testA11y('ds-my-dspace-page'); }); it('should have a working detailed view that passes accessibility tests', () => { diff --git a/cypress/e2e/search-page.cy.ts b/cypress/e2e/search-page.cy.ts index 0d4f70ef037..755f8eaac6c 100644 --- a/cypress/e2e/search-page.cy.ts +++ b/cypress/e2e/search-page.cy.ts @@ -27,17 +27,7 @@ describe('Search Page', () => { cy.get('[data-test="filter-toggle"]').click({ multiple: true }); // Analyze <ds-search-page> for accessibility issues - testA11y( - { - include: ['ds-search-page'], - }, - { - rules: { - // Search filters fail this "moderate" impact rule - 'heading-order': { enabled: false }, - } - } as Options - ); + testA11y('ds-search-page'); }); it('should have a working grid view that passes accessibility tests', () => { diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-filter.component.html index a6fb0021b7f..421d1ede2c0 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.html @@ -6,9 +6,9 @@ [attr.aria-label]="(((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate) + ' ' + (('search.filters.filter.' + filter.name + '.head') | translate | lowercase)" [attr.data-test]="'filter-toggle' | dsBrowserOnly" > - <h5 class="d-inline-block mb-0"> + <h4 class="d-inline-block mb-0"> {{'search.filters.filter.' + filter.name + '.head'| translate}} - </h5> + </h4> <span class="filter-toggle flex-grow-1 fas p-auto" [ngClass]="(collapsed$ | async) ? 'fa-plus' : 'fa-minus'" [title]="((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate"> diff --git a/src/app/shared/sidebar/sidebar-dropdown.component.html b/src/app/shared/sidebar/sidebar-dropdown.component.html index 0c2a1c05d25..2eadac09f75 100644 --- a/src/app/shared/sidebar/sidebar-dropdown.component.html +++ b/src/app/shared/sidebar/sidebar-dropdown.component.html @@ -1,5 +1,5 @@ <div class="setting-option mb-3 p-3"> - <h5><label for="{{id}}">{{label | translate}}</label></h5> + <h4><label for="{{id}}">{{label | translate}}</label></h4> <select id="{{id}}" class="form-control" (change)="change.emit($event)"> <ng-content></ng-content> </select> diff --git a/src/themes/dspace/styles/_global-styles.scss b/src/themes/dspace/styles/_global-styles.scss index e41dae0e3f2..5bd4c19bc04 100644 --- a/src/themes/dspace/styles/_global-styles.scss +++ b/src/themes/dspace/styles/_global-styles.scss @@ -17,7 +17,7 @@ background-color: var(--bs-primary); } - h5 { + h4 { font-size: 1.1rem } } From a6c1120700398fb0cf99ffd6e1a7ff52e5858a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carvalho?= <jnsc@ua.pt> Date: Wed, 30 Aug 2023 15:52:34 +0100 Subject: [PATCH 120/282] Minor pt-PT translation fixes --- src/assets/i18n/pt-PT.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/pt-PT.json5 b/src/assets/i18n/pt-PT.json5 index 5aa4817e881..faa027705e0 100644 --- a/src/assets/i18n/pt-PT.json5 +++ b/src/assets/i18n/pt-PT.json5 @@ -2259,7 +2259,7 @@ "confirmation-modal.delete-eperson.header": "Apagar Utilizador \"{{ dsoName }}\"", // "confirmation-modal.delete-eperson.info": "Are you sure you want to delete EPerson \"{{ dsoName }}\"", - "confirmation-modal.delete-eperson.info": "Pretende apagar o utilizar \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Pretende apagar o utilizador \"{{ dsoName }}\"", // "confirmation-modal.delete-eperson.cancel": "Cancel", "confirmation-modal.delete-eperson.cancel": "Cancelar", @@ -2666,7 +2666,7 @@ "health-page.property.status": "Código Estado", // "health-page.section.db.title": "Database", - "health-page.section.db.title": "Base Dados", + "health-page.section.db.title": "Base de Dados", // "health-page.section.geoIp.title": "GeoIp", "health-page.section.geoIp.title": "GeoIp", From 18febff7a6c8e92d3d30016e6a4d93f7fe521dd0 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 1 Sep 2023 21:09:40 +0200 Subject: [PATCH 121/282] Fix routes not working with baseHref --- .../item-edit-bitstream/item-edit-bitstream.component.html | 2 +- .../item-edit-bitstream.component.spec.ts | 6 +++++- src/app/shared/cookies/klaro-configuration.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html index 0f0fad21993..a3e29ac10c2 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html @@ -25,7 +25,7 @@ <div class="{{columnSizes.columns[3].buildClasses()}} row-element d-flex align-items-center"> <div class="text-center w-100"> <div class="btn-group relationship-action-buttons"> - <a *ngIf="bitstreamDownloadUrl != null" [href]="bitstreamDownloadUrl" + <a *ngIf="bitstreamDownloadUrl != null" [routerLink]="bitstreamDownloadUrl" class="btn btn-outline-primary btn-sm" title="{{'item.edit.bitstreams.edit.buttons.download' | translate}}" [attr.data-test]="'download-button' | dsBrowserOnly"> diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts index aafa5a4fe45..f3c897aa738 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.spec.ts @@ -13,6 +13,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-dat import { getBitstreamDownloadRoute } from '../../../../app-routing-paths'; import { By } from '@angular/platform-browser'; import { BrowserOnlyMockPipe } from '../../../../shared/testing/browser-only-mock.pipe'; +import { RouterTestingModule } from '@angular/router/testing'; let comp: ItemEditBitstreamComponent; let fixture: ComponentFixture<ItemEditBitstreamComponent>; @@ -72,7 +73,10 @@ describe('ItemEditBitstreamComponent', () => { ); TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], + imports: [ + RouterTestingModule.withRoutes([]), + TranslateModule.forRoot(), + ], declarations: [ ItemEditBitstreamComponent, VarDirective, diff --git a/src/app/shared/cookies/klaro-configuration.ts b/src/app/shared/cookies/klaro-configuration.ts index a41b641dec1..c818ddc19cb 100644 --- a/src/app/shared/cookies/klaro-configuration.ts +++ b/src/app/shared/cookies/klaro-configuration.ts @@ -22,7 +22,7 @@ export const GOOGLE_ANALYTICS_KLARO_KEY = 'google-analytics'; export const klaroConfiguration: any = { storageName: ANONYMOUS_STORAGE_NAME_KLARO, - privacyPolicy: '/info/privacy', + privacyPolicy: './info/privacy', /* Setting 'hideLearnMore' to 'true' will hide the "learn more / customize" link in From 3e5524de69fa09808e3a7d0ab4042e5e3ffc98e0 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 8 Sep 2023 11:31:26 -0600 Subject: [PATCH 122/282] =?UTF-8?q?=F0=9F=8E=A8=20revert=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metadata-schema-form.component.ts | 119 ++++++++---------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts index 61766a4a109..24bf4306619 100644 --- a/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts +++ b/src/app/admin/admin-registries/metadata-registry/metadata-schema-form/metadata-schema-form.component.ts @@ -1,10 +1,4 @@ -import { - Component, - EventEmitter, - OnDestroy, - OnInit, - Output, -} from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { DynamicFormControlModel, DynamicFormGroupModel, @@ -21,12 +15,13 @@ import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model' @Component({ selector: 'ds-metadata-schema-form', - templateUrl: './metadata-schema-form.component.html', + templateUrl: './metadata-schema-form.component.html' }) /** * A form used for creating and editing metadata schemas */ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { + /** * A unique id used for ds-form */ @@ -58,14 +53,14 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { formLayout: DynamicFormLayout = { name: { grid: { - host: 'col col-sm-6 d-inline-block', - }, + host: 'col col-sm-6 d-inline-block' + } }, namespace: { grid: { - host: 'col col-sm-6 d-inline-block', - }, - }, + host: 'col col-sm-6 d-inline-block' + } + } }; /** @@ -78,67 +73,63 @@ export class MetadataSchemaFormComponent implements OnInit, OnDestroy { */ @Output() submitForm: EventEmitter<any> = new EventEmitter(); - constructor( - public registryService: RegistryService, - private formBuilderService: FormBuilderService, - private translateService: TranslateService - ) {} + constructor(public registryService: RegistryService, private formBuilderService: FormBuilderService, private translateService: TranslateService) { + } ngOnInit() { combineLatest([ this.translateService.get(`${this.messagePrefix}.name`), - this.translateService.get(`${this.messagePrefix}.namespace`), + this.translateService.get(`${this.messagePrefix}.namespace`) ]).subscribe(([name, namespace]) => { this.name = new DynamicInputModel({ - id: 'name', - label: name, - name: 'name', - validators: { - required: null, - pattern: '^[^. ,]*$', - maxLength: 32, - }, - required: true, - errorMessages: { - pattern: 'error.validation.metadata.name.invalid-pattern', - maxLength: 'error.validation.metadata.name.max-length', - }, - }); + id: 'name', + label: name, + name: 'name', + validators: { + required: null, + pattern: '^[^. ,]*$', + maxLength: 32, + }, + required: true, + errorMessages: { + pattern: 'error.validation.metadata.name.invalid-pattern', + maxLength: 'error.validation.metadata.name.max-length', + }, + }); this.namespace = new DynamicInputModel({ - id: 'namespace', - label: namespace, - name: 'namespace', - validators: { - required: null, - maxLength: 256, - }, - required: true, - errorMessages: { - maxLength: 'error.validation.metadata.namespace.max-length', - }, - }); + id: 'namespace', + label: namespace, + name: 'namespace', + validators: { + required: null, + maxLength: 256, + }, + required: true, + errorMessages: { + maxLength: 'error.validation.metadata.namespace.max-length', + }, + }); this.formModel = [ - new DynamicFormGroupModel({ - id: 'metadatadataschemagroup', - group: [this.namespace, this.name], - }), + new DynamicFormGroupModel( + { + id: 'metadatadataschemagroup', + group:[this.namespace, this.name] + }) ]; this.formGroup = this.formBuilderService.createFormGroup(this.formModel); - this.registryService - .getActiveMetadataSchema() - .subscribe((schema: MetadataSchema) => { - if (schema == null) { - this.clearFields(); - } else { - this.formGroup.patchValue({ - metadatadataschemagroup: { - name: schema.prefix, - namespace: schema.namespace, - }, - }); - this.name.disabled = true; - } - }); + this.registryService.getActiveMetadataSchema().subscribe((schema: MetadataSchema) => { + if (schema == null) { + this.clearFields(); + } else { + this.formGroup.patchValue({ + metadatadataschemagroup: { + name: schema.prefix, + namespace: schema.namespace, + }, + }); + this.name.disabled = true; + } + }); }); } From 13e4052c4da07014a1c01087bfc6d293a8bb71c5 Mon Sep 17 00:00:00 2001 From: Hugo Dominguez <hugo@escire.lat> Date: Fri, 8 Sep 2023 11:51:42 -0600 Subject: [PATCH 123/282] =?UTF-8?q?=F0=9F=8E=A8revert=20unnecessary=20form?= =?UTF-8?q?at?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workspaceitem-section-upload-file.model.ts | 4 ++-- .../file/view/section-upload-file-view.component.ts | 12 +++++------- 2 files changed, 7 insertions(+), 9 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 59a8faf6342..785d7c402fa 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. 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 b0ea2487e10..b15b0ab3211 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,11 +1,9 @@ -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 From 01c8a4d9c3347cb5b30d4d912a3f7e18b81f989a Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 8 Sep 2023 14:28:23 -0500 Subject: [PATCH 124/282] Update workspaceitem-section-upload-file.model.ts Fix code comment --- .../models/workspaceitem-section-upload-file.model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 785d7c402fa..725e646d761 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 @@ -30,7 +30,7 @@ export class WorkspaceitemSectionUploadFileObject { }; /** - * The file check sum + * The file format information */ format: { shortDescription: string, From 0905a53db5eca45220809831663ba8d6761e55c5 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Fri, 8 Sep 2023 22:35:27 +0200 Subject: [PATCH 125/282] Fix innerText still being undefined in ssr mode --- src/app/shared/log-in/log-in.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/log-in/log-in.component.html b/src/app/shared/log-in/log-in.component.html index 05d8d4370f0..857b977360e 100644 --- a/src/app/shared/log-in/log-in.component.html +++ b/src/app/shared/log-in/log-in.component.html @@ -1,7 +1,7 @@ <ds-themed-loading *ngIf="(loading | async) || (isAuthenticated | async)" class="m-5"></ds-themed-loading> <div *ngIf="!(loading | async) && !(isAuthenticated | async)" class="px-4 py-3 mx-auto login-container"> <ng-container *ngFor="let authMethod of getOrderedAuthMethods(authMethods | async); let last = last"> - <div [class.d-none]="contentRef.innerText.trim().length === 0"> + <div [class.d-none]="contentRef.innerText?.trim().length === 0"> <div #contentRef> <ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container> </div> From 49247430e50a708996bef1790c7cc2af2271113a Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 12 Sep 2023 13:57:26 -0500 Subject: [PATCH 126/282] Correct text of help info on edit group page --- src/assets/i18n/en.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 0bc24355543..32a10d4d542 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -508,9 +508,9 @@ "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.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": "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.", - "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": "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 groups. Then click the plus icon for each group you wish to add in the list below, or the trash can icon for each group you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages.", "admin.search.breadcrumbs": "Administrative Search", From cfa70ecb8e2815c5b9e2e2a7a0552597691f679b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eike=20Martin=20L=C3=B6hden?= <eike.loehden@ub.uni-marburg.de> Date: Thu, 14 Sep 2023 16:28:21 +0200 Subject: [PATCH 127/282] Removed default value from inExpandableNavbar. --- .../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 cecafc9d5cd..9dafe6c4261 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 @@ -15,7 +15,7 @@ export class ThemedUserMenuComponent extends ThemedComponent<UserMenuComponent>{ /** * The input flag to show user details in navbar expandable menu */ - @Input() inExpandableNavbar = false; + @Input() inExpandableNavbar: boolean; protected inAndOutputNames: (keyof UserMenuComponent & keyof this)[] = ['inExpandableNavbar']; From 5bc5dd859e18a601c6eadf9e2c3496b1fb8b4589 Mon Sep 17 00:00:00 2001 From: Sascha Szott <szott@gmx.de> Date: Tue, 19 Sep 2023 17:51:58 +0200 Subject: [PATCH 128/282] allow to insert multi-line scope notes in MD field registry --- .../metadata-field-form/metadata-field-form.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts index 773e0600fbf..f04324bdc59 100644 --- a/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts +++ b/src/app/admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.ts @@ -3,7 +3,8 @@ import { DynamicFormControlModel, DynamicFormGroupModel, DynamicFormLayout, - DynamicInputModel + DynamicInputModel, + DynamicTextAreaModel } from '@ng-dynamic-forms/core'; import { UntypedFormGroup } from '@angular/forms'; import { RegistryService } from '../../../../core/registry/registry.service'; @@ -51,7 +52,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy { /** * A dynamic input model for the scopeNote field */ - scopeNote: DynamicInputModel; + scopeNote: DynamicTextAreaModel; /** * A list of all dynamic input models @@ -132,11 +133,12 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy { maxLength: 'error.validation.metadata.qualifier.max-length', }, }); - this.scopeNote = new DynamicInputModel({ + this.scopeNote = new DynamicTextAreaModel({ id: 'scopeNote', label: scopenote, name: 'scopeNote', required: false, + rows: 5, }); this.formModel = [ new DynamicFormGroupModel( From 5ad621b27ea13177196c35ea31f5abdc6714762b Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Fri, 22 Sep 2023 10:23:07 +0200 Subject: [PATCH 129/282] fix issue where more than one api call was made on every route change --- src/app/core/data/request.service.spec.ts | 37 +++++++++ src/app/core/data/request.service.ts | 30 ++++++- src/app/core/data/root-data.service.spec.ts | 38 ++++----- src/app/core/data/root-data.service.ts | 13 ++- .../server-check/server-check.guard.spec.ts | 80 +++++++++++-------- .../core/server-check/server-check.guard.ts | 34 ++++++-- src/modules/app/browser-init.service.ts | 13 ++- 7 files changed, 174 insertions(+), 71 deletions(-) diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index 108a5888818..12208d7e40a 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -638,4 +638,41 @@ describe('RequestService', () => { expect(done$).toBeObservable(cold('-----(t|)', { t: true })); })); }); + + describe('setStaleByHref', () => { + const uuid = 'c574a42c-4818-47ac-bbe1-6c3cd622c81f'; + const href = 'https://rest.api/some/object'; + const freshRE: any = { + request: { uuid, href }, + state: RequestEntryState.Success + }; + const staleRE: any = { + request: { uuid, href }, + state: RequestEntryState.SuccessStale + }; + + it(`should call getByHref to retrieve the RequestEntry matching the href`, () => { + spyOn(service, 'getByHref').and.returnValue(observableOf(staleRE)); + service.setStaleByHref(href); + expect(service.getByHref).toHaveBeenCalledWith(href); + }); + + it(`should dispatch a RequestStaleAction for the RequestEntry returned by getByHref`, (done: DoneFn) => { + spyOn(service, 'getByHref').and.returnValue(observableOf(staleRE)); + spyOn(store, 'dispatch'); + service.setStaleByHref(href).subscribe(() => { + expect(store.dispatch).toHaveBeenCalledWith(new RequestStaleAction(uuid)); + done(); + }); + }); + + it(`should emit true when the request in the store is stale`, () => { + spyOn(service, 'getByHref').and.returnValue(cold('a-b', { + a: freshRE, + b: staleRE + })); + const result$ = service.setStaleByHref(href); + expect(result$).toBeObservable(cold('--(c|)', { c: true })); + }); + }); }); diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index 1f6680203e0..27176390d7e 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -16,7 +16,7 @@ import { RequestExecuteAction, RequestStaleAction } from './request.actions'; -import { GetRequest} from './request.models'; +import { GetRequest } from './request.models'; import { CommitSSBAction } from '../cache/server-sync-buffer.actions'; import { RestRequestMethod } from './rest-request-method'; import { coreSelector } from '../core.selectors'; @@ -331,7 +331,29 @@ export class RequestService { map((request: RequestEntry) => isStale(request.state)), filter((stale: boolean) => stale), take(1), - ); + ); + } + + /** + * Mark a request as stale + * @param href the href of the request + * @return an Observable that will emit true once the Request becomes stale + */ + setStaleByHref(href: string): Observable<boolean> { + const requestEntry$ = this.getByHref(href); + + requestEntry$.pipe( + map((re: RequestEntry) => re.request.uuid), + take(1), + ).subscribe((uuid: string) => { + this.store.dispatch(new RequestStaleAction(uuid)); + }); + + return requestEntry$.pipe( + map((request: RequestEntry) => isStale(request.state)), + filter((stale: boolean) => stale), + take(1) + ); } /** @@ -344,10 +366,10 @@ export class RequestService { // if it's not a GET request if (request.method !== RestRequestMethod.GET) { return true; - // if it is a GET request, check it isn't pending + // if it is a GET request, check it isn't pending } else if (this.isPending(request)) { return false; - // if it is pending, check if we're allowed to use a cached version + // if it is pending, check if we're allowed to use a cached version } else if (!useCachedVersionIfAvailable) { return true; } else { diff --git a/src/app/core/data/root-data.service.spec.ts b/src/app/core/data/root-data.service.spec.ts index b65449d0075..c34ad375310 100644 --- a/src/app/core/data/root-data.service.spec.ts +++ b/src/app/core/data/root-data.service.spec.ts @@ -1,16 +1,18 @@ import { RootDataService } from './root-data.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; -import { Observable, of } from 'rxjs'; +import { + createSuccessfulRemoteDataObject$, + createFailedRemoteDataObject$ +} from '../../shared/remote-data.utils'; +import { Observable } from 'rxjs'; import { RemoteData } from './remote-data'; import { Root } from './root.model'; -import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { cold } from 'jasmine-marbles'; describe('RootDataService', () => { let service: RootDataService; let halService: HALEndpointService; - let restService; + let requestService; let rootEndpoint; let findByHrefSpy; @@ -19,10 +21,10 @@ describe('RootDataService', () => { halService = jasmine.createSpyObj('halService', { getRootHref: rootEndpoint, }); - restService = jasmine.createSpyObj('halService', { - get: jasmine.createSpy('get'), - }); - service = new RootDataService(null, null, null, halService, restService); + requestService = jasmine.createSpyObj('requestService', [ + 'setStaleByHref', + ]); + service = new RootDataService(requestService, null, null, halService); findByHrefSpy = spyOn(service as any, 'findByHref'); findByHrefSpy.and.returnValue(createSuccessfulRemoteDataObject$({})); @@ -47,12 +49,8 @@ describe('RootDataService', () => { let result$: Observable<boolean>; it('should return observable of true when root endpoint is available', () => { - const mockResponse = { - statusCode: 200, - statusText: 'OK' - } as RawRestResponse; + spyOn(service, 'findRoot').and.returnValue(createSuccessfulRemoteDataObject$<Root>({} as any)); - restService.get.and.returnValue(of(mockResponse)); result$ = service.checkServerAvailability(); expect(result$).toBeObservable(cold('(a|)', { @@ -61,12 +59,8 @@ describe('RootDataService', () => { }); it('should return observable of false when root endpoint is not available', () => { - const mockResponse = { - statusCode: 500, - statusText: 'Internal Server Error' - } as RawRestResponse; + spyOn(service, 'findRoot').and.returnValue(createFailedRemoteDataObject$<Root>('500')); - restService.get.and.returnValue(of(mockResponse)); result$ = service.checkServerAvailability(); expect(result$).toBeObservable(cold('(a|)', { @@ -75,4 +69,12 @@ describe('RootDataService', () => { }); }); + + describe(`invalidateRootCache`, () => { + it(`should set the cached root request to stale`, () => { + service.invalidateRootCache(); + expect(halService.getRootHref).toHaveBeenCalled(); + expect(requestService.setStaleByHref).toHaveBeenCalledWith(rootEndpoint); + }); + }); }); diff --git a/src/app/core/data/root-data.service.ts b/src/app/core/data/root-data.service.ts index 54fe614d3e8..88cffdf6cf2 100644 --- a/src/app/core/data/root-data.service.ts +++ b/src/app/core/data/root-data.service.ts @@ -7,12 +7,11 @@ import { HALEndpointService } from '../shared/hal-endpoint.service'; import { Observable, of as observableOf } from 'rxjs'; import { RemoteData } from './remote-data'; import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; -import { DspaceRestService } from '../dspace-rest/dspace-rest.service'; -import { RawRestResponse } from '../dspace-rest/raw-rest-response.model'; import { catchError, map } from 'rxjs/operators'; import { BaseDataService } from './base/base-data.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { dataService } from './base/data-service.decorator'; +import { getFirstCompletedRemoteData } from '../shared/operators'; /** * A service to retrieve the {@link Root} object from the REST API. @@ -25,21 +24,21 @@ export class RootDataService extends BaseDataService<Root> { protected rdbService: RemoteDataBuildService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, - protected restService: DspaceRestService, ) { - super('', requestService, rdbService, objectCache, halService, 6 * 60 * 60 * 1000); + super('', requestService, rdbService, objectCache, halService, 60 * 1000); } /** * Check if root endpoint is available */ checkServerAvailability(): Observable<boolean> { - return this.restService.get(this.halService.getRootHref()).pipe( + return this.findRoot().pipe( catchError((err ) => { console.error(err); return observableOf(false); }), - map((res: RawRestResponse) => res.statusCode === 200) + getFirstCompletedRemoteData(), + map((rootRd: RemoteData<Root>) => rootRd.statusCode === 200) ); } @@ -60,6 +59,6 @@ export class RootDataService extends BaseDataService<Root> { * Set to sale the root endpoint cache hit */ invalidateRootCache() { - this.requestService.setStaleByHrefSubstring(this.halService.getRootHref()); + this.requestService.setStaleByHref(this.halService.getRootHref()); } } 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 1f126be5e55..13045b0ff6d 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -1,68 +1,78 @@ import { ServerCheckGuard } from './server-check.guard'; -import { Router } from '@angular/router'; +import { Router, NavigationStart, UrlTree, NavigationEnd, RouterEvent } from '@angular/router'; -import { of } from 'rxjs'; -import { take } from 'rxjs/operators'; - -import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; +import { of, ReplaySubject } from 'rxjs'; import { RootDataService } from '../data/root-data.service'; +import { TestScheduler } from 'rxjs/testing'; import SpyObj = jasmine.SpyObj; describe('ServerCheckGuard', () => { let guard: ServerCheckGuard; - let router: SpyObj<Router>; + let router: Router; + const eventSubject = new ReplaySubject<RouterEvent>(1); let rootDataServiceStub: SpyObj<RootDataService>; - - rootDataServiceStub = jasmine.createSpyObj('RootDataService', { - checkServerAvailability: jasmine.createSpy('checkServerAvailability'), - invalidateRootCache: jasmine.createSpy('invalidateRootCache') - }); - router = jasmine.createSpyObj('Router', { - navigateByUrl: jasmine.createSpy('navigateByUrl') - }); + let testScheduler: TestScheduler; + let redirectUrlTree: UrlTree; beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + rootDataServiceStub = jasmine.createSpyObj('RootDataService', { + checkServerAvailability: jasmine.createSpy('checkServerAvailability'), + invalidateRootCache: jasmine.createSpy('invalidateRootCache') + }); + redirectUrlTree = new UrlTree(); + router = { + events: eventSubject.asObservable(), + navigateByUrl: jasmine.createSpy('navigateByUrl'), + parseUrl: jasmine.createSpy('parseUrl').and.returnValue(redirectUrlTree) + } as any; guard = new ServerCheckGuard(router, rootDataServiceStub); }); - afterEach(() => { - router.navigateByUrl.calls.reset(); - rootDataServiceStub.invalidateRootCache.calls.reset(); - }); - it('should be created', () => { expect(guard).toBeTruthy(); }); - describe('when root endpoint has succeeded', () => { + describe('when root endpoint request has succeeded', () => { beforeEach(() => { rootDataServiceStub.checkServerAvailability.and.returnValue(of(true)); }); - it('should not redirect to error page', () => { - guard.canActivateChild({} as any, {} as any).pipe( - take(1) - ).subscribe((canActivate: boolean) => { - expect(canActivate).toEqual(true); - expect(rootDataServiceStub.invalidateRootCache).not.toHaveBeenCalled(); - expect(router.navigateByUrl).not.toHaveBeenCalled(); + it('should return true', () => { + testScheduler.run(({ expectObservable }) => { + const result$ = guard.canActivateChild({} as any, {} as any); + expectObservable(result$).toBe('(a|)', { a: true }); }); }); }); - describe('when root endpoint has not succeeded', () => { + describe('when root endpoint request has not succeeded', () => { beforeEach(() => { rootDataServiceStub.checkServerAvailability.and.returnValue(of(false)); }); - it('should redirect to error page', () => { - guard.canActivateChild({} as any, {} as any).pipe( - take(1) - ).subscribe((canActivate: boolean) => { - expect(canActivate).toEqual(false); - expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalled(); - expect(router.navigateByUrl).toHaveBeenCalledWith(getPageInternalServerErrorRoute()); + it('should return a UrlTree with the route to the 500 error page', () => { + testScheduler.run(({ expectObservable }) => { + const result$ = guard.canActivateChild({} as any, {} as any); + expectObservable(result$).toBe('(b|)', { b: redirectUrlTree }); }); + expect(router.parseUrl).toHaveBeenCalledWith('/500'); + }); + }); + + describe(`listenForRouteChanges`, () => { + 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(3); }); }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 8a0e26c01da..ab3bc2c6e99 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -1,8 +1,15 @@ import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'; +import { + ActivatedRouteSnapshot, + CanActivateChild, + Router, + RouterStateSnapshot, + UrlTree, + NavigationStart +} from '@angular/router'; import { Observable } from 'rxjs'; -import { take, tap } from 'rxjs/operators'; +import { take, map, filter } from 'rxjs/operators'; import { RootDataService } from '../data/root-data.service'; import { getPageInternalServerErrorRoute } from '../../app-routing-paths'; @@ -23,17 +30,32 @@ export class ServerCheckGuard implements CanActivateChild { */ canActivateChild( route: ActivatedRouteSnapshot, - state: RouterStateSnapshot): Observable<boolean> { + state: RouterStateSnapshot + ): Observable<boolean | UrlTree> { return this.rootDataService.checkServerAvailability().pipe( take(1), - tap((isAvailable: boolean) => { + map((isAvailable: boolean) => { if (!isAvailable) { - this.rootDataService.invalidateRootCache(); - this.router.navigateByUrl(getPageInternalServerErrorRoute()); + return this.router.parseUrl(getPageInternalServerErrorRoute()); + } else { + return true; } }) ); + } + /** + * Listen to all router events. Every time a new navigation starts, invalidate the cache + * for the root endpoint. That way we retrieve it once per routing operation to ensure the + * backend is not down. But if the guard is called multiple times during the same routing + * operation, the cached version is used. + */ + listenForRouteChanges(): void { + this.router.events.pipe( + filter(event => event instanceof NavigationStart), + ).subscribe(() => { + this.rootDataService.invalidateRootCache(); + }); } } diff --git a/src/modules/app/browser-init.service.ts b/src/modules/app/browser-init.service.ts index 61d57f10f98..bf40f0c68b6 100644 --- a/src/modules/app/browser-init.service.ts +++ b/src/modules/app/browser-init.service.ts @@ -32,6 +32,7 @@ import { logStartupMessage } from '../../../startup-message'; import { MenuService } from '../../app/shared/menu/menu.service'; import { RootDataService } from '../../app/core/data/root-data.service'; import { firstValueFrom, Subscription } from 'rxjs'; +import { ServerCheckGuard } from '../../app/core/server-check/server-check.guard'; /** * Performs client-side initialization. @@ -56,7 +57,8 @@ export class BrowserInitService extends InitService { protected authService: AuthService, protected themeService: ThemeService, protected menuService: MenuService, - private rootDataService: RootDataService + private rootDataService: RootDataService, + protected serverCheckGuard: ServerCheckGuard, ) { super( store, @@ -172,4 +174,13 @@ export class BrowserInitService extends InitService { }); } + /** + * Start route-listening subscriptions + * @protected + */ + protected initRouteListeners(): void { + super.initRouteListeners(); + this.serverCheckGuard.listenForRouteChanges(); + } + } From 8fbe8c16dc2fe999cc53c851bb8ae9df9b8487e4 Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Fri, 22 Sep 2023 12:00:59 +0200 Subject: [PATCH 130/282] fix issue where invalidateRootCache didn't happen when the page first loaded --- src/app/core/server-check/server-check.guard.spec.ts | 6 ++++-- src/app/core/server-check/server-check.guard.ts | 4 ++++ 2 files changed, 8 insertions(+), 2 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 13045b0ff6d..f18b3867538 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -63,16 +63,18 @@ describe('ServerCheckGuard', () => { }); describe(`listenForRouteChanges`, () => { - it(`should invalidate the root cache on every NavigationStart event`, () => { + it(`should invalidate the root cache when the method is first called, and then on every NavigationStart event`, () => { testScheduler.run(() => { guard.listenForRouteChanges(); + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(1); + 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(3); + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(4); }); }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index ab3bc2c6e99..1cea5f36bab 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -52,6 +52,10 @@ export class ServerCheckGuard implements CanActivateChild { * operation, the cached version is used. */ 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(); + this.router.events.pipe( filter(event => event instanceof NavigationStart), ).subscribe(() => { From 77d6212e462b38802f801ebd6151ebdd26c7a807 Mon Sep 17 00:00:00 2001 From: Sascha Szott <szott@gmx.de> Date: Fri, 22 Sep 2023 19:57:36 +0200 Subject: [PATCH 131/282] remove obsolete label element in metadata-schema.component.html (#2505) * remove obsolete label element in metadata-schema.component.html --- .../metadata-schema/metadata-schema.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.html b/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.html index 557741df80c..2fe53dfcd84 100644 --- a/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.html +++ b/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.html @@ -41,7 +41,7 @@ <h3>{{'admin.registries.schema.fields.head' | translate}}</h3> </label> </td> <td class="selectable-row" (click)="editField(field)">{{field.id}}</td> - <td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}<label *ngIf="field.qualifier" class="mb-0">.</label>{{field.qualifier}}</td> + <td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}{{field.qualifier ? '.' + field.qualifier : ''}}</td> <td class="selectable-row" (click)="editField(field)">{{field.scopeNote}}</td> </tr> </tbody> 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 132/282] 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 <davide.negretti@4science.com> Date: Mon, 25 Sep 2023 23:51:48 +0200 Subject: [PATCH 133/282] [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 <alan.orth@gmail.com> Date: Mon, 18 Sep 2023 14:40:19 +0300 Subject: [PATCH 134/282] 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"> <label class="mb-0 d-flex w-100"> <input type="checkbox" [checked]="true" class="my-1 align-self-stretch filter-checkbox"/> - <span class="filter-value pl-1 text-capitalize break-facet"> + <span class="filter-value pl-1 break-facet"> {{ 'search.filters.' + filterConfig.name + '.' + selectedValue.value | translate: {default: selectedValue.label} }} </span> </label> 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 @@ -<a class="badge badge-primary mr-1 mb-1 text-capitalize" +<a class="badge badge-primary mr-1 mb-1" [routerLink]="searchLink" [queryParams]="(removeParameters | async)" queryParamsHandling="merge"> {{('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 <imilos@gmail.com> Date: Tue, 26 Sep 2023 07:29:17 +0200 Subject: [PATCH 135/282] 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 <a href='{{comcolEditRolesRoute}}'>\"dodeli uloge\"</a> 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 \"<i>Glavni članak</i>\" ili \"<i>Očitavanja podataka eksperimenta</i>\".", + "bitstream.edit.form.description.label": "Opis", + "bitstream.edit.form.embargo.hint": "Prvi dan od kojeg je pristup dozvoljen. <b>Ovaj datum se ne može izmeniti u ovom obrascu.</b> Da biste postavili datum zabrane za bitstream, idite na karticu <i>Status stavke</i>, kliknite na <i>Ovlašćenja...</i >, kreirajte ili izmenite politiku bitstream-ova<i>PROČITAJTE</i> i postavite <i>Datum početka</i> 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, \"<i>ACMESoft SuperApp verzija 1.5</i>\").", + "bitstream.edit.form.primaryBitstream.label": "Primarni bitstream", + "bitstream.edit.form.selectedFormat.hint": "Ako format nije na gornjoj listi, <b>izaberite \"format nije na listi\" iznad</b> 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: \"<b>{{name}}</b>\"", + "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: <strong>Provera autentičnosti, podešavanja, potvrda i statistika</strong>. <br/> 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: <strong>Provera autentičnosti, podešavanja, potvrda i statistika</strong>.", + "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 <a href=\"https://solr.apache.org/guide/kueri-sintak-and-parsing.html\" target=\"_blank\">Solr sintaksu upita</a> 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: <br> <br>", + "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 <a href='{{ url }}'>{{ name }}</a>, 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: \"<b>{{name}}</b>\"", + "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 <a href='{{destination}}'>ovde</a>.", + "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 <b>registraciju i vraćanje lozinke</b> (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.<br>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 <strong>{{sectionId}}</strong>.", + "submission.sections.general.metadata-extracted-new-section": "Novi odeljak <strong>{{sectionId}}</strong> 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 <strong> otpremite dodatne fajlove tako što ćete ih prevući i otpustiti bilo gde na stranici.</strong>", + "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 <strong>nije</strong> 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 <a href='{{orcid}}'>ovde</a> 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 <andrea.barbasso@gmail.com> Date: Tue, 26 Sep 2023 09:22:30 +0200 Subject: [PATCH 136/282] 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: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>. <br/> To learn more, please read our {privacyPolicy}.", - "cookies.consent.content-notice.description": "Raccogliamo e processiamo le tue informazioni personali per i seguenti scopi: <strong>Autenticazione, Preferenze, Accettazione e Statistiche</strong>. <br/> Per saperne di più, leggi la nostra {privacyPolicy}.", + "cookies.consent.content-notice.description": "Raccogliamo ed elaboriamo le tue informazioni personali per i seguenti scopi: <strong>Autenticazione, Preferenze, Accettazione e Statistiche</strong>. <br/> 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: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>.", - // TODO New key - Add a translation - "cookies.consent.content-notice.description.no-privacy": "We collect and process your personal information for the following purposes: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>.", + "cookies.consent.content-notice.description.no-privacy": "Raccogliamo ed elaboriamo le tue informazioni personali per i seguenti scopi: <strong>Autenticazione, Preferenze, Accettazione e Statistiche</strong>.", // "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 <b>Registration and Password recovery</b> (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 <b>Registration and Password recovery</b> (Google reCaptcha) cookies.", + "register-page.registration.google-recaptcha.must-accept-cookies": "Per registrarsi è obbligatorio accettare i cookie <b>Registration and Password recovery</b> (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.<br>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.<br>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.<br> 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 <strong>upload additional files by dragging & dropping them anywhere on the page.</strong>", - // 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 <fortng>upload di file aggiuntivi semplicemente trascinandoli e rilasciandoli ovunque nella pagina</strong>", + "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 <strong>caricare file aggiuntivi semplicemente trascinandoli e rilasciandoli ovunque nella pagina</strong>", // "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 <art.lowel@gmail.com> Date: Tue, 26 Sep 2023 14:44:13 +0200 Subject: [PATCH 137/282] 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 <art.lowel@gmail.com> Date: Tue, 26 Sep 2023 16:56:07 +0200 Subject: [PATCH 138/282] 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<Root> { 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 <jens.vannerum@atmire.com> Date: Fri, 29 Sep 2023 15:54:34 +0200 Subject: [PATCH 139/282] 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 <alexandre@atmire.com> Date: Fri, 29 Sep 2023 21:40:29 +0200 Subject: [PATCH 140/282] 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 <alexandre@atmire.com> Date: Tue, 26 Sep 2023 11:50:29 +0200 Subject: [PATCH 141/282] 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<boolean>; + 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 @@ <ds-context-help-toggle></ds-context-help-toggle> <ds-themed-auth-nav-menu></ds-themed-auth-nav-menu> <ds-impersonate-navbar></ds-impersonate-navbar> - <div class="pl-2"> - <button class="navbar-toggler" type="button" (click)="toggleNavbar()" + <div *ngIf="isXsOrSm$ | async" class="pl-2"> + <button class="navbar-toggler px-0" type="button" (click)="toggleNavbar()" aria-controls="collapsingNav" aria-expanded="false" [attr.aria-label]="'nav.toggle' | translate"> <span class="navbar-toggler-icon fas fa-bars fa-fw" aria-hidden="true"></span> diff --git a/src/app/header/header.component.scss b/src/app/header/header.component.scss index cca3ed2abb0..8a11a651956 100644 --- a/src/app/header/header.component.scss +++ b/src/app/header/header.component.scss @@ -20,3 +20,7 @@ } } +.navbar { + display: flex; + gap: 0.25rem; +} diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts index 9bc952cee35..ccf8b196219 100644 --- a/src/app/header/header.component.spec.ts +++ b/src/app/header/header.component.spec.ts @@ -10,6 +10,8 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { MenuService } from '../shared/menu/menu.service'; import { MenuServiceStub } from '../shared/testing/menu-service.stub'; +import { HostWindowService } from '../shared/host-window.service'; +import { HostWindowServiceStub } from '../shared/testing/host-window-service.stub'; let comp: HeaderComponent; let fixture: ComponentFixture<HeaderComponent>; @@ -26,6 +28,7 @@ describe('HeaderComponent', () => { ReactiveFormsModule], declarations: [HeaderComponent], providers: [ + { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }, { provide: MenuService, useValue: menuService } ], schemas: [NO_ERRORS_SCHEMA] @@ -40,7 +43,7 @@ describe('HeaderComponent', () => { fixture = TestBed.createComponent(HeaderComponent); comp = fixture.componentInstance; - + fixture.detectChanges(); }); describe('when the toggle button is clicked', () => { diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index 366b4f5e7a1..5153a19be47 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -1,7 +1,8 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { MenuService } from '../shared/menu/menu.service'; import { MenuID } from '../shared/menu/menu-id.model'; +import { HostWindowService } from '../shared/host-window.service'; /** * Represents the header with the logo and simple navigation @@ -11,20 +12,25 @@ import { MenuID } from '../shared/menu/menu-id.model'; styleUrls: ['header.component.scss'], templateUrl: 'header.component.html', }) -export class HeaderComponent { +export class HeaderComponent implements OnInit { /** * Whether user is authenticated. * @type {Observable<string>} */ public isAuthenticated: Observable<boolean>; - public showAuth = false; + public isXsOrSm$: Observable<boolean>; menuID = MenuID.PUBLIC; constructor( - private menuService: MenuService + protected menuService: MenuService, + protected windowService: HostWindowService, ) { } + ngOnInit(): void { + this.isXsOrSm$ = this.windowService.isXsOrSm(); + } + public toggleNavbar(): void { this.menuService.toggleMenu(this.menuID); } diff --git a/src/app/search-navbar/search-navbar.component.html b/src/app/search-navbar/search-navbar.component.html index 2b30507f3ec..8a98d4c44c4 100644 --- a/src/app/search-navbar/search-navbar.component.html +++ b/src/app/search-navbar/search-navbar.component.html @@ -1,9 +1,9 @@ <div id="search-navbar-container" [title]="'nav.search' | translate" (dsClickOutside)="collapse()"> <div class="d-inline-block position-relative"> - <form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on"> + <form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on" class="d-flex"> <input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query" formControlName="query" type="text" placeholder="{{searchExpanded ? ('nav.search' | translate) : ''}}" - class="d-inline-block bg-transparent position-absolute form-control dropdown-menu-right p-1" [attr.data-test]="'header-search-box' | dsBrowserOnly"> + class="d-inline-block bg-transparent position-absolute form-control dropdown-menu-right pl-1" [attr.data-test]="'header-search-box' | dsBrowserOnly"> <button class="submit-icon btn btn-link btn-link-inline" [attr.aria-label]="'nav.search.button' | translate" type="button" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly"> <em class="fas fa-search fa-lg fa-fw"></em> </button> 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 @@ <li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item" (click)="$event.stopPropagation();"> <div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut> - <a href="javascript:void(0);" class="dropdownLogin px-1" [attr.aria-label]="'nav.login' |translate" + <a href="javascript:void(0);" class="dropdownLogin px-0.5" [attr.aria-label]="'nav.login' |translate" (click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly" ngbDropdownToggle>{{ 'nav.login' | translate }}</a> <div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu @@ -13,7 +13,7 @@ </div> </li> <li *ngIf="!(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item"> - <a routerLink="/login" routerLinkActive="active" class="loginLink px-1"> + <a routerLink="/login" routerLinkActive="active" class="loginLink px-0.5"> {{ 'nav.login' | translate }}<span class="sr-only">(current)</span> </a> </li> 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 @@ -<ul class="navbar-nav" *ngIf="(isAuthenticated$ | async) && isImpersonating"> +<ul class="navbar-nav" *ngIf="isImpersonating$ | async"> <li class="nav-item"> <button class="btn btn-sm btn-dark" ngbTooltip="{{'nav.stop-impersonating' | translate}}" (click)="stopImpersonating()"> <i class="fa fa-user-secret"></i> diff --git a/src/app/shared/impersonate-navbar/impersonate-navbar.component.spec.ts b/src/app/shared/impersonate-navbar/impersonate-navbar.component.spec.ts index af03afc05f9..0e78a5d68a2 100644 --- a/src/app/shared/impersonate-navbar/impersonate-navbar.component.spec.ts +++ b/src/app/shared/impersonate-navbar/impersonate-navbar.component.spec.ts @@ -14,6 +14,7 @@ import { authReducer } from '../../core/auth/auth.reducer'; import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model'; import { EPersonMock } from '../testing/eperson.mock'; import { AppState, storeModuleConfig } from '../../app.reducer'; +import { of as observableOf } from 'rxjs'; describe('ImpersonateNavbarComponent', () => { let component: ImpersonateNavbarComponent; @@ -65,7 +66,7 @@ describe('ImpersonateNavbarComponent', () => { describe('when the user is impersonating another user', () => { beforeEach(() => { - component.isImpersonating = true; + component.isImpersonating$ = observableOf(true); fixture.detectChanges(); }); diff --git a/src/app/shared/impersonate-navbar/impersonate-navbar.component.ts b/src/app/shared/impersonate-navbar/impersonate-navbar.component.ts index 6166ee950dc..485492b1a77 100644 --- a/src/app/shared/impersonate-navbar/impersonate-navbar.component.ts +++ b/src/app/shared/impersonate-navbar/impersonate-navbar.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ElementRef } from '@angular/core'; import { select, Store } from '@ngrx/store'; import { AppState } from '../../app.reducer'; import { AuthService } from '../../core/auth/auth.service'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; import { isAuthenticated } from '../../core/auth/selectors'; @Component({ @@ -13,24 +14,32 @@ import { isAuthenticated } from '../../core/auth/selectors'; * Navbar component for actions to take concerning impersonating users */ export class ImpersonateNavbarComponent implements OnInit { - /** - * Whether or not the user is authenticated. - * @type {Observable<string>} - */ - isAuthenticated$: Observable<boolean>; /** * Is the user currently impersonating another user? */ - isImpersonating: boolean; + isImpersonating$: Observable<boolean>; + + subscriptions: Subscription[] = []; - constructor(private store: Store<AppState>, - private authService: AuthService) { + constructor( + protected elRef: ElementRef, + protected store: Store<AppState>, + protected authService: AuthService, + ) { } ngOnInit(): void { - this.isAuthenticated$ = this.store.pipe(select(isAuthenticated)); - this.isImpersonating = this.authService.isImpersonating(); + this.isImpersonating$ = this.store.pipe(select(isAuthenticated)).pipe( + map((isUserAuthenticated: boolean) => isUserAuthenticated && this.authService.isImpersonating()), + ); + this.subscriptions.push(this.isImpersonating$.subscribe((isImpersonating: boolean) => { + if (isImpersonating) { + this.elRef.nativeElement.classList.remove('d-none'); + } else { + this.elRef.nativeElement.classList.add('d-none'); + } + })); } /** diff --git a/src/app/shared/lang-switch/lang-switch.component.html b/src/app/shared/lang-switch/lang-switch.component.html index d9a5efaa814..73a5041f7b2 100644 --- a/src/app/shared/lang-switch/lang-switch.component.html +++ b/src/app/shared/lang-switch/lang-switch.component.html @@ -1,7 +1,7 @@ <div ngbDropdown class="navbar-nav" *ngIf="moreThanOneLanguage" display="dynamic" placement="bottom-right"> <a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.language' |translate" - [title]="'nav.language' | translate" class="px-1" + [title]="'nav.language' | translate" (click)="$event.preventDefault()" data-toggle="dropdown" ngbDropdownToggle tabindex="0"> <i class="fas fa-globe-asia fa-lg fa-fw"></i> diff --git a/src/app/shared/lang-switch/lang-switch.component.ts b/src/app/shared/lang-switch/lang-switch.component.ts index 41d707a0568..d2c70839c0e 100644 --- a/src/app/shared/lang-switch/lang-switch.component.ts +++ b/src/app/shared/lang-switch/lang-switch.component.ts @@ -1,7 +1,5 @@ -import { Component, OnInit } from '@angular/core'; - +import { Component, OnInit, ElementRef } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; - import { LangConfig } from '../../../config/lang-config.interface'; import { environment } from '../../../environments/environment'; import { LocaleService } from '../../core/locale/locale.service'; @@ -25,6 +23,7 @@ export class LangSwitchComponent implements OnInit { moreThanOneLanguage: boolean; constructor( + public el: ElementRef, public translate: TranslateService, private localeService: LocaleService ) { @@ -33,6 +32,9 @@ export class LangSwitchComponent implements OnInit { ngOnInit(): void { this.activeLangs = environment.languages.filter((MyLangConfig) => MyLangConfig.active === true); this.moreThanOneLanguage = (this.activeLangs.length > 1); + if (!this.moreThanOneLanguage) { + this.el.nativeElement.style.display = 'none'; + } } /** diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index b714d399a08..00fcb0f86f1 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -267,3 +267,29 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { .table td { vertical-align: middle; } + +.pt-0\.5 { + padding-top: 0.125rem !important; +} + +.pr-0\.5 { + padding-right: 0.125rem !important; +} + +.pb-0\.5 { + padding-bottom: 0.125rem !important; +} + +.pl-0\.5 { + padding-left: 0.125rem !important; +} + +.px-0\.5 { + padding-left: 0.125rem !important; + padding-right: 0.125rem !important; +} + +.py-0\.5 { + padding-top: 0.125rem !important; + padding-bottom: 0.125rem !important; +} From f9b4460e70d21de0e82ee272492d0bd5c1d653a3 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 26 Sep 2023 12:02:55 +0200 Subject: [PATCH 142/282] Themed LangSwitchComponent --- src/app/header/header.component.html | 2 +- .../lang-switch/lang-switch.component.ts | 2 +- .../themed-lang-switch.component.ts | 27 +++++++++++++++++++ src/app/shared/shared.module.ts | 2 ++ .../lang-switch/lang-switch.component.html | 0 .../lang-switch/lang-switch.component.scss | 0 .../lang-switch/lang-switch.component.ts | 12 +++++++++ src/themes/custom/eager-theme.module.ts | 2 ++ .../dspace/app/header/header.component.html | 2 +- .../dspace/app/navbar/navbar.component.html | 2 +- 10 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/app/shared/lang-switch/themed-lang-switch.component.ts create mode 100644 src/themes/custom/app/shared/lang-switch/lang-switch.component.html create mode 100644 src/themes/custom/app/shared/lang-switch/lang-switch.component.scss create mode 100644 src/themes/custom/app/shared/lang-switch/lang-switch.component.ts diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index 425f52c6017..32b42dc8a7c 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -7,7 +7,7 @@ <nav role="navigation" [attr.aria-label]="'nav.user.description' | translate" class="navbar navbar-light navbar-expand-md flex-shrink-0 px-0"> <ds-themed-search-navbar></ds-themed-search-navbar> - <ds-lang-switch></ds-lang-switch> + <ds-themed-lang-switch></ds-themed-lang-switch> <ds-context-help-toggle></ds-context-help-toggle> <ds-themed-auth-nav-menu></ds-themed-auth-nav-menu> <ds-impersonate-navbar></ds-impersonate-navbar> diff --git a/src/app/shared/lang-switch/lang-switch.component.ts b/src/app/shared/lang-switch/lang-switch.component.ts index d2c70839c0e..e3c5e919caa 100644 --- a/src/app/shared/lang-switch/lang-switch.component.ts +++ b/src/app/shared/lang-switch/lang-switch.component.ts @@ -33,7 +33,7 @@ export class LangSwitchComponent implements OnInit { this.activeLangs = environment.languages.filter((MyLangConfig) => MyLangConfig.active === true); this.moreThanOneLanguage = (this.activeLangs.length > 1); if (!this.moreThanOneLanguage) { - this.el.nativeElement.style.display = 'none'; + this.el.nativeElement.parentElement.classList.add('d-none'); } } diff --git a/src/app/shared/lang-switch/themed-lang-switch.component.ts b/src/app/shared/lang-switch/themed-lang-switch.component.ts new file mode 100644 index 00000000000..8be34474267 --- /dev/null +++ b/src/app/shared/lang-switch/themed-lang-switch.component.ts @@ -0,0 +1,27 @@ +import { Component } from '@angular/core'; +import { ThemedComponent } from '../theme-support/themed.component'; +import { LangSwitchComponent } from './lang-switch.component'; + +/** + * Themed wrapper for {@link LangSwitchComponent} + */ +@Component({ + selector: 'ds-themed-lang-switch', + styleUrls: [], + templateUrl: '../theme-support/themed.component.html', +}) +export class ThemedLangSwitchComponent extends ThemedComponent<LangSwitchComponent> { + + protected getComponentName(): string { + return 'LangSwitchComponent'; + } + + protected importThemedComponent(themeName: string): Promise<any> { + return import(`../../../themes/${themeName}/app/shared/lang-switch/lang-switch.component`); + } + + protected importUnthemedComponent(): Promise<any> { + return import(`./lang-switch.component`); + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9b..b21712f4824 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 { ThemedLangSwitchComponent } from './lang-switch/themed-lang-switch.component'; const MODULES = [ CommonModule, @@ -335,6 +336,7 @@ const COMPONENTS = [ DsSelectComponent, ErrorComponent, LangSwitchComponent, + ThemedLangSwitchComponent, LoadingComponent, ThemedLoadingComponent, LogInComponent, diff --git a/src/themes/custom/app/shared/lang-switch/lang-switch.component.html b/src/themes/custom/app/shared/lang-switch/lang-switch.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/lang-switch/lang-switch.component.scss b/src/themes/custom/app/shared/lang-switch/lang-switch.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/lang-switch/lang-switch.component.ts b/src/themes/custom/app/shared/lang-switch/lang-switch.component.ts new file mode 100644 index 00000000000..fe803949dbc --- /dev/null +++ b/src/themes/custom/app/shared/lang-switch/lang-switch.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { LangSwitchComponent as BaseComponent } from '../../../../../app/shared/lang-switch/lang-switch.component'; + +@Component({ + selector: 'ds-lang-switch', + // styleUrls: ['./lang-switch.component.scss'], + styleUrls: ['../../../../../app/shared/lang-switch/lang-switch.component.scss'], + // templateUrl: './lang-switch.component.html', + templateUrl: '../../../../../app/shared/lang-switch/lang-switch.component.html', +}) +export class LangSwitchComponent extends BaseComponent { +} diff --git a/src/themes/custom/eager-theme.module.ts b/src/themes/custom/eager-theme.module.ts index 7d7f5b3d8b4..a181487ea7a 100644 --- a/src/themes/custom/eager-theme.module.ts +++ b/src/themes/custom/eager-theme.module.ts @@ -54,6 +54,7 @@ import { ItemSearchResultListElementComponent } from './app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TopLevelCommunityListComponent } from './app/home-page/top-level-community-list/top-level-community-list.component'; +import { LangSwitchComponent } from './app/shared/lang-switch/lang-switch.component'; /** @@ -91,6 +92,7 @@ const DECLARATIONS = [ EditCollectionSelectorComponent, EditCommunitySelectorComponent, EditItemSelectorComponent, + LangSwitchComponent, ]; @NgModule({ diff --git a/src/themes/dspace/app/header/header.component.html b/src/themes/dspace/app/header/header.component.html index dbc98098ae5..87a26ca326a 100644 --- a/src/themes/dspace/app/header/header.component.html +++ b/src/themes/dspace/app/header/header.component.html @@ -7,7 +7,7 @@ </div> <div class="d-flex flex-grow-1 ml-auto justify-content-end align-items-center"> <ds-themed-search-navbar></ds-themed-search-navbar> - <ds-lang-switch></ds-lang-switch> + <ds-themed-lang-switch></ds-themed-lang-switch> <ds-context-help-toggle></ds-context-help-toggle> <ds-themed-auth-nav-menu></ds-themed-auth-nav-menu> <ds-impersonate-navbar></ds-impersonate-navbar> diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index 05afac7d7e9..c2e3286ed07 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -16,7 +16,7 @@ </ul> </div> <ds-search-navbar class="navbar-collapsed"></ds-search-navbar> - <ds-lang-switch class="navbar-collapsed"></ds-lang-switch> + <ds-themed-lang-switch class="navbar-collapsed"></ds-themed-lang-switch> <ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle> <ds-themed-auth-nav-menu class="navbar-collapsed"></ds-themed-auth-nav-menu> <ds-impersonate-navbar class="navbar-collapsed"></ds-impersonate-navbar> From 58d31dd73f9762a341e774df261d909d97c4b3e2 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 26 Sep 2023 22:16:25 +0200 Subject: [PATCH 143/282] 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 @@ <form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on" class="d-flex"> <input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query" formControlName="query" type="text" placeholder="{{searchExpanded ? ('nav.search' | translate) : ''}}" - class="d-inline-block bg-transparent position-absolute form-control dropdown-menu-right pl-1" [attr.data-test]="'header-search-box' | dsBrowserOnly"> + 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"> <button class="submit-icon btn btn-link btn-link-inline" [attr.aria-label]="'nav.search.button' | translate" type="button" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly"> <em class="fas fa-search fa-lg fa-fw"></em> </button> 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 @@ <img src="assets/images/dspace-logo.svg" [attr.alt]="'menu.header.image.logo' | translate"/> </a> </div> - <div class="d-flex flex-grow-1 ml-auto justify-content-end align-items-center"> + <div class="navbar-buttons d-flex flex-grow-1 ml-auto justify-content-end align-items-center"> <ds-themed-search-navbar></ds-themed-search-navbar> <ds-themed-lang-switch></ds-themed-lang-switch> <ds-context-help-toggle></ds-context-help-toggle> diff --git a/src/themes/dspace/app/header/header.component.scss b/src/themes/dspace/app/header/header.component.scss index 2fc857826f9..14c46a2316a 100644 --- a/src/themes/dspace/app/header/header.component.scss +++ b/src/themes/dspace/app/header/header.component.scss @@ -24,3 +24,9 @@ color: var(--ds-header-icon-color-hover); } } + +.navbar-buttons { + display: flex; + gap: calc(var(--bs-spacer) / 3); + align-items: center; +} diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index c2e3286ed07..d9631aad182 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -15,10 +15,12 @@ </ng-container> </ul> </div> - <ds-search-navbar class="navbar-collapsed"></ds-search-navbar> - <ds-themed-lang-switch class="navbar-collapsed"></ds-themed-lang-switch> - <ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle> - <ds-themed-auth-nav-menu class="navbar-collapsed"></ds-themed-auth-nav-menu> - <ds-impersonate-navbar class="navbar-collapsed"></ds-impersonate-navbar> + <div class="navbar-buttons"> + <ds-themed-search-navbar class="navbar-collapsed"></ds-themed-search-navbar> + <ds-themed-lang-switch class="navbar-collapsed"></ds-themed-lang-switch> + <ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle> + <ds-themed-auth-nav-menu class="navbar-collapsed"></ds-themed-auth-nav-menu> + <ds-impersonate-navbar class="navbar-collapsed"></ds-impersonate-navbar> + </div> </div> </nav> 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 <alexandre@atmire.com> Date: Thu, 28 Sep 2023 11:50:24 +0200 Subject: [PATCH 144/282] 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 @@ <h4 class="section-header-text mb-0">{{ 'menu.header.admin' | translate }}</h4> </div> </li> - <ng-container *ngFor="let section of (sections | async)"> + <li *ngFor="let section of (sections | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container> - </ng-container> + </li> </ul> </div> <div class="navbar-nav"> diff --git a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts index 4555c0fa938..8591fef97eb 100644 --- a/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts +++ b/src/app/admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component.ts @@ -15,8 +15,7 @@ import { Router } from '@angular/router'; * Represents a expandable section in the sidebar */ @Component({ - /* eslint-disable @angular-eslint/component-selector */ - selector: 'li[ds-expandable-admin-sidebar-section]', + selector: 'ds-expandable-admin-sidebar-section', templateUrl: './expandable-admin-sidebar-section.component.html', styleUrls: ['./expandable-admin-sidebar-section.component.scss'], animations: [rotate, slide, bgColor] diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html index b5023261647..053968834e1 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html @@ -14,9 +14,9 @@ </a> <ul @slide *ngIf="(active | async)" (click)="deactivateSection($event)" class="m-0 shadow-none border-top-0 dropdown-menu show"> - <ng-container *ngFor="let subSection of (subSections$ | async)"> + <li *ngFor="let subSection of (subSections$ | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(subSection.id).component; injector: (sectionMap$ | async).get(subSection.id).injector;"></ng-container> - </ng-container> + </li> </ul> </div> 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 @@ <li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)"> <ds-user-menu [inExpandableNavbar]="true"></ds-user-menu> </li> - <ng-container *ngFor="let section of (sections | async)"> + <li *ngFor="let section of (sections | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container> - </ng-container> + </li> </ul> </div> </div> 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 @@ <li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)"> <ds-user-menu [inExpandableNavbar]="true"></ds-user-menu> </li> - <ng-container *ngFor="let section of (sections | async)"> + <li *ngFor="let section of (sections | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container> - </ng-container> + </li> </ul> </div> <div class="navbar-buttons"> From 3c5079e9ce9dcadcc1fc99bfd872b65ffbe336f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 00:34:17 +0000 Subject: [PATCH 145/282] Bump postcss from 8.4.23 to 8.4.31 Bumps [postcss](https://github.com/postcss/postcss) from 8.4.23 to 8.4.31. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.23...8.4.31) --- updated-dependencies: - dependency-name: postcss dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index c5a82d9e75d..37ba5b84723 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9283,7 +9283,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@8.4.21, postcss@^8.2.14, postcss@^8.3.11, postcss@^8.3.7, postcss@^8.4.19: +postcss@8.4.21: version "8.4.21" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz" integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== @@ -9309,10 +9309,10 @@ postcss@^7.0.14: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.4: - version "8.4.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" - integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== +postcss@^8.2.14, postcss@^8.3.11, postcss@^8.3.7, postcss@^8.4, postcss@^8.4.19: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" From 0139670371ffd7d8530f3d93ce9f120bc687433c Mon Sep 17 00:00:00 2001 From: Janne Jensen <micrograph@posteo.de> Date: Sat, 7 Oct 2023 10:43:09 +0200 Subject: [PATCH 146/282] translate community as 'Bereich' in de.json5 --- src/assets/i18n/de.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/de.json5 b/src/assets/i18n/de.json5 index 5ab57cf3e6e..c185a13432b 100644 --- a/src/assets/i18n/de.json5 +++ b/src/assets/i18n/de.json5 @@ -1382,7 +1382,7 @@ // "community.create.head": "Create a Community", - "community.create.head": "Sammlung anlegen", + "community.create.head": "Bereich anlegen", // "community.create.notifications.success": "Successfully created the Community", "community.create.notifications.success": "Bereich erfolgreich angelegt", From b321d6f72778aef9c47901f13c2e99195aea8530 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Wed, 11 Oct 2023 13:02:13 +0200 Subject: [PATCH 147/282] [DURACOM-190] Fix i18n labels in vocabulary-treeview --- .../vocabulary-treeview.component.html | 2 +- .../vocabulary-treeview.component.ts | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index fb7d1620082..64442b258d5 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -1,4 +1,4 @@ -<ds-alert *ngIf="description | async" [content]="description | async" [type]="'alert-info'"></ds-alert> +<ds-alert [content]="'vocabulary-treeview.info' | translate" [type]="'alert-info'"></ds-alert> <div class="treeview-header row"> <div class="col-12"> <div class="input-group"> diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts index 13d4495e614..804ae634913 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts @@ -1,7 +1,6 @@ import { FlatTreeControl } from '@angular/cdk/tree'; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, OnChanges, SimpleChanges } from '@angular/core'; -import { map } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; @@ -16,7 +15,6 @@ import { VocabularyEntry } from '../../../core/submission/vocabularies/models/vo import { VocabularyTreeFlattener } from './vocabulary-tree-flattener'; import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source'; import { CoreState } from '../../../core/core-state.model'; -import { lowerCase } from 'lodash/string'; import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service'; import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; @@ -50,11 +48,6 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges */ @Input() multiSelect = false; - /** - * Contain a descriptive message for this vocabulary retrieved from i18n files - */ - description: Observable<string>; - /** * A map containing the current node showed by the tree */ @@ -216,12 +209,6 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges }) ); - this.translate.get(`search.filters.filter.${this.vocabularyOptions.name}.head`).pipe( - map((type) => lowerCase(type)), - ).subscribe( - (type) => this.description = this.translate.get('vocabulary-treeview.info', { type }) - ); - this.loading = this.vocabularyTreeviewService.isLoading(); this.vocabularyTreeviewService.initialize(this.vocabularyOptions, new PageInfo(), this.selectedItems, null); From 0d376a6607633c04a867b6602b56f16eb2bf98a6 Mon Sep 17 00:00:00 2001 From: Marie Verdonck <maria.verdonck@atmire.com> Date: Wed, 4 Oct 2023 17:27:04 +0200 Subject: [PATCH 148/282] Issue#2535: Hide add more button in submission if no disabled sections (cherry picked from commit 709848ee25bca09efbcf4dac8d427ffd42af8e78) --- .../section-add/submission-form-section-add.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/submission/form/section-add/submission-form-section-add.component.html b/src/app/submission/form/section-add/submission-form-section-add.component.html index 939f23209ac..3740de6345d 100644 --- a/src/app/submission/form/section-add/submission-form-section-add.component.html +++ b/src/app/submission/form/section-add/submission-form-section-add.component.html @@ -3,13 +3,14 @@ placement="bottom-right" class="d-inline-block" [ngClass]="{'w-100': windowService.isXs()}"> + <ng-container *ngIf="hasSections$ | async"> <button class="btn btn-outline-primary dropdown-toggle" id="sectionControls" - [disabled]="!(hasSections$ | async)" [ngClass]="{'w-100': (windowService.isXs() | async)}" ngbDropdownToggle> {{ 'submission.sections.general.add-more' | translate }} <i class="fa fa-plus" aria-hidden="true"></i> </button> + </ng-container> <div ngbDropdownMenu class="sections-dropdown-menu" aria-labelledby="sectionControls" From feb2b2be53272cae025f7e02ad9c6a30728ed0d2 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Fri, 13 Oct 2023 11:05:14 +0200 Subject: [PATCH 149/282] [DURACOM-190] Fix alignment in vocabulary-treeview --- .../vocabulary-treeview/vocabulary-treeview.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index 64442b258d5..3b858faac45 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -23,7 +23,7 @@ <h4 *ngIf="!(loading | async) && dataSource.data.length === 0" class="text-cente <!-- Leaf node --> <cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="d-flex"> <button type="button" class="btn btn-default" cdkTreeNodeToggle> - <span class="fas fa-angle-right invisible" aria-hidden="true"></span> + <span class="fas fa-fw fa-angle-right invisible" aria-hidden="true"></span> </button> <label *ngIf="multiSelect" class="d-flex align-items-center m-0 p-0 form-check" [class.text-success]="node.isSelected" @@ -55,7 +55,7 @@ <h4 *ngIf="!(loading | async) && dataSource.data.length === 0" class="text-cente <button type="button" class="btn btn-default" cdkTreeNodeToggle [attr.aria-label]="'toggle ' + node.name" (click)="loadChildren(node)"> - <span class="fas {{treeControl.isExpanded(node) ? 'fa-angle-down' : 'fa-angle-right'}}" + <span class="fas fa-fw {{treeControl.isExpanded(node) ? 'fa-angle-down' : 'fa-angle-right'}}" aria-hidden="true"></span> </button> From fa79c358c09cb52ed142ef122e08b77de880685d Mon Sep 17 00:00:00 2001 From: Flo <33422716+floriangantner@users.noreply.github.com> Date: Tue, 17 Oct 2023 21:17:28 +0200 Subject: [PATCH 150/282] Check cssRules before css variables are read from stylesheet (#2454) Check cssRules existence before css variables are get from stylesheet --- src/app/shared/sass-helper/css-variable.service.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app/shared/sass-helper/css-variable.service.ts b/src/app/shared/sass-helper/css-variable.service.ts index 0190a05036f..ca6384e0ee5 100644 --- a/src/app/shared/sass-helper/css-variable.service.ts +++ b/src/app/shared/sass-helper/css-variable.service.ts @@ -26,6 +26,15 @@ export class CSSVariableService { return styleSheet.href.indexOf(window.location.origin) === 0; }; + /** + * Checks whether the specific stylesheet object has the property cssRules + * @param styleSheet The stylesheet + */ + hasCssRules = (styleSheet) => { + // Injected styles might have no css rules value + return styleSheet.hasOwnProperty('cssRules') && styleSheet.cssRules; + }; + /* Determine if the given rule is a CSSStyleRule See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants @@ -93,8 +102,10 @@ export class CSSVariableService { if (isNotEmpty(document.styleSheets)) { // styleSheets is array-like, so we convert it to an array. // Filter out any stylesheets not on this domain + // Filter out any stylesheets that have no cssRules property return [...document.styleSheets] .filter(this.isSameDomain) + .filter(this.hasCssRules) .reduce( (finalArr, sheet) => finalArr.concat( From 97f7a5e82aa30a41d64974fe4c553bd3358dc6b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 01:56:32 +0000 Subject: [PATCH 151/282] Bump @babel/traverse from 7.21.4 to 7.23.2 Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.4 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> --- yarn.lock | 119 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 16 deletions(-) diff --git a/yarn.lock b/yarn.lock index 37ba5b84723..dff9302cc72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -451,13 +451,21 @@ resolved "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz" integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.21.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": version "7.21.4" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz" integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.21.4": version "7.21.4" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz" @@ -535,7 +543,7 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/generator@^7.18.9", "@babel/generator@^7.19.3", "@babel/generator@^7.21.4": +"@babel/generator@^7.18.9", "@babel/generator@^7.19.3": version "7.21.4" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz" integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA== @@ -545,6 +553,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" + integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== + dependencies: + "@babel/types" "^7.23.0" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@7.18.6", "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" @@ -610,6 +628,11 @@ resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + "@babel/helper-explode-assignable-expression@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" @@ -625,6 +648,14 @@ "@babel/template" "^7.20.7" "@babel/types" "^7.21.0" +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" @@ -632,6 +663,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": version "7.21.0" resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz" @@ -715,16 +753,33 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.19.4": version "7.19.4" resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + "@babel/helper-validator-option@^7.18.6", "@babel/helper-validator-option@^7.21.0": version "7.21.0" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz" @@ -758,11 +813,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.3", "@babel/parser@^7.14.7", "@babel/parser@^7.18.9", "@babel/parser@^7.19.3", "@babel/parser@^7.20.7", "@babel/parser@^7.21.4": +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.10.3", "@babel/parser@^7.14.7", "@babel/parser@^7.18.9", "@babel/parser@^7.19.3", "@babel/parser@^7.20.7": version "7.21.4" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz" integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" @@ -1403,19 +1472,28 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" -"@babel/traverse@^7.10.3", "@babel/traverse@^7.18.9", "@babel/traverse@^7.19.3", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2": - version "7.21.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz" - integrity sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q== +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== dependencies: - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.4" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.4" - "@babel/types" "^7.21.4" + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.10.3", "@babel/traverse@^7.18.9", "@babel/traverse@^7.19.3", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.0" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.0" + "@babel/types" "^7.23.0" debug "^4.1.0" globals "^11.1.0" @@ -1428,6 +1506,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" @@ -3849,7 +3936,7 @@ chalk@^1.1.1: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== From e0a3f15c007fcf306ee5083c74dd3eed5637b4df Mon Sep 17 00:00:00 2001 From: Yana De Pauw <yana@atmire.com> Date: Mon, 18 Sep 2023 16:43:32 +0200 Subject: [PATCH 152/282] 106974: Angular SSR menu issues (cherry picked from commit 3e8d180f1b92adc2c69a4f74d864d165150611ea) --- src/app/core/core.effects.ts | 2 ++ src/app/shared/menu/menu.actions.ts | 11 ++++++- src/app/shared/menu/menu.effects.spec.ts | 41 ++++++++++++++++++++++++ src/app/shared/menu/menu.effects.ts | 23 +++++++++++++ src/app/shared/menu/menu.reducer.spec.ts | 13 +++++++- src/app/shared/menu/menu.reducer.ts | 19 ++++++----- src/app/shared/menu/menu.service.spec.ts | 27 ++++++++++++++-- src/app/shared/menu/menu.service.ts | 3 +- 8 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 src/app/shared/menu/menu.effects.spec.ts create mode 100644 src/app/shared/menu/menu.effects.ts diff --git a/src/app/core/core.effects.ts b/src/app/core/core.effects.ts index b569df290d5..1724e88743b 100644 --- a/src/app/core/core.effects.ts +++ b/src/app/core/core.effects.ts @@ -7,6 +7,7 @@ import { ServerSyncBufferEffects } from './cache/server-sync-buffer.effects'; import { ObjectUpdatesEffects } from './data/object-updates/object-updates.effects'; import { RouteEffects } from './services/route.effects'; import { RouterEffects } from './router/router.effects'; +import { MenuEffects } from '../shared/menu/menu.effects'; export const coreEffects = [ RequestEffects, @@ -18,4 +19,5 @@ export const coreEffects = [ ObjectUpdatesEffects, RouteEffects, RouterEffects, + MenuEffects, ]; diff --git a/src/app/shared/menu/menu.actions.ts b/src/app/shared/menu/menu.actions.ts index f02fd73292e..268c149c5ba 100644 --- a/src/app/shared/menu/menu.actions.ts +++ b/src/app/shared/menu/menu.actions.ts @@ -18,6 +18,7 @@ export const MenuActionTypes = { EXPAND_MENU: type('dspace/menu/EXPAND_MENU'), SHOW_MENU: type('dspace/menu/SHOW_MENU'), HIDE_MENU: type('dspace/menu/HIDE_MENU'), + REINIT_MENUS: type('dspace/menu/REINIT_MENUS'), COLLAPSE_MENU_PREVIEW: type('dspace/menu/COLLAPSE_MENU_PREVIEW'), EXPAND_MENU_PREVIEW: type('dspace/menu/EXPAND_MENU_PREVIEW'), ADD_SECTION: type('dspace/menu-section/ADD_SECTION'), @@ -115,6 +116,13 @@ export class ExpandMenuPreviewAction implements Action { } } +/** + * Action used to re-initialise the menus + */ +export class ReinitMenuAction implements Action { + type = MenuActionTypes.REINIT_MENUS; +} + // MENU SECTION ACTIONS /** * Action used to perform state changes for a section of a certain menu @@ -224,4 +232,5 @@ export type MenuAction = | DeactivateMenuSectionAction | ToggleActiveMenuSectionAction | CollapseMenuPreviewAction - | ExpandMenuPreviewAction; + | ExpandMenuPreviewAction + | ReinitMenuAction; diff --git a/src/app/shared/menu/menu.effects.spec.ts b/src/app/shared/menu/menu.effects.spec.ts new file mode 100644 index 00000000000..5da53286747 --- /dev/null +++ b/src/app/shared/menu/menu.effects.spec.ts @@ -0,0 +1,41 @@ +import { Observable } from 'rxjs'; +import { TestBed, waitForAsync } from '@angular/core/testing'; +import { provideMockActions } from '@ngrx/effects/testing'; +import { cold, hot } from 'jasmine-marbles'; +import { MenuEffects } from './menu.effects'; +import { ReinitMenuAction } from './menu.actions'; +import { StoreAction, StoreActionTypes } from '../../store.actions'; + +describe('MenuEffects', () => { + let menuEffects: MenuEffects; + let actions: Observable<any>; + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + providers: [ + MenuEffects, + provideMockActions(() => actions), + ], + }); + })); + + beforeEach(() => { + menuEffects = TestBed.inject(MenuEffects); + }); + + describe('reinitDSOMenus', () => { + describe('When a REHYDRATE action is triggered', () => { + let action; + beforeEach(() => { + action = new StoreAction(StoreActionTypes.REHYDRATE, null); + }); + it('should return a ReinitMenuAction', () => { + actions = hot('--a-', {a: action}); + const expected = cold('--b-', {b: new ReinitMenuAction}); + + expect(menuEffects.reinitDSOMenus).toBeObservable(expected); + }); + }); + }); + + +}); diff --git a/src/app/shared/menu/menu.effects.ts b/src/app/shared/menu/menu.effects.ts new file mode 100644 index 00000000000..2787f80b78a --- /dev/null +++ b/src/app/shared/menu/menu.effects.ts @@ -0,0 +1,23 @@ +import { map } from 'rxjs/operators'; +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; + +import { StoreActionTypes } from '../../store.actions'; +import { ReinitMenuAction } from './menu.actions'; + +@Injectable() +export class MenuEffects { + + /** + * When the store is rehydrated in the browser, re-initialise the menus to ensure + * the menus with functions are loaded correctly. + */ + reinitDSOMenus = createEffect(() => this.actions$ + .pipe(ofType(StoreActionTypes.REHYDRATE), + map(() => new ReinitMenuAction()) + )); + + constructor(private actions$: Actions) { + } + +} diff --git a/src/app/shared/menu/menu.reducer.spec.ts b/src/app/shared/menu/menu.reducer.spec.ts index 2865e887fca..8f540c016d5 100644 --- a/src/app/shared/menu/menu.reducer.spec.ts +++ b/src/app/shared/menu/menu.reducer.spec.ts @@ -9,7 +9,7 @@ import { ExpandMenuAction, ExpandMenuPreviewAction, HideMenuAction, - HideMenuSectionAction, + HideMenuSectionAction, ReinitMenuAction, RemoveMenuSectionAction, ShowMenuAction, ShowMenuSectionAction, @@ -317,6 +317,17 @@ describe('menusReducer', () => { // is mutated, and any uncaught exception will cause the test to fail }); + it('should reset the menu state to the initial state when performing the REINIT_MENUS action without affecting the previous state', () => { + dummyState[MenuID.ADMIN].visible = true; + const state = dummyState; + deepFreeze([state]); + + const action = new ReinitMenuAction(); + const menusState = menusReducer(state, action); + expect(menusState).toEqual(initialMenusState); + + }); + it('should set add a new section for the correct menu in response to the ADD_SECTION action', () => { const state = dummyState; const action = new AddMenuSectionAction(menuID, visibleSection1); diff --git a/src/app/shared/menu/menu.reducer.ts b/src/app/shared/menu/menu.reducer.ts index c7ea017cc24..4c9ee31403a 100644 --- a/src/app/shared/menu/menu.reducer.ts +++ b/src/app/shared/menu/menu.reducer.ts @@ -26,36 +26,39 @@ import { MenuID } from './menu-id.model'; * @returns {MenusState} The new, reducer MenusState */ export function menusReducer(state: MenusState = initialMenusState, action: MenuAction): MenusState { - const menuState: MenuState = state[action.menuID]; switch (action.type) { case MenuActionTypes.COLLAPSE_MENU: { - const newMenuState = Object.assign({}, menuState, { collapsed: true }); + const newMenuState = Object.assign({}, state[action.menuID], { collapsed: true }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.EXPAND_MENU: { - const newMenuState = Object.assign({}, menuState, { collapsed: false }); + const newMenuState = Object.assign({}, state[action.menuID], { collapsed: false }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.COLLAPSE_MENU_PREVIEW: { - const newMenuState = Object.assign({}, menuState, { previewCollapsed: true }); + const newMenuState = Object.assign({}, state[action.menuID], { previewCollapsed: true }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.EXPAND_MENU_PREVIEW: { - const newMenuState = Object.assign({}, menuState, { previewCollapsed: false }); + const newMenuState = Object.assign({}, state[action.menuID], { previewCollapsed: false }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.TOGGLE_MENU: { + const menuState = state[action.menuID]; const newMenuState = Object.assign({}, menuState, { collapsed: !menuState.collapsed }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.SHOW_MENU: { - const newMenuState = Object.assign({}, menuState, { visible: true }); + const newMenuState = Object.assign({}, state[action.menuID], { visible: true }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } case MenuActionTypes.HIDE_MENU: { - const newMenuState = Object.assign({}, menuState, { visible: false }); + const newMenuState = Object.assign({}, state[action.menuID], { visible: false }); return Object.assign({}, state, { [action.menuID]: newMenuState }); } + case MenuActionTypes.REINIT_MENUS: { + return Object.assign({}, initialMenusState); + } case MenuActionTypes.ADD_SECTION: { return addSection(state, action as AddMenuSectionAction); } @@ -230,7 +233,7 @@ function toggleActiveSection(state: MenusState, action: ToggleActiveMenuSectionA * @param {MenuSection} section The section that will be added or replaced in the state * @returns {MenusState} The new reduced state */ -function putSectionState(state: MenusState, action: MenuAction, section: MenuSection): MenusState { +function putSectionState(state: MenusState, action: MenuSectionAction, section: MenuSection): MenusState { const menuState: MenuState = state[action.menuID]; const newSections = Object.assign({}, menuState.sections, { [section.id]: section diff --git a/src/app/shared/menu/menu.service.spec.ts b/src/app/shared/menu/menu.service.spec.ts index 0d8d669a0aa..6af7c54d58c 100644 --- a/src/app/shared/menu/menu.service.spec.ts +++ b/src/app/shared/menu/menu.service.spec.ts @@ -41,6 +41,7 @@ describe('MenuService', () => { let routeDataMenuSection: MenuSection; let routeDataMenuSectionResolved: MenuSection; let routeDataMenuChildSection: MenuSection; + let routeDataMenuOverwrittenChildSection: MenuSection; let toBeRemovedMenuSection: MenuSection; let alreadyPresentMenuSection: MenuSection; let route; @@ -127,6 +128,17 @@ describe('MenuService', () => { link: '' } as LinkMenuItemModel }; + routeDataMenuOverwrittenChildSection = { + id: 'mockChildSection', + parentID: 'mockSection', + active: false, + visible: true, + model: { + type: MenuItemType.LINK, + text: 'menu.section.mockChildOverwrittenSection', + link: '' + } as LinkMenuItemModel + }; toBeRemovedMenuSection = { id: 'toBeRemovedSection', active: false, @@ -167,7 +179,17 @@ describe('MenuService', () => { [MenuID.PUBLIC]: routeDataMenuChildSection } } + }, + firstChild: { + snapshot: { + data: { + menu: { + [MenuID.PUBLIC]: routeDataMenuOverwrittenChildSection + } + } + } } + } } }; @@ -541,7 +563,7 @@ describe('MenuService', () => { }); describe('buildRouteMenuSections', () => { - it('should add and remove menu sections depending on the current route', () => { + it('should add and remove menu sections depending on the current route and overwrite menu sections when they have the same ID with the child route version', () => { spyOn(service, 'addSection'); spyOn(service, 'removeSection'); @@ -550,7 +572,8 @@ describe('MenuService', () => { service.buildRouteMenuSections(MenuID.PUBLIC); expect(service.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuSectionResolved); - expect(service.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuChildSection); + expect(service.addSection).not.toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuChildSection); + expect(service.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuOverwrittenChildSection); expect(service.addSection).not.toHaveBeenCalledWith(MenuID.PUBLIC, alreadyPresentMenuSection); expect(service.removeSection).toHaveBeenCalledWith(MenuID.PUBLIC, toBeRemovedMenuSection.id); }); diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts index fac3b3fba70..0ec7d67f252 100644 --- a/src/app/shared/menu/menu.service.ts +++ b/src/app/shared/menu/menu.service.ts @@ -399,7 +399,8 @@ export class MenuService { } if (!last) { - return [...menuSections, ...this.resolveRouteMenuSections(route.firstChild, menuID)]; + const childMenuSections = this.resolveRouteMenuSections(route.firstChild, menuID); + return [...menuSections.filter(menu => !(childMenuSections).map(childMenu => childMenu.id).includes(menu.id)), ...childMenuSections]; } else { return [...menuSections]; } From 2e571767ea2d2e7eff1ed2b928480ddc1806dd6f Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Thu, 19 Oct 2023 23:01:24 +0200 Subject: [PATCH 153/282] 107664: Normalized ePerson & group edit url and moved error message to translation file --- src/app/access-control/access-control-routing-paths.ts | 4 ++-- src/app/access-control/access-control-routing.module.ts | 4 ++-- .../epeople-registry/epeople-registry.component.ts | 2 +- src/assets/i18n/en.json5 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/access-control/access-control-routing-paths.ts b/src/app/access-control/access-control-routing-paths.ts index c8b9e01793f..31f39f1c47d 100644 --- a/src/app/access-control/access-control-routing-paths.ts +++ b/src/app/access-control/access-control-routing-paths.ts @@ -8,7 +8,7 @@ export function getEPersonsRoute(): string { } export function getEPersonEditRoute(id: string): string { - return new URLCombiner(getEPersonsRoute(), id).toString(); + return new URLCombiner(getEPersonsRoute(), id, 'edit').toString(); } export const GROUP_PATH = 'groups'; @@ -18,5 +18,5 @@ export function getGroupsRoute() { } export function getGroupEditRoute(id: string) { - return new URLCombiner(getGroupsRoute(), id).toString(); + return new URLCombiner(getGroupsRoute(), id, 'edit').toString(); } diff --git a/src/app/access-control/access-control-routing.module.ts b/src/app/access-control/access-control-routing.module.ts index 4ef97cb5eab..97d049ad836 100644 --- a/src/app/access-control/access-control-routing.module.ts +++ b/src/app/access-control/access-control-routing.module.ts @@ -38,7 +38,7 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; canActivate: [SiteAdministratorGuard], }, { - path: `${EPERSON_PATH}/:id`, + path: `${EPERSON_PATH}/:id/edit`, component: EPersonFormComponent, resolve: { breadcrumb: I18nBreadcrumbResolver, @@ -66,7 +66,7 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service'; canActivate: [GroupAdministratorGuard] }, { - path: `${GROUP_PATH}/:groupId`, + path: `${GROUP_PATH}/:groupId/edit`, 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 d2837a5317e..4596eec98e3 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 occurred when trying to delete EPerson with id: ${ePerson.id} with code: ${restResponse.statusCode} and message: ${restResponse.errorMessage}`); + this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { id: ePerson.id, statusCode: restResponse.statusCode, errorMessage: restResponse.errorMessage })); } }); } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 2a552296163..94780b97683 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -334,7 +334,7 @@ "admin.access-control.epeople.form.goToGroups": "Add to groups", - "admin.access-control.epeople.notification.deleted.failure": "Failed to delete EPerson: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.failure": "Error occurred when trying to delete EPerson with id \"{{id}}\" with code: \"{{statusCode}}\" and message: \"{{restResponse.errorMessage}}\"", "admin.access-control.epeople.notification.deleted.success": "Successfully deleted EPerson: \"{{name}}\"", From ad12e5a7f2c72dfed5dd0b2e3e12d0b9c7457874 Mon Sep 17 00:00:00 2001 From: imilos <imilos@gmail.com> Date: Fri, 20 Oct 2023 11:00:11 +0200 Subject: [PATCH 154/282] Added Serbian cyrilic translation and corrected Serbian latin translation. --- config/config.example.yml | 3 + src/assets/i18n/sr-cyr.json5 | 2616 ++++++++++++++++++++++++++++++ src/assets/i18n/sr-lat.json5 | 12 +- src/config/default-app-config.ts | 1 + 4 files changed, 2626 insertions(+), 6 deletions(-) create mode 100644 src/assets/i18n/sr-cyr.json5 diff --git a/config/config.example.yml b/config/config.example.yml index d73a68e8aa3..69a9ffd320f 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -235,6 +235,9 @@ languages: - code: el label: Ελληνικά active: true + - code: sr-cyr + label: Српски + active: true - code: uk label: Yкраї́нська active: true diff --git a/src/assets/i18n/sr-cyr.json5 b/src/assets/i18n/sr-cyr.json5 new file mode 100644 index 00000000000..5f2dc12f358 --- /dev/null +++ b/src/assets/i18n/sr-cyr.json5 @@ -0,0 +1,2616 @@ +{ + // Initial version provided by University of Kragujevac, Serbia 2023. + "401.help": "Нисте овлашћени да приступите овој страници. Можете користити дугме испод да се вратите на почетну страницу.", + "401.link.home-page": "Одведи ме на почетну страницу", + "401.unauthorized": "Неовлашћен приступ", + "403.help": "Немате дозволу да приступите овој страници. Можете користити дугме испод да се вратите на почетну страницу.", + "403.link.home-page": "Одведи ме на почетну страницу", + "403.forbidden": "Забрањен приступ", + "500.page-internal-server-error": "Услуга није доступна", + "500.help": "Сервер привремено није у могућности да сервисира ваш захтев због застоја у одржавању или проблема са капацитетом. Покушајте поново касније.", + "500.link.home-page": "Одведи ме на почетну страницу", + "404.help": "Не можемо да пронађемо страницу коју тражите. Страница је можда премештена или избрисана. Можете користити дугме испод да се вратите на почетну страницу.", + "404.link.home-page": "Одведи ме на почетну страницу", + "404.page-not-found": "Страница није пронађена", + "error-page.description.401": "Неовлашћен приступ", + "error-page.description.403": "Забрањен приступ", + "error-page.description.500": "Услуга није доступна", + "error-page.description.404": "Страница није пронађена", + "error-page.orcid.generic-error": "Дошло је до грешке приликом пријављивања преко ORCID-а. Уверите се да сте поделили имејл адресу свог ORCID налога са DSpace-ом. Ако грешка и даље постоји, контактирајте администратора", + "access-status.embargo.listelement.badge": "Ембарго", + "access-status.metadata.only.listelement.badge": "Само метаподаци", + "access-status.open.access.listelement.badge": "Отворен приступ", + "access-status.restricted.listelement.badge": "Ограничен приступ", + "access-status.unknown.listelement.badge": "Непознато", + "admin.curation-tasks.breadcrumbs": "Задаци курирања система", + "admin.curation-tasks.title": "Задаци курирања система", + "admin.curation-tasks.header": "Задаци курирања система", + "admin.registries.bitstream-formats.breadcrumbs": "Форматирајте регистар", + "admin.registries.bitstream-formats.create.breadcrumbs": "Формат битстрим-а", + "admin.registries.bitstream-formats.create.failure.content": "Дошло је до грешке при креирању новог формата битстрим-а.", + "admin.registries.bitstream-formats.create.failure.head": "Неуспешно", + "admin.registries.bitstream-formats.create.head": "Креирајте формат битстрим-а", + "admin.registries.bitstream-formats.create.new": "Додајте нови формат битстрим-а", + "admin.registries.bitstream-formats.create.success.content": "Нови формат битстрим-а је успешно креиран.", + "admin.registries.bitstream-formats.create.success.head": "Успешно", + "admin.registries.bitstream-formats.delete.failure.amount": "Уклањање {{ amount }} формата није успело", + "admin.registries.bitstream-formats.delete.failure.head": "Неуспешно", + "admin.registries.bitstream-formats.delete.success.amount": "Успешно уклоњен {{ amount }} формат", + "admin.registries.bitstream-formats.delete.success.head": "Успешно", + "admin.registries.bitstream-formats.description": "Ова листа формата битстрим-а пружа информације о познатим форматима и нивоу њихове подршке.", + "admin.registries.bitstream-formats.edit.breadcrumbs": "Формат битстрим-а", + "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.label": "Опис", + "admin.registries.bitstream-formats.edit.extensions.hint": "Екстензије су екстензије фајлова које се користе за аутоматску идентификацију формата отпремљених фајлова. Можете да унесете неколико екстензија за сваки формат.", + "admin.registries.bitstream-formats.edit.extensions.label": "Екстензије фајлова", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Унесите екстензију фајла без тачке", + "admin.registries.bitstream-formats.edit.failure.content": "Дошло је до грешке при уређивању формата битстрим-а", + "admin.registries.bitstream-formats.edit.failure.head": "Неуспешно", + "admin.registries.bitstream-formats.edit.head": "Формат битстрим-а: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint": "Формати означени као интерни су скривени од корисника и користе се у административне сврхе.", + "admin.registries.bitstream-formats.edit.internal.label": "Унутрашње", + "admin.registries.bitstream-formats.edit.mimetype.hint": "MIME тип повезан са овим форматом не мора бити јединствен.", + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME тип", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "Јединствено име за овај формат, (нпр. Microsoft Word XP или Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Име", + "admin.registries.bitstream-formats.edit.success.content": "Формат битстрим-а је успешно измењен.", + "admin.registries.bitstream-formats.edit.success.head": "Успешно", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "Ниво подршке коју ваша институција обећава за овај формат.", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Ниво подршке", + "admin.registries.bitstream-formats.head": "Регистар формата битстрим-а", + "admin.registries.bitstream-formats.no-items": "Нема формата битова за приказ.", + "admin.registries.bitstream-formats.table.delete": "Избриши изабрано", + "admin.registries.bitstream-formats.table.deselect-all": "Поништите све", + "admin.registries.bitstream-formats.table.internal": "Унутрашње", + "admin.registries.bitstream-formats.table.mimetype": "MIME тип", + "admin.registries.bitstream-formats.table.name": "Име", + "admin.registries.bitstream-formats.table.id": "ID", + "admin.registries.bitstream-formats.table.return": "Назад", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Познато", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Подржано", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Непознато", + "admin.registries.bitstream-formats.table.supportLevel.head": "Ниво подршке", + "admin.registries.bitstream-formats.title": "Регистар формата битстрим-а", + "admin.registries.metadata.breadcrumbs": "Регистар метаподатака", + "admin.registries.metadata.description": "Регистар метаподатака одржава листу свих поља метаподатака доступних у спремишту. Ова поља могу бити подељена на више шема. Међутим, DSpace захтева квалификовану Dublin Core шему", + "admin.registries.metadata.form.create": "Креирајте шему метаподатака", + "admin.registries.metadata.form.edit": "Уредите шему метаподатака", + "admin.registries.metadata.form.name": "Име", + "admin.registries.metadata.form.namespace": "Простор имена", + "admin.registries.metadata.head": "Регистар метаподатака", + "admin.registries.metadata.schemas.no-items": "Нема шема метаподатака за приказ.", + "admin.registries.metadata.schemas.table.delete": "Избриши изабрано", + "admin.registries.metadata.schemas.table.id": "ID", + "admin.registries.metadata.schemas.table.name": "Име", + "admin.registries.metadata.schemas.table.namespace": "Простор имена", + "admin.registries.metadata.title": "Регистар метаподатака", + "admin.registries.schema.breadcrumbs": "Шема метаподатака", + "admin.registries.schema.description": "Ово је шема метаподатака за \"{{namespace}}\".", + "admin.registries.schema.fields.head": "Поља метаподатака шеме", + "admin.registries.schema.fields.no-items": "Нема поља метаподатака за приказ.", + "admin.registries.schema.fields.table.delete": "Избриши изабрано", + "admin.registries.schema.fields.table.field": "Поље", + "admin.registries.schema.fields.table.id": "ID", + "admin.registries.schema.fields.table.scopenote": "Сцопе напомена", + "admin.registries.schema.form.create": "Креирајте поље за метаподатке", + "admin.registries.schema.form.edit": "Измените поље за метаподатке", + "admin.registries.schema.form.element": "Елемент", + "admin.registries.schema.form.qualifier": "Квалификатор", + "admin.registries.schema.form.scopenote": "Сцопе напомена", + "admin.registries.schema.head": "Шема метаподатака", + "admin.registries.schema.notification.created": "Успешно креирана шема метаподатака \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure": "Неуспешно брисање {{amount}} шема метаподатака", + "admin.registries.schema.notification.deleted.success": "Успешно избрисане {{amount}} шеме метаподатака", + "admin.registries.schema.notification.edited": "Успешно измењена шема метаподатака \"{{prefix}}\"", + "admin.registries.schema.notification.failure": "Грешка", + "admin.registries.schema.notification.field.created": "Успешно креирано поље метаподатака \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure": "Неуспешно брисање {{amount}} поља метаподатака", + "admin.registries.schema.notification.field.deleted.success": "Успешно избрисана {{amount}} поља метаподатака", + "admin.registries.schema.notification.field.edited": "Успешно измењено поље метаподатака \"{{field}}\"", + "admin.registries.schema.notification.success": "Успешно", + "admin.registries.schema.return": "Назад", + "admin.registries.schema.title": "Регистар шеме метаподатака", + "admin.access-control.bulk-access.breadcrumbs": "Управљање масовним приступом", + "administrativeBulkAccess.search.results.head": "Резултати претраге", + "admin.access-control.bulk-access": "Управљање масовним приступом", + "admin.access-control.bulk-access.title": "Управљање масовним приступом", + "admin.access-control.bulk-access-browse.header": "Корак 1: Изаберите објекте", + "admin.access-control.bulk-access-browse.search.header": "Претрага", + "admin.access-control.bulk-access-browse.selected.header": "Тренутни избор ({{number}})", + "admin.access-control.bulk-access-settings.header": "Корак 2: Операција коју треба извршити", + "admin.access-control.epeople.actions.delete": "Избришите EPerson", + "admin.access-control.epeople.actions.impersonate": "Опонашати EPerson", + "admin.access-control.epeople.actions.reset": "Ресетујте шифру", + "admin.access-control.epeople.actions.stop-impersonating": "Заустави представљање као 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": "Претрага", + "admin.access-control.epeople.button.see-all": "Прегледајте све", + "admin.access-control.epeople.search.scope.metadata": "Метаподаци", + "admin.access-control.epeople.search.scope.email": "Е-мејл (тачно)", + "admin.access-control.epeople.search.button": "Претрага", + "admin.access-control.epeople.search.placeholder": "Претражите људе...", + "admin.access-control.epeople.button.add": "Додајте EPerson", + "admin.access-control.epeople.table.id": "ID", + "admin.access-control.epeople.table.name": "Име", + "admin.access-control.epeople.table.email": "Е-мејл (тачно)", + "admin.access-control.epeople.table.edit": "Измена", + "admin.access-control.epeople.table.edit.buttons.edit": "Измените \"{{name}}\"", + "admin.access-control.epeople.table.edit.buttons.edit-disabled": "Нисте овлашћени за уређивање ове групе", + "admin.access-control.epeople.table.edit.buttons.remove": "Избришите \"{{name}}\"", + "admin.access-control.epeople.no-items": "Нема EPeople за приказ.", + "admin.access-control.epeople.form.create": "Креирајте EPerson", + "admin.access-control.epeople.form.edit": "Измените EPerson", + "admin.access-control.epeople.form.firstName": "Име", + "admin.access-control.epeople.form.lastName": "Презиме", + "admin.access-control.epeople.form.email": "Е-мејл", + "admin.access-control.epeople.form.emailHint": "Мора бити важећа Е-мејл адреса", + "admin.access-control.epeople.form.canLogIn": "Може се пријавити", + "admin.access-control.epeople.form.requireCertificate": "Потребан је сертификат", + "admin.access-control.epeople.form.return": "Назад", + "admin.access-control.epeople.form.notification.created.success": "Успешно креиран EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure": "Неуспешно креирање EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.created.failure.emailInUse": "Неуспешно креирање EPerson \"{{name}}\", емаил \"{{email}}\" се већ користи.", + "admin.access-control.epeople.form.notification.edited.failure.emailInUse": "Неуспешна измена EPerson \"{{name}}\", емаил \"{{email}}\" се већ користи.", + "admin.access-control.epeople.form.notification.edited.success": "Успешно измењен EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.edited.failure": "Неуспешна измена EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.success": "Успешно избрисан EPerson \"{{name}}\"", + "admin.access-control.epeople.form.notification.deleted.failure": "Неуспешно брисање EPerson \"{{name}}\"", + "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Члан ових група:", + "admin.access-control.epeople.form.table.id": "ID", + "admin.access-control.epeople.form.table.name": "Име", + "admin.access-control.epeople.form.table.collectionOrCommunity": "Колекција/Заједница", + "admin.access-control.epeople.form.memberOfNoGroups": "Овај EPerson није члан ниједне групе", + "admin.access-control.epeople.form.goToGroups": "Додајте групама", + "admin.access-control.epeople.notification.deleted.failure": "Неуспешно брисање EPerson: \"{{name}}\"", + "admin.access-control.epeople.notification.deleted.success": "Успешно избрисан EPerson: \"{{name}}\"", + "admin.access-control.groups.title": "Групе", + "admin.access-control.groups.breadcrumbs": "Групе", + "admin.access-control.groups.singleGroup.breadcrumbs": "Измените групу", + "admin.access-control.groups.title.singleGroup": "Измените групу", + "admin.access-control.groups.title.addGroup": "Нова група", + "admin.access-control.groups.addGroup.breadcrumbs": "Нова група", + "admin.access-control.groups.head": "Групе", + "admin.access-control.groups.button.add": "Додајте групу", + "admin.access-control.groups.search.head": "Претрага група", + "admin.access-control.groups.button.see-all": "Прегледајте све", + "admin.access-control.groups.search.button": "Претрага", + "admin.access-control.groups.search.placeholder": "Претражите групе...", + "admin.access-control.groups.table.id": "ID", + "admin.access-control.groups.table.name": "Име", + "admin.access-control.groups.table.collectionOrCommunity": "Колекција/Заједница", + "admin.access-control.groups.table.members": "Чланови", + "admin.access-control.groups.table.edit": "Изменити", + "admin.access-control.groups.table.edit.buttons.edit": "Измените \"{{name}}\"", + "admin.access-control.groups.table.edit.buttons.remove": "Избришите \"{{name}}\"", + "admin.access-control.groups.no-items": "Није пронађена ниједна група са овим у свом имену или овим као UUID", + "admin.access-control.groups.notification.deleted.success": "Успешно избрисана група \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.title": "Неуспешно брисање групе \"{{name}}\"", + "admin.access-control.groups.notification.deleted.failure.content": "Узрок: \"{{cause}}\"", + "admin.access-control.groups.form.alert.permanent": "Ова група је трајна, тако да се не може мењати или брисати. И даље можете да додајете и уклањате чланове групе користећи ову страницу.", + "admin.access-control.groups.form.alert.workflowGroup": "Ова група се не може изменити или избрисати јер одговара улози у процесу слања и тока посла у \"{{name}}\" {{comcol}}. Можете је избрисати са картице <a href='{{comcolEditRolesRoute}}'>\"додели улоге\"</a> на страници за уређивање {{comcol}}. И даље можете да додајете и уклањате чланове групе користећи ову страницу.", + "admin.access-control.groups.form.head.create": "Креирај групу", + "admin.access-control.groups.form.head.edit": "Измени групу", + "admin.access-control.groups.form.groupName": "Назив групе", + "admin.access-control.groups.form.groupCommunity": "Заједница или колекција", + "admin.access-control.groups.form.groupDescription": "Опис", + "admin.access-control.groups.form.notification.created.success": "Успешно креирана Група \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure": "Неуспешно креирање Групе \"{{name}}\"", + "admin.access-control.groups.form.notification.created.failure.groupNameInUse": "Неуспешно креирање Групе са именом: \"{{name}}\", проверите да име није већ употребљено.", + "admin.access-control.groups.form.notification.edited.failure": "Неуспешна измена Групе \"{{name}}\"", + "admin.access-control.groups.form.notification.edited.failure.groupNameInUse": "Назив \"{{name}}\" се већ користи!", + "admin.access-control.groups.form.notification.edited.success": "Група \"{{name}}\" је успешно измењена", + "admin.access-control.groups.form.actions.delete": "Избришите групу", + "admin.access-control.groups.form.delete-group.modal.header": "Избришите групу \"{{ dsoName}}\"", + "admin.access-control.groups.form.delete-group.modal.info": "Да ли сте сигурни да желите да избришете групу \"{{ dsoName }}\"", + "admin.access-control.groups.form.delete-group.modal.cancel": "Поништити, отказати", + "admin.access-control.groups.form.delete-group.modal.confirm": "Избришите", + "admin.access-control.groups.form.notification.deleted.success": "Група \"{{ name }}\" је успешно обрисана", + "admin.access-control.groups.form.notification.deleted.failure.title": "Брисање групе \"{{ name }}\" није успело", + "admin.access-control.groups.form.notification.deleted.failure.content": "Узрок: \"{{ cause }}\"", + "admin.access-control.groups.form.members-list.head": "EPeople", + "admin.access-control.groups.form.members-list.search.head": "Додајте EPeople", + "admin.access-control.groups.form.members-list.button.see-all": "Прегледајте све", + "admin.access-control.groups.form.members-list.headMembers": "Тренутни чланови", + "admin.access-control.groups.form.members-list.search.scope.metadata": "Метаподатак", + "admin.access-control.groups.form.members-list.search.scope.email": "Е-мејл (тачно)", + "admin.access-control.groups.form.members-list.search.button": "Претрага", + "admin.access-control.groups.form.members-list.table.id": "ID", + "admin.access-control.groups.form.members-list.table.name": "Име", + "admin.access-control.groups.form.members-list.table.identity": "Идентитет", + "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": "Уклони / Додај", + "admin.access-control.groups.form.members-list.table.edit.buttons.remove": "Уклоните члана са именом \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.addMember": "Члан је успешно додат: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.addMember": "Додавање члана није успело: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.success.deleteMember": "Успешно обрисан члан: \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.deleteMember": "Брисање члана није успело: \"{{name}}\"", + "admin.access-control.groups.form.members-list.table.edit.buttons.add": "Додај члана са именом \"{{name}}\"", + "admin.access-control.groups.form.members-list.notification.failure.noActiveGroup": "Нема тренутно активне групе, прво пошаљите име.", + "admin.access-control.groups.form.members-list.no-members-yet": "Још нема чланова у групи, претражите и додајте.", + "admin.access-control.groups.form.members-list.no-items": "Ниједан EPeople није пронађен у тој претрази", + "admin.access-control.groups.form.subgroups-list.notification.failure": "Нешто није у реду: \"{{cause}}\"", + "admin.access-control.groups.form.subgroups-list.head": "Групе", + "admin.access-control.groups.form.subgroups-list.search.head": "Додајте подгрупу", + "admin.access-control.groups.form.subgroups-list.button.see-all": "Прегледајте све", + "admin.access-control.groups.form.subgroups-list.headSubgroups": "Тренутне подгрупе", + "admin.access-control.groups.form.subgroups-list.search.button": "Претрага", + "admin.access-control.groups.form.subgroups-list.table.id": "ID", + "admin.access-control.groups.form.subgroups-list.table.name": "Име", + "admin.access-control.groups.form.subgroups-list.table.collectionOrCommunity": "Колекција/Заједница", + "admin.access-control.groups.form.subgroups-list.table.edit": "Уклони / Додај", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.remove": "Уклоните подгрупу са именом \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Додајте подгрупу са именом \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Тренутна група", + "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Подгрупа је успешно додата: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Додавање подгрупе није успело: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.success.deleteSubgroup": "Успешно обрисана подгрупа: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.deleteSubgroup": "Брисање подгрупе није успело: \"{{name}}\"", + "admin.access-control.groups.form.subgroups-list.notification.failure.noActiveGroup": "Нема тренутно активне групе, прво пошаљите име.", + "admin.access-control.groups.form.subgroups-list.notification.failure.subgroupToAddIsActiveGroup": "Ово је тренутна група, не може се додати.", + "admin.access-control.groups.form.subgroups-list.no-items": "Није пронађена ниједна група са овим у свом имену или овим као UUID", + "admin.access-control.groups.form.subgroups-list.no-subgroups-yet": "Још нема подгрупа у групи.", + "admin.access-control.groups.form.return": "Назад", + "admin.access-control.groups.form.tooltip.editGroupPage": "На овој страници можете да мењате својства и чланове групе. У горњем одељку можете да измените име и опис групе, осим ако је ово администраторска група за колекцију или заједницу, у ком случају се име и опис групе аутоматски генеришу и не могу се мењати. У следећим одељцима можете да мењате чланство у групи. Погледајте [wiki](https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group) за више детаља.", + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Да бисте додали или уклонили EPerson-у/из ове групе, или кликните на дугме 'Прегледај све' или користите траку за претрагу испод да бисте претражили кориснике (користите падајући мени са леве стране траке за претрагу да бисте изабрали да ли ћете претраживати према метаподацима или према е-маилу). Затим кликните на икону плус за сваког корисника којег желите да додате на листу испод или на икону корпе за смеће за сваког корисника којег желите да уклоните. Листа у наставку може имати неколико страница: користите контроле странице испод листе да бисте прешли на следеће странице. Када будете спремни, сачувајте промене кликом на дугме \"Сачувај\" у горњем делу.", + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Да бисте додали или уклонили подгрупу у/из ове групе, кликните на дугме 'Прегледај све' или користите траку за претрагу испод да бисте претражили кориснике. Затим кликните на икону плус за сваког корисника којег желите да додате на листу испод или на икону корпе за смеће за сваког корисника којег желите да уклоните. Листа у наставку може имати неколико страница: користите контроле странице испод листе да бисте прешли на следеће странице. Када будете спремни, сачувајте промене кликом на дугме \"Сачувај\" у горњем делу.", + "admin.search.breadcrumbs": "Административна претрага", + "admin.search.collection.edit": "Уредите", + "admin.search.community.edit": "Уредите", + "admin.search.item.delete": "Избришите", + "admin.search.item.edit": "Уредите", + "admin.search.item.make-private": "Учините невидљивим", + "admin.search.item.make-public": "Учините видљивим", + "admin.search.item.move": "Померите", + "admin.search.item.reinstate": "Реинстате", + "admin.search.item.withdraw": "Одустати", + "admin.search.title": "Административна претрага", + "administrativeView.search.results.head": "Административна претрага", + "admin.workflow.breadcrumbs": "Администрирање радног процеса", + "admin.workflow.title": "Администрирање радног процеса", + "admin.workflow.item.workflow": "Процес рада", + "admin.workflow.item.workspace": "Радни простор", + "admin.workflow.item.delete": "Избришите", + "admin.workflow.item.send-back": "Вратите", + "admin.workflow.item.policies": "Политике", + "admin.workflow.item.supervision": "Надзор", + "admin.metadata-import.breadcrumbs": "Увези метаподатке", + "admin.batch-import.breadcrumbs": "Увези Batch", + "admin.metadata-import.title": "Увези метаподатке", + "admin.batch-import.title": "Увези Batch", + "admin.metadata-import.page.header": "Увезите метаподатке", + "admin.batch-import.page.header": "Увези Batch", + "admin.metadata-import.page.help": "Овде можете да превучете или прегледате CSV фајлове који садрже Batch операције метаподатака за фајлове", + "admin.batch-import.page.help": "Изаберите колекцију у коју желите да увезете. Затим превуците или потражите ZIP фајл једноставног архивског формата (SAF) која укључује ставке за увоз", + "admin.batch-import.page.toggle.help": "Могуће је извршити увоз било са отпремањем фајла или преко URL-а, користите горњи прекидач да бисте подесили извор уноса", + "admin.metadata-import.page.dropMsg": "Превуците CSV са метаподацима за увоз", + "admin.batch-import.page.dropMsg": "Превуците Batch ZIP за увоз", + "admin.metadata-import.page.dropMsgReplace": "Превуците да замените CSV са метаподацима за увоз", + "admin.batch-import.page.dropMsgReplace": "Превуците да замените Batch ZIP за увоз", + "admin.metadata-import.page.button.return": "Назад", + "admin.metadata-import.page.button.proceed": "Наставите", + "admin.metadata-import.page.button.select-collection": "Изаберите колекцију", + "admin.metadata-import.page.error.addFile": "Прво изаберите фајл!", + "admin.metadata-import.page.error.addFileUrl": "Прво унесите URL фајл!", + "admin.batch-import.page.error.addFile": "Прво изаберите ZIP фајл!", + "admin.metadata-import.page.toggle.upload": "Отпремите", + "admin.metadata-import.page.toggle.url": "URL", + "admin.metadata-import.page.urlMsg": "Уметните Batch ZIP URL за увоз", + "admin.metadata-import.page.validateOnly": "Само валидирај", + "admin.metadata-import.page.validateOnly.hint": "Када се изабере, отпремљени CSV ће бити потврђен. Добићете извештај о утврђеним променама, али промене неће бити сачуване.", + "advanced-workflow-action.rating.form.rating.label": "Оцена", + "advanced-workflow-action.rating.form.rating.error": "Морате оценити ставку", + "advanced-workflow-action.rating.form.review.label": "Преглед", + "advanced-workflow-action.rating.form.review.error": "Морате унети рецензију да бисте послали ову оцену", + "advanced-workflow-action.rating.description": "Молимо изаберите оцену испод", + "advanced-workflow-action.rating.description-requiredDescription": "Молимо изаберите оцену испод и додајте рецензију", + "advanced-workflow-action.select-reviewer.description-single": "Молимо изаберите једног рецензента испод пре слања", + "advanced-workflow-action.select-reviewer.description-multiple": "Молимо изаберите једног или више рецензената испод пре слања", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Додајте EPeople", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Прегледајте све", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Тренутни чланови", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Метаподаци", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "Е-мејл (тачно)", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Претрага", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Име", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Идентитет", + "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": "Уклоните / Додајте", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Уклоните члана са именом \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Успешно додат члан: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Неуспешно додавање члана: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Успешно избрисан члан: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Неуспешно брисање члана: \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Додајте члана са именом \"{{name}}\"", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Тренутно нема активне групе, прво унесите име.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "Још нема чланова у групи, претражите и додајте.", + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Ниједан EPeople није пронађен у тој претрази", + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Није изабран рецензент.", + "admin.batch-import.page.validateOnly.hint": "Када се изабере, отпремљени ZIP ће бити потврђен. Добићете извештај о утврђеним променама, али промене неће бити сачуване.", + "admin.batch-import.page.remove": "уклонити", + "auth.errors.invalid-user": "Погрешна Е-мејл адреса или лозинка.", + "auth.messages.expired": "Ваша сесија је истекла. Молимо пријавите се поново.", + "auth.messages.token-refresh-failed": "Освежавање токена сесије није успело. Молимо пријавите се поново.", + "bitstream.download.page": "Тренутно се преузима {{bitstream}}...", + "bitstream.download.page.back": "Назад", + "bitstream.edit.authorizations.link": "Измените полисе битстрим-а", + "bitstream.edit.authorizations.title": "Измените полисе битстрим-а", + "bitstream.edit.return": "Назад", + "bitstream.edit.bitstream": "битстрим:", + "bitstream.edit.form.description.hint": "Опционо, наведите кратак опис фајла, на пример \"<i>Главни чланак</i>\" или \"<i>Очитавања података експеримента</i>\".", + "bitstream.edit.form.description.label": "Опис", + "bitstream.edit.form.embargo.hint": "Први дан од којег је приступ дозвољен. <b>Овај датум се не може изменити у овом обрасцу.</b> Да бисте поставили датум забране за битстрим, идите на картицу <i>Статус ставке</i>, кликните на <i>Овлашћења...</i >, креирајте или измените политику битстрим-ова<i>ПРОЧИТАЈТЕ</i> и поставите <i>Датум почетка</i> по жељи.", + "bitstream.edit.form.embargo.label": "Забрана до одређеног датума", + "bitstream.edit.form.fileName.hint": "Промените име фајла за битстрим. Имајте на уму да ће се овим променити приказани битстрим URL, али ће се стари линкови и даље разрешити све док се ID секвенце не промени.", + "bitstream.edit.form.fileName.label": "Име фајла", + "bitstream.edit.form.newFormat.label": "Опишите нови формат", + "bitstream.edit.form.newFormat.hint": "Апликација коју сте користили за креирање фајла, и број верзије (на пример, \"<i>ACMESoft SuperApp верзија 1.5</i>\").", + "bitstream.edit.form.primaryBitstream.label": "Примарни битстрим", + "bitstream.edit.form.selectedFormat.hint": "Ако формат није на горњој листи, <b>изаберите \"формат није на листи\" изнад</b> и опишите га под \"Опишите нови формат\".", + "bitstream.edit.form.selectedFormat.label": "Изабрани формат", + "bitstream.edit.form.selectedFormat.unknown": "Формат није на листи", + "bitstream.edit.notifications.error.format.title": "Дошло је до грешке приликом чувања битстрим формата", + "bitstream.edit.notifications.error.primaryBitstream.title": "Дошло је до грешке приликом чувања примарног битстрим-а", + "bitstream.edit.form.iiifLabel.label": "IIIF ознака", + "bitstream.edit.form.iiifLabel.hint": "Ознака canvas-а за ову слику. Ако није дата, користиће се подразумевана ознака.", + "bitstream.edit.form.iiifToc.label": "IIIF Преглед садржаја", + "bitstream.edit.form.iiifToc.hint": "Додавање текста овде, чини ово место почетком новог опсега садржаја.", + "bitstream.edit.form.iiifWidth.label": "IIIF ширина canvas-а", + "bitstream.edit.form.iiifWidth.hint": "Ширина платна обично треба да одговара ширини слике.", + "bitstream.edit.form.iiifHeight.label": "IIIF висина canvas-a", + "bitstream.edit.form.iiifHeight.hint": "Висина canvas-а обично треба да одговара висини слике.", + "bitstream.edit.notifications.saved.content": "Ваше промене у овом битстрим-у су сачуване.", + "bitstream.edit.notifications.saved.title": "битстрим је сачуван", + "bitstream.edit.title": "Измените битстрим", + "bitstream-request-a-copy.alert.canDownload1": "Већ имате приступ овом фајлу. Ако желите да преузмете фајл, кликните", + "bitstream-request-a-copy.alert.canDownload2": "овде", + "bitstream-request-a-copy.header": "Затражите копију фајла", + "bitstream-request-a-copy.intro": "Унесите следеће информације да бисте затражили копију следеће ставке:", + "bitstream-request-a-copy.intro.bitstream.one": "Захтева се следећи фајл:", + "bitstream-request-a-copy.intro.bitstream.all": "Захтевају се сви фајлови.", + "bitstream-request-a-copy.name.label": "име *", + "bitstream-request-a-copy.name.error": "Име је обавезно", + "bitstream-request-a-copy.email.label": "Ваша емаил адреса *", + "bitstream-request-a-copy.email.hint": "Ова Е-мејл адреса се користи за слање фајла.", + "bitstream-request-a-copy.email.error": "Молим Вас унесите исправну Е-мејл адресу.", + "bitstream-request-a-copy.allfiles.label": "Фајлови", + "bitstream-request-a-copy.files-all-false.label": "Само тражени фајл", + "bitstream-request-a-copy.files-all-true.label": "Све фајлови (ове ставке) у ограниченом приступу", + "bitstream-request-a-copy.message.label": "Порука", + "bitstream-request-a-copy.return": "Назад", + "bitstream-request-a-copy.submit": "Захтевај копију", + "bitstream-request-a-copy.submit.success": "Захтев за ставку је успешно достављен.", + "bitstream-request-a-copy.submit.error": "Нешто није у реду са слањем захтева за ставку.", + "browse.back.all-results": "Сви резултати прегледа", + "browse.comcol.by.author": "По аутору", + "browse.comcol.by.dateissued": "По датуму издања", + "browse.comcol.by.subject": "По предмету", + "browse.comcol.by.srsc": "По категорији предмета", + "browse.comcol.by.title": "По наслову", + "browse.comcol.head": "Прегледајте", + "browse.empty": "Нема ставки за приказ.", + "browse.metadata.author": "Аутору", + "browse.metadata.dateissued": "Датуму издања", + "browse.metadata.subject": "Предмету", + "browse.metadata.title": "Наслову", + "browse.metadata.author.breadcrumbs": "Преглед по аутору", + "browse.metadata.dateissued.breadcrumbs": "Преглед по датуму", + "browse.metadata.subject.breadcrumbs": "Преглед по предмету", + "browse.metadata.srsc.breadcrumbs": "Преглед по категорији предмета", + "browse.metadata.title.breadcrumbs": "Преглед по наслову", + "pagination.next.button": "Следеће", + "pagination.previous.button": "Претходно", + "pagination.next.button.disabled.tooltip": "Нема више страница са резултатима", + "browse.startsWith": ", почевши од {{ startsWith }}", + "browse.startsWith.choose_start": "(Изаберите почетак)", + "browse.startsWith.choose_year": "(Изаберите годину)", + "browse.startsWith.choose_year.label": "Изаберите годину издања", + "browse.startsWith.jump": "Филтрирајте резултате по години или месецу", + "browse.startsWith.months.april": "Април", + "browse.startsWith.months.august": "Август", + "browse.startsWith.months.december": "Децембар", + "browse.startsWith.months.february": "Фебруар", + "browse.startsWith.months.january": "Јануар", + "browse.startsWith.months.july": "Јул", + "browse.startsWith.months.june": "Јун", + "browse.startsWith.months.march": "Март", + "browse.startsWith.months.may": "Мај", + "browse.startsWith.months.none": "(Изаберите месец)", + "browse.startsWith.months.none.label": "Изаберите месец издања", + "browse.startsWith.months.november": "Новембар", + "browse.startsWith.months.october": "Октобар", + "browse.startsWith.months.september": "Септембар", + "browse.startsWith.submit": "Прегледај", + "browse.startsWith.type_date": "Филтрирајте резултате по датуму", + "browse.startsWith.type_date.label": "Или унесите датум (година-месец) и кликните на дугме Прегледај", + "browse.startsWith.type_text": "Филтрирајте резултате уписивањем првих неколико слова", + "browse.startsWith.input": "Филтер", + "browse.taxonomy.button": "Прегледај", + "browse.title": "Прегледање {{ collection }} према {{ field }}{{ startsWith }} {{ value }}", + "browse.title.page": "Прегледање {{ collection }} према {{ field }} {{ value }}", + "search.browse.item-back": "Назад на резултате", + "chips.remove": "Уклоните чип", + "claimed-approved-search-result-list-element.title": "Одобрено", + "claimed-declined-search-result-list-element.title": "Одбијено, враћено подносиоцу", + "claimed-declined-task-search-result-list-element.title": "Одбијено, враћено менаджеру за преглед", + "collection.create.head": "Направите колекцију", + "collection.create.notifications.success": "Колекција је успешно направљена", + "collection.create.sub-head": "Направите колекцију за заједницу {{ parent }}", + "collection.curate.header": "Сачувај колекцију: {{collection}}", + "collection.delete.cancel": "Поништити, отказати", + "collection.delete.confirm": "Потврди", + "collection.delete.processing": "Брисање", + "collection.delete.head": "Избришите колекцију", + "collection.delete.notification.fail": "Колекција се не може избрисати", + "collection.delete.notification.success": "Колекција је успешно избрисана", + "collection.delete.text": "Да ли сте сигурни да желите да избришете колекцију \"{{ dso }}\"", + "collection.edit.delete": "Избришите ову колекцију", + "collection.edit.head": "Уредите колекцију", + "collection.edit.breadcrumbs": "Уредите колекцију", + "collection.edit.tabs.mapper.head": "Мапирање ставки", + "collection.edit.tabs.item-mapper.title": "Уређивање колекције - мапирање ставки", + "collection.edit.item-mapper.cancel": "Поништити, отказати", + "collection.edit.item-mapper.collection": "Колекција: \"<b>{{name}}</b>\"", + "collection.edit.item-mapper.confirm": "Мапирајте изабране ставке", + "collection.edit.item-mapper.description": "Ово је алатка за мапирање ставки која омогућава администраторима колекције да мапирају ставке из других колекција у ову колекцију. Можете тражити ставке из других колекција и мапирати их или прегледати листу тренутно мапираних ставки.", + "collection.edit.item-mapper.head": "Мапирање ставки - мапа ставки из других колекција", + "collection.edit.item-mapper.no-search": "Унесите упит за претрагу", + "collection.edit.item-mapper.notifications.map.error.content": "Дошло је до грешака за мапирање {{amount}} ставки.", + "collection.edit.item-mapper.notifications.map.error.head": "Грешке у мапирању", + "collection.edit.item-mapper.notifications.map.success.content": "Успешно мапиране {{amount}} ставке.", + "collection.edit.item-mapper.notifications.map.success.head": "Мапирање је завршено", + "collection.edit.item-mapper.notifications.unmap.error.content": "Дошло је до грешака при уклањању мапирања ставки {{amount}}.", + "collection.edit.item-mapper.notifications.unmap.error.head": "Уклоните грешке мапирања", + "collection.edit.item-mapper.notifications.unmap.success.content": "Успешно су уклоњена мапирања {{amount}} ставки.", + "collection.edit.item-mapper.notifications.unmap.success.head": "Уклањање мапирања је завршено", + "collection.edit.item-mapper.remove": "Уклањање мапирања изабраних ставки", + "collection.edit.item-mapper.search-form.placeholder": "Претражи ставке...", + "collection.edit.item-mapper.tabs.browse": "Прегледајте мапиране ставке", + "collection.edit.item-mapper.tabs.map": "Мапирајте нове ставке", + "collection.edit.logo.delete.title": "Избришите лого", + "collection.edit.logo.delete-undo.title": "Опозови брисање", + "collection.edit.logo.label": "Лого колекције", + "collection.edit.logo.notifications.add.error": "Отпремање лога колекције није успело. Проверите садржај пре поновног покушаја.", + "collection.edit.logo.notifications.add.success": "Отпремање лога колекције је успешно.", + "collection.edit.logo.notifications.delete.success.title": "Лого је избрисан", + "collection.edit.logo.notifications.delete.success.content": "Успешно је обрисан лого колекције", + "collection.edit.logo.notifications.delete.error.title": "Грешка при брисању лога", + "collection.edit.logo.upload": "Превуците логотип колекције за отпремање", + "collection.edit.notifications.success": "Успешно уређена колекција", + "collection.edit.return": "Назад", + "collection.edit.tabs.access-control.head": "Контрола приступа", + "collection.edit.tabs.access-control.title": "Уређивање колекције - Контрола приступа", + "collection.edit.tabs.curate.head": "Curate", + "collection.edit.tabs.curate.title": "Уређивање колекције - Curate", + "collection.edit.tabs.authorizations.head": "Овлашћења", + "collection.edit.tabs.authorizations.title": "Уређивање колекције - овлашћења", + "collection.edit.item.authorizations.load-bundle-button": "Учитајте још пакета", + "collection.edit.item.authorizations.load-more-button": "Учитај више", + "collection.edit.item.authorizations.show-bitstreams-button": "Прикажи битстрим смернице за пакет", + "collection.edit.tabs.metadata.head": "Уреди метаподатке", + "collection.edit.tabs.metadata.title": "Уређивање колекције - Метаподаци", + "collection.edit.tabs.roles.head": "Додели улоге", + "collection.edit.tabs.roles.title": "Уређивање колекције - Улоге", + "collection.edit.tabs.source.external": "Ова колекција прикупља свој садржај из спољашњег извора", + "collection.edit.tabs.source.form.errors.oaiSource.required": "Морате да обезбедите сет ID циљне колекције.", + "collection.edit.tabs.source.form.harvestType": "Садржај се прикупља", + "collection.edit.tabs.source.form.head": "Конфигуришите спољни извор", + "collection.edit.tabs.source.form.metadataConfigId": "Формат метаподатака", + "collection.edit.tabs.source.form.oaiSetId": "ID специфичног скупа за OAI", + "collection.edit.tabs.source.form.oaiSource": "OAI провајдер", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_BITSTREAMS": "Сакупите метаподатке и битстрим-ове (захтева ORE подршку)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_AND_REF": "Сакупите метаподатке и референце на битстрим-ове (захтева ORE подршку)", + "collection.edit.tabs.source.form.options.harvestType.METADATA_ONLY": "Само прикупљени метаподаци", + "collection.edit.tabs.source.head": "Извор садржаја", + "collection.edit.tabs.source.notifications.discarded.content": "Ваше промене су одбачене. Да бисте поново поставили своје промене, кликните на дугме \"Опозови\".", + "collection.edit.tabs.source.notifications.discarded.title": "Промене су одбачене", + "collection.edit.tabs.source.notifications.invalid.content": "Ваше промене нису сачуване. Проверите да ли су сва поља исправна пре него што сачувате.", + "collection.edit.tabs.source.notifications.invalid.title": "Метаподаци су неважећи", + "collection.edit.tabs.source.notifications.saved.content": "Ваше промене извора садржаја ове колекције су сачуване.", + "collection.edit.tabs.source.notifications.saved.title": "Извор садржаја је сачуван", + "collection.edit.tabs.source.title": "Уређивање колекције – Извор садржаја", + "collection.edit.template.add-button": "Додати", + "collection.edit.template.breadcrumbs": "Шаблон ставке", + "collection.edit.template.cancel": "Отказати", + "collection.edit.template.delete-button": "Избришите", + "collection.edit.template.edit-button": "Измените", + "collection.edit.template.error": "Дошло је до грешке при преузимању ставке шаблона", + "collection.edit.template.head": "Измените ставку шаблона за колекцију \"{{ collection }}\"", + "collection.edit.template.label": "Ставка шаблона", + "collection.edit.template.loading": "Учитава се ставка шаблона...", + "collection.edit.template.notifications.delete.error": "Неуспешно брисање шаблона ставке", + "collection.edit.template.notifications.delete.success": "Успешно обрисан шаблон ставке", + "collection.edit.template.title": "Измените ставку шаблона", + "collection.form.abstract": "Кратак опис", + "collection.form.description": "Уводни текст (HTML)", + "collection.form.errors.title.required": "Молимо унесите име колекције", + "collection.form.license": "Лиценца", + "collection.form.provenance": "Порекло", + "collection.form.rights": "Ауторски текст (HTML)", + "collection.form.tableofcontents": "Вести (HTML)", + "collection.form.title": "Име", + "collection.form.entityType": "Тип ентитета", + "collection.listelement.badge": "Колекција", + "collection.page.browse.recent.head": "Недавни поднесци", + "collection.page.browse.recent.empty": "Нема ставки за приказ", + "collection.page.edit": "Измените ову колекцију", + "collection.page.handle": "Трајни URI за ову колекцију", + "collection.page.license": "Лиценца", + "collection.page.news": "Вести", + "collection.select.confirm": "Потврдите изабрано", + "collection.select.empty": "Нема колекција за приказ", + "collection.select.table.title": "Наслов", + "collection.source.controls.head": "Контрола прикупљања", + "collection.source.controls.test.submit.error": "Нешто није у реду са покретањем тестирања подешавања", + "collection.source.controls.test.failed": "Скрипта за тестирање подешавања није успела", + "collection.source.controls.test.completed": "Скрипта за тестирање подешавања је успешно завршена", + "collection.source.controls.test.submit": "Тестна конфигурација", + "collection.source.controls.test.running": "Тестирање конфигурације...", + "collection.source.controls.import.submit.success": "Увоз је успешно покренут", + "collection.source.controls.import.submit.error": "Нешто није у реду са покретањем увоза", + "collection.source.controls.import.submit": "Увезите сада", + "collection.source.controls.import.running": "Увоз...", + "collection.source.controls.import.failed": "Дошло је до грешке током увоза", + "collection.source.controls.import.completed": "Увоз је завршен", + "collection.source.controls.reset.submit.success": "Ресетовање и поновни увоз су успешно покренути", + "collection.source.controls.reset.submit.error": "Нешто није у реду са покретањем ресетовања и поновног увоза", + "collection.source.controls.reset.failed": "Дошло је до грешке током ресетовања и поновног увоза", + "collection.source.controls.reset.completed": "Ресетовање и поновни увоз су завршени", + "collection.source.controls.reset.submit": "Ресетујте и поново увезите", + "collection.source.controls.reset.running": "Ресетовање и поновни увоз...", + "collection.source.controls.harvest.status": "Статус прикупљаања:", + "collection.source.controls.harvest.start": "Време почетка прикупљања:", + "collection.source.controls.harvest.last": "Време почетка прикупљања:", + "collection.source.controls.harvest.message": "Информације о прикупљању:", + "collection.source.controls.harvest.no-information": "N/A", + "collection.source.update.notifications.error.content": "Наведена подешавања су тестирана и нису функционисала.", + "collection.source.update.notifications.error.title": "Грешка на серверу", + "communityList.breadcrumbs": "Листа заједнице", + "communityList.tabTitle": "Лист заједнице", + "communityList.title": "Листа заједница", + "communityList.showMore": "Прикажи више", + "community.create.head": "Креирајте заједницу", + "community.create.notifications.success": "Заједница је успешно креирана", + "community.create.sub-head": "Креирајте подзаједницу за заједницу {{ parent }}", + "community.curate.header": "Уредник заједнице: {{community}}", + "community.delete.cancel": "Отказати", + "community.delete.confirm": "Потврдите", + "community.delete.processing": "Брисање...", + "community.delete.head": "Избришите заједницу", + "community.delete.notification.fail": "Није могуће избрисати заједницу", + "community.delete.notification.success": "Успешно избрисана заједница", + "community.delete.text": "Да ли сте сигурни да желите да избришете заједницу \"{{ dso }}\"", + "community.edit.delete": "Избришите ову заједницу", + "community.edit.head": "Измените заједницу", + "community.edit.breadcrumbs": "Измените заједницу", + "community.edit.logo.delete.title": "Избришите лого", + "community.edit.logo.delete-undo.title": "Поништите брисање", + "community.edit.logo.label": "Лого заједнице", + "community.edit.logo.notifications.add.error": "Отпремање логоа заједнице није успело. Молимо проверите садржај пре поновног покушаја.", + "community.edit.logo.notifications.add.success": "Успешно отпремање логоа заједнице.", + "community.edit.logo.notifications.delete.success.title": "Лого је избрисан", + "community.edit.logo.notifications.delete.success.content": "Успешно избрисан лого заједнице", + "community.edit.logo.notifications.delete.error.title": "Грешка при брисању логоа", + "community.edit.logo.upload": "Унесите лого заједнице да бисте га отпремили", + "community.edit.notifications.success": "Успешно је измењена заједница", + "community.edit.notifications.unauthorized": "Немате овлашћење да извршите ову промену", + "community.edit.notifications.error": "Дошло је до грешке при уређивању заједнице", + "community.edit.return": "Назад", + "community.edit.tabs.curate.head": "Curate", + "community.edit.tabs.curate.title": "Уређивање заједнице - Curate", + "community.edit.tabs.access-control.head": "Контрола приступа", + "community.edit.tabs.access-control.title": "Уређивање заједнице - Контрола приступа", + "community.edit.tabs.metadata.head": "Уреди метаподатке", + "community.edit.tabs.metadata.title": "Уређивање заједнице – Метаподаци", + "community.edit.tabs.roles.head": "Додели улоге", + "community.edit.tabs.roles.title": "Уређивање заједнице - Улоге", + "community.edit.tabs.authorizations.head": "Овлашћења", + "community.edit.tabs.authorizations.title": "Уређивање заједнице - овлашћења", + "community.listelement.badge": "Заједница", + "comcol-role.edit.no-group": "Ниједан", + "comcol-role.edit.create": "Креирајте", + "comcol-role.edit.create.error.title": "Прављење групе за улогу \"{{ role }}\" није успело", + "comcol-role.edit.restrict": "Ограничити", + "comcol-role.edit.delete": "Избришите", + "comcol-role.edit.delete.error.title": "Брисање групе улога \"{{ role }}\" није успело", + "comcol-role.edit.community-admin.name": "Администратори", + "comcol-role.edit.collection-admin.name": "Администратори", + "comcol-role.edit.community-admin.description": "Администратори заједнице могу да креирају подзаједнице или колекције и да управљају тим подзаједницама или збиркама или да им додељују управљање. Поред тога, они одлучују ко може да поднесе ставке у било коју подзбирку, уређују метаподатке ставки (након подношења) и додају (мапирају) постојеће ставке из других колекција (предмет овлашћења).", + "comcol-role.edit.collection-admin.description": "Администратори колекције одлучују ко може да шаље ставке у колекцију, уређују метаподатке ставки (након слања) и додају (мапирају) постојеће ставке из других колекција у ову колекцију (предмет овлашћења за ту колекцију).", + "comcol-role.edit.submitters.name": "Подносиоци", + "comcol-role.edit.submitters.description": "Е-људи и групе које имају дозволу да подносе нове ставке у ову колекцију.", + "comcol-role.edit.item_read.name": "Подразумевани приступ за читање ставке", + "comcol-role.edit.item_read.description": "Е-Људи и групе које могу да читају нове ставке послате у ову колекцију. Промене ове улоге нису ретроактивне. Постојеће ставке у систему ће и даље моћи да виде они који су имали приступ за читање у време њиховог додавања.", + "comcol-role.edit.item_read.anonymous-group": "Подразумевано читање за долазне ставке је тренутно постављено на Анонимно.", + "comcol-role.edit.bitstream_read.name": "Подразумевани приступ за читање битстреамова", + "comcol-role.edit.bitstream_read.description": "Администратори заједнице могу да креирају подзаједнице или колекције и да управљају тим подзаједницама или збиркама или да им додељују управљање. Поред тога, они одлучују ко може да поднесе ставке у било коју подзбирку, уређују метаподатке ставки (након подношења) и додају (мапирају) постојеће ставке из других колекција (предмет овлашћења).", + "comcol-role.edit.bitstream_read.anonymous-group": "Подразумевано читање за долазне битстреамове је тренутно подешено на Анонимно.", + "comcol-role.edit.editor.name": "Уредници", + "comcol-role.edit.editor.description": "Уредници могу да уређују метаподатке долазних поднесака, а затим да их прихвате или одбију.", + "comcol-role.edit.finaleditor.name": "Коначни уредници", + "comcol-role.edit.finaleditor.description": "Коначни уредници могу да уређују метаподатке долазних поднесака, али неће моћи да их одбију.", + "comcol-role.edit.reviewer.name": "Рецензенти", + "comcol-role.edit.reviewer.description": "Рецензенти могу да прихвате или одбију долазне поднеске. Међутим, они не могу да уређују метаподатке поднеска.", + "comcol-role.edit.scorereviewers.name": "Резултат рецензената", + "comcol-role.edit.scorereviewers.description": "Рецензенти могу да дају оцену долазним поднесцима, што ће дефинисати да ли ће поднесак бити одбијен или не.", + "community.form.abstract": "Кратак опис", + "community.form.description": "Уводни текст (HTML)", + "community.form.errors.title.required": "Унесите назив заједнице", + "community.form.rights": "Текст ауторских права (HTML)", + "community.form.tableofcontents": "Вести (HTML)", + "community.form.title": "Име", + "community.page.edit": "Уредите ову заједницу", + "community.page.handle": "Стални URI за ову заједницу", + "community.page.license": "Лиценца", + "community.page.news": "Вести", + "community.all-lists.head": "Подзаједнице и колекције", + "community.sub-collection-list.head": "Колекције у овој заједници", + "community.sub-community-list.head": "Заједнице у овој заједници", + "cookies.consent.accept-all": "Прихватите све", + "cookies.consent.accept-selected": "Прихватите изабрано", + "cookies.consent.app.opt-out.description": "Ова апликација се подразумевано учитава (али можете да одустанете)", + "cookies.consent.app.opt-out.title": "(одустати)", + "cookies.consent.app.purpose": "Сврха", + "cookies.consent.app.required.description": "Ова апликација је увек потребна", + "cookies.consent.app.required.title": "(увек потребно)", + "cookies.consent.app.disable-all.description": "Користите овај прекидач да омогућите или онемогућите све услуге.", + "cookies.consent.app.disable-all.title": "Омогућите или онемогућите све услуге", + "cookies.consent.update": "Било је промена од ваше последње посете, ажурирајте своју сагласност.", + "cookies.consent.close": "Затворити", + "cookies.consent.decline": "Одбити", + "cookies.consent.ok": "То је у реду", + "cookies.consent.save": "сачувати", + "cookies.consent.content-notice.title": "Сагласност за колачиће", + "cookies.consent.content-notice.description": "Прикупљамо и обрађујемо ваше личне податке у следеће сврхе: <strong>Провера аутентичности, подешавања, потврда и статистика</strong>. <br/> Да бисте сазнали више, прочитајте нашу {privacyPolicy}.", + "cookies.consent.content-notice.description.no-privacy": "Прикупљамо и обрађујемо ваше личне податке у следеће сврхе: <strong>Провера аутентичности, подешавања, потврда и статистика</strong>.", + "cookies.consent.content-notice.learnMore": "Прилагодити", + "cookies.consent.content-modal.description": "Овде можете видети и прилагодити информације које прикупљамо о вама.", + "cookies.consent.content-modal.privacy-policy.name": "Правила о приватности", + "cookies.consent.content-modal.privacy-policy.text": "Да сазнате више, прочитајте нашу {privacyPolicy}.", + "cookies.consent.content-modal.title": "Информације које прикупљамо", + "cookies.consent.content-modal.services": "Услуге", + "cookies.consent.content-modal.service": "Услуга", + "cookies.consent.app.title.authentication": "Провера", + "cookies.consent.app.description.authentication": "Потребно за пријављивање", + "cookies.consent.app.title.preferences": "Подешавања", + "cookies.consent.app.description.preferences": "Потребно за чување ваших подешавања", + "cookies.consent.app.title.acknowledgement": "Потврда", + "cookies.consent.app.description.acknowledgement": "Потребно за чување ваших потврда и сагласности", + "cookies.consent.app.title.google-analytics": "Гоогле аналитике", + "cookies.consent.app.description.google-analytics": "Омогућава нам да пратимо статистичке податке", + "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", + "cookies.consent.app.description.google-recaptcha": "Користимо Google reCAPTCHA услугу током регистрације и опоравка лозинке", + "cookies.consent.purpose.functional": "Функционални", + "cookies.consent.purpose.statistical": "Статистички", + "cookies.consent.purpose.registration-password-recovery": "Регистрација и опоравак лозинке", + "cookies.consent.purpose.sharing": "Дељење", + "curation-task.task.citationpage.label": "Генеришите страницу са цитатима", + "curation-task.task.checklinks.label": "Проверите везе у метаподацима", + "curation-task.task.noop.label": "NOOP", + "curation-task.task.profileformats.label": "Профил Битстрим формати", + "curation-task.task.requiredmetadata.label": "Проверите потребне метаподатке", + "curation-task.task.translate.label": "Мицрософт преводилац", + "curation-task.task.vscan.label": "Претрага вируса", + "curation-task.task.register-doi.label": "Региструјте DOI", + "curation.form.task-select.label": "Задатак:", + "curation.form.submit": "Почетак", + "curation.form.submit.success.head": "Задато курирање је успешно покренуто", + "curation.form.submit.success.content": "Бићете преусмерени на одговарајућу страницу процеса.", + "curation.form.submit.error.head": "Неуспешно покретање задатог курирања", + "curation.form.submit.error.content": "Дошло је до грешке при покушају покретања задатог курирања.", + "curation.form.submit.error.invalid-handle": "Није могуће одредити handle за овај објекат", + "curation.form.handle.label": "Handle:", + "curation.form.handle.hint": "Савет: Унесите [your-handle-prefix]/0 да бисте покренули задатак на целом сајту (ову могућност не подржавају сви задаци)", + "deny-request-copy.email.message": "Поштовани {{ recipientName }}, \н Као одговор на ваш захтев, са жаљењем вас обавештавам да није могуће послати копију фајла коју сте тражили, у вези са документом: \"{{ itemUrl }}\" ({{ itemName }}), чији сам аутор. \н Срдачан поздрав, \н{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.subject": "Затражите копију документа", + "deny-request-copy.error": "Дошло је до грешке", + "deny-request-copy.header": "Одбијен захтев за копирање документа", + "deny-request-copy.intro": "Ова порука биће послата подносиоцу захтева", + "deny-request-copy.success": "Захтев за ставку је одбијен успешно", + "dso.name.untitled": "Без наслова", + "dso.name.unnamed": "Без имена", + "dso-selector.create.collection.head": "Нова колекција", + "dso-selector.create.collection.sub-level": "Креирајте нову колекцију у", + "dso-selector.create.community.head": "Нова заједница", + "dso-selector.create.community.or-divider": "или", + "dso-selector.create.community.sub-level": "Креирајте нову заједницу у", + "dso-selector.create.community.top-level": "Креирајте нову заједницу највишег нивоа", + "dso-selector.create.item.head": "Нова ставка", + "dso-selector.create.item.sub-level": "Креирајте нову ставку у", + "dso-selector.create.submission.head": "Нови поднесак", + "dso-selector.edit.collection.head": "Измените колекцију", + "dso-selector.edit.community.head": "Измените заједницу", + "dso-selector.edit.item.head": "Измените ставку", + "dso-selector.error.title": "Дошло је до грешке при претрази {{ type }}", + "dso-selector.export-metadata.dspaceobject.head": "Извезите метаподатке из", + "dso-selector.export-batch.dspaceobject.head": "Извезите пакет (ZIP) из", + "dso-selector.import-batch.dspaceobject.head": "Увезите пакет из", + "dso-selector.no-results": "Није пронађен {{ type }}", + "dso-selector.placeholder": "Претражите {{ type }}", + "dso-selector.select.collection.head": "Изаберите колекцију", + "dso-selector.set-scope.community.head": "Изаберите опсег претраге", + "dso-selector.set-scope.community.button": "Претражите читав репозиторијум", + "dso-selector.set-scope.community.or-divider": "или", + "dso-selector.set-scope.community.input-header": "Претражите заједницу или колекцију", + "dso-selector.claim.item.head": "Смернице за профил", + "dso-selector.claim.item.body": "Ово су постојећи профили који се можда односе на Вас. Ако се препознате у једном од ових профила, изаберите га и на страници са детаљима, међу опцијама, изаберите да га затражите. У супротном, можете креирати нови профил од нуле користећи дугме испод.", + "dso-selector.claim.item.not-mine-label": "Ниједан од ових није мој", + "dso-selector.claim.item.create-from-scratch": "Креирајте нови", + "dso-selector.results-could-not-be-retrieved": "Нешто није у реду, молимо освежите поново ↻", + "supervision-group-selector.header": "Селектор групе за надзор", + "supervision-group-selector.select.type-of-order.label": "Изаберите тип налога", + "supervision-group-selector.select.type-of-order.option.none": "НИЈЕДАН", + "supervision-group-selector.select.type-of-order.option.editor": "УРЕДНИК", + "supervision-group-selector.select.type-of-order.option.observer": "ПОСМАТРАЧ", + "supervision-group-selector.select.group.label": "Изаберите групу", + "supervision-group-selector.button.cancel": "Отказати", + "supervision-group-selector.button.save": "Сачувати", + "supervision-group-selector.select.type-of-order.error": "Молимо изаберите тип налога", + "supervision-group-selector.select.group.error": "Молимо изаберите групу", + "supervision-group-selector.notification.create.success.title": "Успешно је креиран налог надзора за групу {{ name}}", + "supervision-group-selector.notification.create.failure.title": "Грешка", + "supervision-group-selector.notification.create.already-existing": "Већ постоји налог за надзор за ову ставку изабране групе", + "confirmation-modal.export-metadata.header": "Извоз метаподатака за {{ dsoName }}", + "confirmation-modal.export-metadata.info": "Да ли сте сигурни да желите да извезете метаподатке за {{ dsoName }}", + "confirmation-modal.export-metadata.cancel": "Отказати", + "confirmation-modal.export-metadata.confirm": "Извоз", + "confirmation-modal.export-batch.header": "Извезите пакет (ZIP) за {{ dsoName }}", + "confirmation-modal.export-batch.info": "Да ли сте сигурни да желите да извезете пакет (ZIP) за {{ dsoName }}", + "confirmation-modal.export-batch.cancel": "Отказати", + "confirmation-modal.export-batch.confirm": "Извоз", + "confirmation-modal.delete-eperson.header": "Избришите EPerson \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.info": "Да ли сте сигурни да желите да избришете EPerson \"{{ dsoName }}\"", + "confirmation-modal.delete-eperson.cancel": "Отказати", + "confirmation-modal.delete-eperson.confirm": "Избрисати", + "confirmation-modal.delete-profile.header": "Избришите профил", + "confirmation-modal.delete-profile.info": "Да ли сте сигурни да желите да избришете свој профил", + "confirmation-modal.delete-profile.cancel": "Отказати", + "confirmation-modal.delete-profile.confirm": "Избрисати", + "confirmation-modal.delete-subscription.header": "Уклонити претплату", + "confirmation-modal.delete-subscription.info": "Да ли сте сигурни да желите да избришете претплату за \"{{ dsoName }}\"", + "confirmation-modal.delete-subscription.cancel": "Отказати", + "confirmation-modal.delete-subscription.confirm": "Избрисати", + "error.bitstream": "Грешка при преузимању битстрим-а", + "error.browse-by": "Грешка при преузимању ставки", + "error.collection": "Грешка при преузимању колекције", + "error.collections": "Грешка при преузимању колекција", + "error.community": "Грешка при преузимању заједнице", + "error.identifier": "Није пронађена ниједна ставка за идентификатор", + "error.default": "Грешка", + "error.item": "Грешка при преузимању ставке", + "error.items": "Грешка при преузимању ставки", + "error.objects": "Грешка при преузимању објеката", + "error.recent-submissions": "Грешка при преузимању недавних поднесака", + "error.search-results": "Грешка при преузимању резултата претраге", + "error.invalid-search-query": "Упит за претрагу није исправан. Проверите најбоља решења за <a href=\"https://solr.apache.org/guide/query-syntax-and-parsing.HTML\" target=\"_blank\">Solr синтаксу упита</a> за додатне информације о овој грешци.", + "error.sub-collections": "Грешка при преузимању подколекција", + "error.sub-communities": "Грешка при преузимању подзаједница", + "error.submission.sections.init-form-error": "Дошло је до грешке током иницијализације одељка, молимо проверите конфигурацију обрасца за унос. Детаљи су испод: <br> <br>", + "error.top-level-communities": "Грешка при преузимању заједница највишег нивоа", + "error.validation.license.notgranted": "Морате доделити ову лиценцу да бисте довршили свој поднесак. Ако у овом тренутку нисте у могућности да доделите ову лиценцу, можете да сачувате свој рад и вратите се касније или уклоните поднесак.", + "error.validation.pattern": "Овај унос је ограничен тренутним обрасцем: {{ pattern}}.", + "error.validation.filerequired": "Отпремање фајла је обавезно", + "error.validation.required": "Ово поље је обавезно", + "error.validation.NotValidEmail": "Овај Е-мејл није важећи Е-мејл", + "error.validation.emailTaken": "Ова Е-мејл адреса је већ заузета", + "error.validation.groupExists": "Ова група већ постоји", + "error.validation.metadata.name.invalid-pattern": "Ово поље не може да садржи тачке, зарезе или размаке. Уместо тога, користите поља Елемент и квалификатор", + "error.validation.metadata.name.max-length": "Ово поље не сме да садржи више од 32 знака", + "error.validation.metadata.namespace.max-length": "Ово поље не сме да садржи више од 256 знакова", + "error.validation.metadata.element.invalid-pattern": "Ово поље не може да садржи тачке, зарезе или размаке. Уместо тога, користите поље Квалификатор", + "error.validation.metadata.element.max-length": "Ово поље не сме да садржи више од 64 знака", + "error.validation.metadata.qualifier.invalid-pattern": "Ово поље не може да садржи тачке, зарезе или размаке", + "error.validation.metadata.qualifier.max-length": "Ово поље не сме да садржи више од 64 знака", + "feed.description": "Syndication feed", + "file-section.error.header": "Грешка при прибављању фајлова за ову ставку", + "footer.copyright": "ауторска права © 2002-{{ year}}", + "footer.link.dspace": "DSpace софтвер", + "footer.link.lyrasis": "LYRASIS", + "footer.link.cookies": "Подешавања колачића", + "footer.link.privacy-policy": "Правила о приватности", + "footer.link.end-user-agreement": "Уговор са крајњим корисником", + "footer.link.feedback": "Пошаљи повратне информације", + "forgot-email.form.header": "Заборавили сте лозинку", + "forgot-email.form.info": "Унесите Е-мејл адресу повезану са налогом.", + "forgot-email.form.email": "Е-мејл адреса *", + "forgot-email.form.email.error.required": "Унесите Е-мејл адресу", + "forgot-email.form.email.error.not-email-form": "Унесите важећу Е-мејл адресу", + "forgot-email.form.email.hint": "Е-мејл са даљим упутствима биће послат на ову адресу", + "forgot-email.form.submit": "Ресетујте лозинку", + "forgot-email.form.success.head": "Послат је Е-мејл за ресетовање лозинке", + "forgot-email.form.success.content": "Е-мејл који садржи посебну URL адресу и даља упутства биће послат на {{ email }}", + "forgot-email.form.error.head": "Грешка при покушају ресетовања лозинке", + "forgot-email.form.error.content": "Дошло је до грешке при покушају ресетовања лозинке за налог повезан са следећом адресом е-поште: {{ email }}", + "forgot-password.title": "Заборавили сте лозинку", + "forgot-password.form.head": "Заборавили сте лозинку", + "forgot-password.form.info": "Унесите нову лозинку у поље испод и потврдите је тако што ћете је поново укуцати у друго поље.", + "forgot-password.form.card.security": "Безбедност", + "forgot-password.form.identification.header": "Идентификовати", + "forgot-password.form.identification.email": "Е-мејл адреса:", + "forgot-password.form.label.password": "Лозинка", + "forgot-password.form.label.passwordrepeat": "Поново откуцајте да бисте потврдили", + "forgot-password.form.error.empty-password": "Унесите лозинку у поље испод.", + "forgot-password.form.error.matching-passwords": "Лозинке се не поклапају.", + "forgot-password.form.notification.error.title": "Грешка при покушају слања нове лозинке", + "forgot-password.form.notification.success.content": "Ресетовање лозинке је било успешно. Пријављени сте као креирани корисник.", + "forgot-password.form.notification.success.title": "Ресетовање лозинке је завршено", + "forgot-password.form.submit": "Пошаљи лозинку", + "form.add": "Додај још", + "form.add-help": "Кликните овде да додате тренутни унос и да додате још један", + "form.cancel": "Поништити, отказати", + "form.clear": "Јасно", + "form.clear-help": "Кликните овде да бисте уклонили изабрану вредност", + "form.discard": "Одбаците", + "form.drag": "Превуците", + "form.edit": "Уредите", + "form.edit-help": "Кликните овде да бисте изменили изабрану вредност", + "form.first-name": "Име", + "form.group-collapse": "Скупи", + "form.group-collapse-help": "Кликните овде за скупљање", + "form.group-expand": "Проширити", + "form.group-expand-help": "Кликните овде да бисте проширили и додали још елемената", + "form.last-name": "Презиме", + "form.loading": "Учитавање...", + "form.lookup": "Потражите", + "form.lookup-help": "Кликните овде да бисте потражили постојећу везу", + "form.no-results": "Нису пронађени резултати", + "form.no-value": "Није унета вредност", + "form.other-information.email": "Е-мејл", + "form.other-information.first-name": "Име", + "form.other-information.insolr": "У Solr индексу", + "form.other-information.institution": "Институција", + "form.other-information.last-name": "Презиме", + "form.other-information.orcid": "ORCID", + "form.remove": "Уклоните", + "form.save": "Сачувајте", + "form.save-help": "Сачувајте измене", + "form.search": "Претрага", + "form.search-help": "Кликните овде да бисте потражили постојећу преписку", + "form.submit": "Сачувајте", + "form.create": "Креирајте", + "form.repeatable.sort.tip": "Спустите ставку на нову позицију", + "grant-deny-request-copy.deny": "Не шаљи копију", + "grant-deny-request-copy.email.back": "Назад", + "grant-deny-request-copy.email.message": "Опциона додатна порука", + "grant-deny-request-copy.email.message.empty": "Унесите поруку", + "grant-deny-request-copy.email.permissions.info": "Можете искористити ову прилику да поново размотрите ограничења приступа документу, како бисте избегли да одговорите на ове захтеве. Ако желите да замолите администраторе спремишта да уклоне ова ограничења, означите поље испод.", + "grant-deny-request-copy.email.permissions.label": "Промените у отворени приступ", + "grant-deny-request-copy.email.send": "Пошаљите", + "grant-deny-request-copy.email.subject": "Предмет", + "grant-deny-request-copy.email.subject.empty": "Унесите тему", + "grant-deny-request-copy.grant": "Пошаљите копију", + "grant-deny-request-copy.header": "Захтев за копију документа", + "grant-deny-request-copy.home-page": "Врати ме на почетну страницу", + "grant-deny-request-copy.intro1": "Ако сте један од аутора документа <a href='{{ url }}'>{{ name }}</a>, онда користите једну од опција у наставку да одговорите на захтев корисника.", + "grant-deny-request-copy.intro2": "Након што одаберете опцију, биће вам представљен предложени одговор е-маила који можете да измените.", + "grant-deny-request-copy.processed": "Овај захтев је већ обрађен. Можете користити дугме испод да се вратите на почетну страницу.", + "grant-request-copy.email.subject": "Затражите копију документа", + "grant-request-copy.error": "Дошло је до грешке", + "grant-request-copy.header": "Одобрите захтев за копију документа", + "grant-request-copy.intro": "Подносиоцу захтева ће бити послата порука. Тражени документ(и) ће бити приложен.", + "grant-request-copy.success": "Захтев за ставку је успешно одобрен", + "health.breadcrumbs": "Здравље", + "health-page.heading": "Здравље", + "health-page.info-tab": "Информације", + "health-page.status-tab": "Статус", + "health-page.error.msg": "Услуга провере здравља је привремено недоступна", + "health-page.property.status": "Статусни код", + "health-page.section.db.title": "База података", + "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 апликације", + "health-page.section-info.java.title": "Java", + "health-page.status": "Статус", + "health-page.status.ok.info": "Оперативни", + "health-page.status.error.info": "Откривени су проблеми", + "health-page.status.warning.info": "Откривени су могући проблеми", + "health-page.title": "Здравље", + "health-page.section.no-issues": "Нису откривени проблеми", + "home.description": "", + "home.breadcrumbs": "Home", + "home.search-form.placeholder": "Претражите репозиторијум...", + "home.title": "Home", + "home.top-level-communities.head": "Заједнице у DSpace-у", + "home.top-level-communities.help": "Изаберите заједницу да бисте прегледали њене колекције.", + "info.end-user-agreement.accept": "Прочитао сам и прихватам Уговором са крајњим корисником", + "info.end-user-agreement.accept.error": "Дошло је до грешке при прихватању Уговора са крајњим корисником", + "info.end-user-agreement.accept.success": "Успешно ажуриран Уговор са крајњим корисником", + "info.end-user-agreement.breadcrumbs": "Уговор са крајњим корисником", + "info.end-user-agreement.buttons.cancel": "Отказати", + "info.end-user-agreement.buttons.save": "Сачувати", + "info.end-user-agreement.head": "Уговор са крајњим корисником", + "info.end-user-agreement.title": "Уговор са крајњим корисником", + "info.end-user-agreement.hosting-country": "Сједињене Државе", + "info.privacy.breadcrumbs": "Изјава о заштити приватности", + "info.privacy.head": "Изјава о заштити приватности", + "info.privacy.title": "Изјава о заштити приватности", + "info.feedback.breadcrumbs": "Повратна информација", + "info.feedback.head": "Повратна информација", + "info.feedback.title": "Повратна информација", + "info.feedback.info": "Хвала Вам што сте поделили повратне информације о DSpace систему. Ценимо Ваше коментаре!", + "info.feedback.email_help": "Ова адреса ће бити коришћена за праћење ваших повратних информација.", + "info.feedback.send": "Пошаљите повратне информације", + "info.feedback.comments": "Коментари", + "info.feedback.email-label": "Ваш Email", + "info.feedback.create.success": "Повратне информације су успешно послате!", + "info.feedback.error.email.required": "Потребна је важећа Е-мејл адреса", + "info.feedback.error.message.required": "Коментар је обавезан", + "info.feedback.page-label": "Страна", + "info.feedback.page_help": "Страница је у вези са Вашим повратним информацијама", + "item.alerts.private": "Ова ставка се не може открити", + "item.alerts.withdrawn": "Ова ставка је повучена", + "item.edit.authorizations.heading": "Помоћу овог едитора можете да прегледате и мењате опције ставке, као и да мењате опције појединачних компоненти ставке: пакете и битстрим-ове. Укратко, ставка је контејнер пакета, а пакети су контејнери битстрим-ова. Контејнери обично имају опције ДОДАВАЊЕ/БРИСАЊЕ/ЧИТАЊЕ/ПИСАЊЕ, док битстрим-ови имају само опције ЧИТАЊЕ/ПИСАЊЕ.", + "item.edit.authorizations.title": "Измените опције ставке", + "item.badge.private": "Невидљив", + "item.badge.withdrawn": "Повучено", + "item.bitstreams.upload.bundle": "Пакет", + "item.bitstreams.upload.bundle.placeholder": "Изаберите пакет или унесите ново име пакета", + "item.bitstreams.upload.bundle.new": "Креирајте пакет", + "item.bitstreams.upload.bundles.empty": "Ова ставка не садржи пакете за отпремање битстрим-ова.", + "item.bitstreams.upload.cancel": "Отказати", + "item.bitstreams.upload.drop-message": "Унесите датотеку за отпремање", + "item.bitstreams.upload.item": "Ставка:", + "item.bitstreams.upload.notifications.bundle.created.content": "Успешно креиран нови пакет.", + "item.bitstreams.upload.notifications.bundle.created.title": "Креирани пакет", + "item.bitstreams.upload.notifications.upload.failed": "Отпремање неуспешно. Молимо Вас проверите садржај пре поновног покушаја.", + "item.bitstreams.upload.title": "Отпремање битстрим-а", + "item.edit.bitstreams.bundle.edit.buttons.upload": "Отпремити", + "item.edit.bitstreams.bundle.displaying": "Тренутно се приказује {{ amount }} битстрим-ова од {{ total }}.", + "item.edit.bitstreams.bundle.load.all": "Учитајте све ({{ total }})", + "item.edit.bitstreams.bundle.load.more": "Учитајте још", + "item.edit.bitstreams.bundle.name": "ПАКЕТ: {{ name }}", + "item.edit.bitstreams.discard-button": "Одбацити", + "item.edit.bitstreams.edit.buttons.download": "Преузимање", + "item.edit.bitstreams.edit.buttons.drag": "Превуците", + "item.edit.bitstreams.edit.buttons.edit": "Изменити", + "item.edit.bitstreams.edit.buttons.remove": "Уклонити", + "item.edit.bitstreams.edit.buttons.undo": "Поништити промене", + "item.edit.bitstreams.empty": "Ова ставка не садржи битстрим-ове. Кликните на дугме за отпремање да бисте га креирали.", + "item.edit.bitstreams.headers.actions": "Радње", + "item.edit.bitstreams.headers.bundle": "Пакет", + "item.edit.bitstreams.headers.description": "Опис", + "item.edit.bitstreams.headers.format": "Формат", + "item.edit.bitstreams.headers.name": "Име", + "item.edit.bitstreams.notifications.discarded.content": "Ваше промене су одбачене. Да бисте поново поставили своје промене, кликните на дугме \"Опозови\".", + "item.edit.bitstreams.notifications.discarded.title": "Промене су одбачене", + "item.edit.bitstreams.notifications.move.failed.title": "Грешка при покретању битстрим-ова", + "item.edit.bitstreams.notifications.move.saved.content": "Промене које сте покренули у битстрим-овима и пакетима ове ставке су сачуване.", + "item.edit.bitstreams.notifications.move.saved.title": "Покренуте промене су сачуване", + "item.edit.bitstreams.notifications.outdated.content": "Ставку на којој тренутно радите је променио други корисник. Ваше тренутне промене се одбацују да би се спречили конфликти", + "item.edit.bitstreams.notifications.outdated.title": "Застареле промене", + "item.edit.bitstreams.notifications.remove.failed.title": "Грешка при брисању битстрим-а", + "item.edit.bitstreams.notifications.remove.saved.content": "Ваше измене у вези са уклањањем битстрим-ова ове ставке су сачуване.", + "item.edit.bitstreams.notifications.remove.saved.title": "Промене уклањања су сачуване", + "item.edit.bitstreams.reinstate-button": "Поништити", + "item.edit.bitstreams.save-button": "Сачувати", + "item.edit.bitstreams.upload-button": "Отпремити", + "item.edit.delete.cancel": "Отказати", + "item.edit.delete.confirm": "Избрисати", + "item.edit.delete.description": "Да ли сте сигурни да ову ставку треба потпуно избрисати? Опрез: Тренутно не би остао ниједан обрисани запис.", + "item.edit.delete.error": "Дошло је до грешке приликом брисања ставке", + "item.edit.delete.header": "Избришите ставку: {{ id }}", + "item.edit.delete.success": "Ставка је избрисана", + "item.edit.head": "Уредите ставку", + "item.edit.breadcrumbs": "Уредите ставку", + "item.edit.tabs.disabled.tooltip": "Нисте овлашћени да приступите овој картици", + "item.edit.tabs.mapper.head": "Мапирање колекције", + "item.edit.tabs.item-mapper.title": "Уређивање ставке - мапирање колекције", + "item.edit.identifiers.doi.status.UNKNOWN": "Непознато", + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "На чекању за регистрацију", + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "На чекању за резервацију", + "item.edit.identifiers.doi.status.IS_REGISTERED": "Регистровано", + "item.edit.identifiers.doi.status.IS_RESERVED": "Резервисано", + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Резервисано (на чекању за ажурирање)", + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Регистровано (на чекању за ажурирање)", + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "На чекању за ажурирање и регистрацију", + "item.edit.identifiers.doi.status.TO_BE_DELETED": "На чекању за брисање", + "item.edit.identifiers.doi.status.DELETED": "Избрисано", + "item.edit.identifiers.doi.status.PENDING": "На чекању (није регистровано)", + "item.edit.identifiers.doi.status.MINTED": "Минтед (није регистровано)", + "item.edit.tabs.status.buttons.register-doi.label": "Региструјте нови или DOI на чекању", + "item.edit.tabs.status.buttons.register-doi.button": "Региструјте DOI...", + "item.edit.register-doi.header": "Региструјте нови или DOI на чекању", + "item.edit.register-doi.description": "Прегледајте све идентификаторе и ставке метаподатака на чекању испод и кликните на Потврди да бисте наставили са DOI регистрацијом, или Откажи да бисте се повукли", + "item.edit.register-doi.confirm": "Потврдити", + "item.edit.register-doi.cancel": "Поништити, отказати", + "item.edit.register-doi.success": "DOI на чекању за регистрацију успешно.", + "item.edit.register-doi.error": "Грешка при регистрацији DOI", + "item.edit.register-doi.to-update": "Следећи DOI је већ минтед и биће на чекању за регистрацију на мрежи", + "item.edit.item-mapper.buttons.add": "Мапирајте ставку у изабране колекције", + "item.edit.item-mapper.buttons.remove": "Уклоните мапирање ставке за изабране колекције", + "item.edit.item-mapper.cancel": "Поништити, отказати", + "item.edit.item-mapper.description": "Ово је алатка за мапирање ставки која омогућава администраторима да мапирају ову ставку у друге колекције. Можете претражити колекције и мапирати их или прегледати листу колекција на које је ставка тренутно мапирана.", + "item.edit.item-mapper.head": "Мапирање ставке – мапирајте ставку у колекције", + "item.edit.item-mapper.item": "Ставка: \"<b>{{name}}</b>\"", + "item.edit.item-mapper.no-search": "Унесите упит за претрагу", + "item.edit.item-mapper.notifications.add.error.content": "Дошло је до грешака при мапирању ставке у {{amount}} колекције.", + "item.edit.item-mapper.notifications.add.error.head": "Грешке у мапирању", + "item.edit.item-mapper.notifications.add.success.content": "Ставка је успешно мапирана у {{amount}} колекције.", + "item.edit.item-mapper.notifications.add.success.head": "Мапирање је завршено", + "item.edit.item-mapper.notifications.remove.error.content": "Дошло је до грешака при уклањању мапирања на {{amount}} колекције.", + "item.edit.item-mapper.notifications.remove.error.head": "Уклањање грешака у мапирању", + "item.edit.item-mapper.notifications.remove.success.content": "Успешно је уклоњено мапирање ставке у {{amount}} колекције.", + "item.edit.item-mapper.notifications.remove.success.head": "Уклањање мапирања је завршено", + "item.edit.item-mapper.search-form.placeholder": "Претражи колекције...", + "item.edit.item-mapper.tabs.browse": "Прегледајте мапиране колекције", + "item.edit.item-mapper.tabs.map": "Мапирајте нове колекције", + "item.edit.metadata.add-button": "Додати", + "item.edit.metadata.discard-button": "Одбацити", + "item.edit.metadata.edit.buttons.confirm": "Потврдити", + "item.edit.metadata.edit.buttons.drag": "Превуците да бисте променили редослед", + "item.edit.metadata.edit.buttons.edit": "Уредити", + "item.edit.metadata.edit.buttons.remove": "Уклонити", + "item.edit.metadata.edit.buttons.undo": "Поништити промене", + "item.edit.metadata.edit.buttons.unedit": "Зауставити уређивање", + "item.edit.metadata.edit.buttons.virtual": "Ово је виртуелна вредност метаподатака, односно вредност наслеђена од повезаног ентитета. Не може се директно мењати. Додајте или уклоните одговарајући однос на картици \"Односи\".", + "item.edit.metadata.empty": "Ставка тренутно не садржи никакве метаподатке. Кликните на Додај да бисте почели да додајете вредност метаподатака.", + "item.edit.metadata.headers.edit": "Уредити", + "item.edit.metadata.headers.field": "Поље", + "item.edit.metadata.headers.language": "Језик", + "item.edit.metadata.headers.value": "Вредност", + "item.edit.metadata.metadatafield.error": "Дошло је до грешке при провери поља метаподатака", + "item.edit.metadata.metadatafield.invalid": "Изаберите важеће поље за метаподатке", + "item.edit.metadata.notifications.discarded.content": "Ваше промене су одбачене. Да бисте вратили своје промене, кликните на дугме \"Поништи\".", + "item.edit.metadata.notifications.discarded.title": "Промене су одбачене", + "item.edit.metadata.notifications.error.title": "Дошло је до грешке", + "item.edit.metadata.notifications.invalid.content": "Ваше промене нису сачуване. Уверите се да су сва поља важећа пре него што сачувате.", + "item.edit.metadata.notifications.invalid.title": "Метаподаци су неважећи", + "item.edit.metadata.notifications.outdated.content": "Ставку на којој тренутно радите је променио други корисник. Ваше тренутне промене се одбацују да би се спречили конфликти", + "item.edit.metadata.notifications.outdated.title": "Промене су застареле", + "item.edit.metadata.notifications.saved.content": "Ваше промене метаподатака ове ставке су сачуване.", + "item.edit.metadata.notifications.saved.title": "Метаподаци су сачувани", + "item.edit.metadata.reinstate-button": "Поништити", + "item.edit.metadata.reset-order-button": "Поништите промену редоследа", + "item.edit.metadata.save-button": "Сачувати", + "item.edit.modify.overview.field": "Поље", + "item.edit.modify.overview.language": "Језик", + "item.edit.modify.overview.value": "Вредност", + "item.edit.move.cancel": "Назад", + "item.edit.move.save-button": "Сачувати", + "item.edit.move.discard-button": "Одбацити", + "item.edit.move.description": "Изаберите колекцију у коју желите да преместите ову ставку. Да бисте сузили листу приказаних колекција, можете да унесете упит за претрагу у оквир.", + "item.edit.move.error": "Дошло је до грешке при покушају премештања ставке", + "item.edit.move.head": "Преместите ставку: {{id}}", + "item.edit.move.inheritpolicies.checkbox": "Смернице наслеђивања", + "item.edit.move.inheritpolicies.description": "Наследите подразумеване смернице одредишне колекције", + "item.edit.move.move": "Преместите", + "item.edit.move.processing": "Премештање...", + "item.edit.move.search.placeholder": "Унесите упит за претрагу да бисте потражили колекције", + "item.edit.move.success": "Ставка је успешно премештена", + "item.edit.move.title": "Преместите ставку", + "item.edit.private.cancel": "Поништити, отказати", + "item.edit.private.confirm": "Учините неприступачним", + "item.edit.private.description": "Да ли сте сигурни да ова ставка треба да буде неприступачна у архиви?", + "item.edit.private.error": "Дошло је до грешке при постављању неприступачне ставке", + "item.edit.private.header": "Учините ставку неприступачном: {{ id }}", + "item.edit.private.success": "Ставка је сада неприступачна", + "item.edit.public.cancel": "Поништити, отказати", + "item.edit.public.confirm": "Учините приступачним", + "item.edit.public.description": "Да ли сте сигурни да ова ставка треба да буде приступачна у архиви?", + "item.edit.public.error": "Дошло је до грешке при омогућавању видљивости ставке", + "item.edit.public.header": "Учините ставку видљивом: {{ id }}", + "item.edit.public.success": "Ставка је сада видљива", + "item.edit.reinstate.cancel": "Отказати", + "item.edit.reinstate.confirm": "Обновити", + "item.edit.reinstate.description": "Да ли сте сигурни да ову ставку треба вратити у архиву?", + "item.edit.reinstate.error": "Дошло је до грешке при враћању ставке", + "item.edit.reinstate.header": "Вратите ставку: {{ id }}", + "item.edit.reinstate.success": "Ставка је успешно враћена", + "item.edit.relationships.discard-button": "Одбацити", + "item.edit.relationships.edit.buttons.add": "Додати", + "item.edit.relationships.edit.buttons.remove": "Уклонити", + "item.edit.relationships.edit.buttons.undo": "Поништити промене", + "item.edit.relationships.no-relationships": "Нема релација", + "item.edit.relationships.notifications.discarded.content": "Ваше промене су одбачене. Да бисте вратили своје промене, кликните на дугме \"Поништити\".", + "item.edit.relationships.notifications.discarded.title": "Промене су одбачене", + "item.edit.relationships.notifications.failed.title": "Грешка при измени релација", + "item.edit.relationships.notifications.outdated.content": "Ставку на којој тренутно радите је променио други корисник. Ваше тренутне промене су одбачене да би се спречили конфликти", + "item.edit.relationships.notifications.outdated.title": "Застареле промене", + "item.edit.relationships.notifications.saved.content": "Ваше промене у релацијама ове ставке су сачуване.", + "item.edit.relationships.notifications.saved.title": "Релације су сачуване", + "item.edit.relationships.reinstate-button": "Поништи", + "item.edit.relationships.save-button": "Сачувати", + "item.edit.relationships.no-entity-type": "Додајте метаподатке \"DSpace.entity.type\" да бисте омогућили релације за ову ставку", + "item.edit.return": "Назад", + "item.edit.tabs.bitstreams.head": "битстрим-ови", + "item.edit.tabs.bitstreams.title": "Измена ставке - битстрим-ови", + "item.edit.tabs.curate.head": "Курирање", + "item.edit.tabs.curate.title": "Измена ставке - Курирање", + "item.edit.curate.title": "Курирање ставке: {{item}}", + "item.edit.tabs.access-control.head": "Контрола приступа", + "item.edit.tabs.access-control.title": "Измена ставке - Контрола приступа", + "item.edit.tabs.metadata.head": "Метаподаци", + "item.edit.tabs.metadata.title": "Измена ставке – Метаподаци", + "item.edit.tabs.relationships.head": "Релације", + "item.edit.tabs.relationships.title": "Измена ставке - Релације", + "item.edit.tabs.status.buttons.authorizations.button": "Овлашћења...", + "item.edit.tabs.status.buttons.authorizations.label": "Измените смернице овлашћења ставке", + "item.edit.tabs.status.buttons.delete.button": "Трајно избрисати", + "item.edit.tabs.status.buttons.delete.label": "Потпуно избрисати ставку", + "item.edit.tabs.status.buttons.mappedCollections.button": "Мапиране колекције", + "item.edit.tabs.status.buttons.mappedCollections.label": "Управљајте мапираним колекцијама", + "item.edit.tabs.status.buttons.move.button": "Премести ову ставку у другу колекцију", + "item.edit.tabs.status.buttons.move.label": "Премести ставку у другу колекцију", + "item.edit.tabs.status.buttons.private.button": "Поставите да буде невидљиво...", + "item.edit.tabs.status.buttons.private.label": "Поставите ставку да буде невидљива", + "item.edit.tabs.status.buttons.public.button": "Поставите да буде видљиво...", + "item.edit.tabs.status.buttons.public.label": "Поставите ставку да буде видљива", + "item.edit.tabs.status.buttons.reinstate.button": "Поново поставите...", + "item.edit.tabs.status.buttons.reinstate.label": "Вратите ставку у репозиторијум", + "item.edit.tabs.status.buttons.unauthorized": "Нисте овлашћени да извршите ову радњу", + "item.edit.tabs.status.buttons.withdraw.button": "Повуците ову ставку", + "item.edit.tabs.status.buttons.withdraw.label": "Повуците ставку из репозиторијума", + "item.edit.tabs.status.description": "Добродошли на страницу за управљање ставкама. Одавде можете повући, вратити, преместити или избрисати ставку. Такође можете ажурирати или додати нове метаподатке / битстрим-ове на другим картицама.", + "item.edit.tabs.status.head": "Статус", + "item.edit.tabs.status.labels.handle": "Handle", + "item.edit.tabs.status.labels.id": "Интерни ID ставке", + "item.edit.tabs.status.labels.itemPage": "Страница ставке", + "item.edit.tabs.status.labels.lastModified": "Последња измена", + "item.edit.tabs.status.title": "Измена ставке - Статус", + "item.edit.tabs.versionhistory.head": "Историја верзија", + "item.edit.tabs.versionhistory.title": "Измена ставке - Историја верзија", + "item.edit.tabs.versionhistory.under-construction": "Измена или додавање нових верзија још увек није могуће у овом корисничком интерфејсу.", + "item.edit.tabs.view.head": "Прикажи ставку", + "item.edit.tabs.view.title": "Измени ставку - Прикажи", + "item.edit.withdraw.cancel": "Отказати", + "item.edit.withdraw.confirm": "Повуците", + "item.edit.withdraw.description": "Да ли сте сигурни да ову ставку треба повући из архиве?", + "item.edit.withdraw.error": "Дошло је до грешке при повлачењу ставке", + "item.edit.withdraw.header": "Повуците ставку: {{ id }}", + "item.edit.withdraw.success": "Ставка је успешно повучена", + "item.orcid.return": "Назад", + "item.listelement.badge": "Ставка", + "item.page.description": "Опис", + "item.page.journal-issn": "ISSN часописа", + "item.page.journal-title": "Наслов часописа", + "item.page.publisher": "Издавач", + "item.page.titleprefix": "Ставка:", + "item.page.volume-title": "Наслов свеске", + "item.search.results.head": "Резултати претраге ставки", + "item.search.title": "Претрага ставке", + "item.truncatable-part.show-more": "Прикажите још", + "item.truncatable-part.show-less": "Скупити", + "workflow-item.search.result.delete-supervision.modal.header": "Избришите налог за надзор", + "workflow-item.search.result.delete-supervision.modal.info": "Да ли сте сигурни да желите да избришете налог за надзор", + "workflow-item.search.result.delete-supervision.modal.cancel": "Отказати", + "workflow-item.search.result.delete-supervision.modal.confirm": "Избрисати", + "workflow-item.search.result.notification.deleted.success": "Успешно је избрисан налог за надзор \"{{name}}\"", + "workflow-item.search.result.notification.deleted.failure": "Неуспешно брисање налога за надзор \"{{name}}\"", + "workflow-item.search.result.list.element.supervised-by": "Прегледао:", + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Уклонити групу за надзор", + "item.page.abstract": "Сажетак", + "item.page.author": "Аутори", + "item.page.citation": "Цитат", + "item.page.collections": "Колекције", + "item.page.collections.loading": "Учитавање...", + "item.page.collections.load-more": "Учитајте још", + "item.page.date": "Датум", + "item.page.edit": "Измените ову ставку", + "item.page.files": "Фајлови", + "item.page.filesection.description": "Опис:", + "item.page.filesection.download": "Преузимање", + "item.page.filesection.format": "Формат:", + "item.page.filesection.name": "име:", + "item.page.filesection.size": "Величина:", + "item.page.journal.search.title": "Чланци у овом часопису", + "item.page.link.full": "Пун запис ставке", + "item.page.link.simple": "Једноставан запис ставке", + "item.page.orcid.title": "ORCID", + "item.page.orcid.tooltip": "Отворите страницу за подешавање ORCID-а", + "item.page.person.search.title": "Чланци овог аутора", + "item.page.related-items.view-more": "Прикажи још {{ amount }}", + "item.page.related-items.view-less": "Сакриј последњи {{ amount }}", + "item.page.relationships.isAuthorOfPublication": "Публикације", + "item.page.relationships.isJournalOfPublication": "Публикације", + "item.page.relationships.isOrgUnitOfPerson": "Аутори", + "item.page.relationships.isOrgUnitOfProject": "Истраживачки пројекти", + "item.page.subject": "Кључне речи", + "item.page.uri": "URI", + "item.page.bitstreams.view-more": "Прикажи више", + "item.page.bitstreams.collapse": "Скупити", + "item.page.filesection.original.bundle": "Оригинални пакет", + "item.page.filesection.license.bundle": "Лиценцни пакет", + "item.page.return": "Назад", + "item.page.version.create": "Креирајте нову верзију", + "item.page.version.hasDraft": "Нова верзија се не може креирати зато што је у току подношење", + "item.page.claim.button": "Потврда", + "item.page.claim.tooltip": "Потврди ову ставку као профил", + "item.preview.dc.identifier.uri": "Идентификатор:", + "item.preview.dc.contributor.author": "Аутори:", + "item.preview.dc.date.issued": "Датум објављивања:", + "item.preview.dc.description.abstract": "Сажетак:", + "item.preview.dc.identifier.other": "Други идентификатор:", + "item.preview.dc.language.iso": "Језик:", + "item.preview.dc.subject": "Предмети:", + "item.preview.dc.title": "Наслов:", + "item.preview.dc.type": "Тип:", + "item.preview.oaire.citation.issue": "Издање", + "item.preview.oaire.citation.volume": "Опсег", + "item.preview.dc.relation.issn": "ISSN", + "item.preview.dc.identifier.isbn": "ISBN", + "item.preview.dc.identifier": "Идентификатор:", + "item.preview.dc.relation.ispartof": "Часопис или серија", + "item.preview.dc.identifier.doi": "DOI", + "item.preview.dc.publisher": "Издавач:", + "item.preview.person.familyName": "презиме:", + "item.preview.person.givenName": "Име:", + "item.preview.person.identifier.orcid": "ORCID:", + "item.preview.project.funder.name": "Финансијер:", + "item.preview.project.funder.identifier": "Идентификатор финансијера:", + "item.preview.oaire.awardNumber": "ID финансирања:", + "item.preview.dc.title.alternative": "Акроним:", + "item.preview.dc.coverage.spatial": "Јурисдикција:", + "item.preview.oaire.fundingStream": "Ток финансирања:", + "item.select.confirm": "Потврдите изабрано", + "item.select.empty": "Нема ставки за приказ", + "item.select.table.author": "Аутор", + "item.select.table.collection": "Колекција", + "item.select.table.title": "Наслов", + "item.version.history.empty": "Још увек нема других верзија за ову ставку.", + "item.version.history.head": "Историја верзија", + "item.version.history.return": "Назад", + "item.version.history.selected": "Изабрана верзија", + "item.version.history.selected.alert": "Тренутно гледате верзију {{version}} ставке.", + "item.version.history.table.version": "Верзија", + "item.version.history.table.item": "Ставка", + "item.version.history.table.editor": "Уредник", + "item.version.history.table.date": "Датум", + "item.version.history.table.summary": "Резиме", + "item.version.history.table.workspaceItem": "Ставка радног простора", + "item.version.history.table.workflowItem": "Ставка процеса рада", + "item.version.history.table.actions": "Поступак", + "item.version.history.table.action.editWorkspaceItem": "Уредите ставку радног простора", + "item.version.history.table.action.editSummary": "Уредите резиме", + "item.version.history.table.action.saveSummary": "Сачувајте измене резимеа", + "item.version.history.table.action.discardSummary": "Одбаците измене резимеа", + "item.version.history.table.action.newVersion": "Креирајте нову верзију од овог", + "item.version.history.table.action.deleteVersion": "Избришите верзију", + "item.version.history.table.action.hasDraft": "Нова верзија се не може креирати зато што је у току прихват у историји верзија", + "item.version.notice": "Ово није најновија верзија ове ставке. Најновију верзију можете пронаћи <a href='{{destination}}'>овде</a>.", + "item.version.create.modal.header": "Нова верзија", + "item.version.create.modal.text": "Направите нову верзију за ову ставку", + "item.version.create.modal.text.startingFrom": "почевши од верзије {{version}}", + "item.version.create.modal.button.confirm": "Креирајте", + "item.version.create.modal.button.confirm.tooltip": "Креирајте нову верзију", + "item.version.create.modal.button.cancel": "Поништити, отказати", + "item.version.create.modal.button.cancel.tooltip": "Не креирајте нову верзију", + "item.version.create.modal.form.summary.label": "Резиме", + "item.version.create.modal.form.summary.placeholder": "Убаците резиме за нову верзију", + "item.version.create.modal.submitted.header": "Креирање нове верзије...", + "item.version.create.modal.submitted.text": "Нова верзија је у изради. Ово може потрајати неко време ако ставка има много веза.", + "item.version.create.notification.success": "Нова верзија је направљена са бројем верзије {{version}}", + "item.version.create.notification.failure": "Нова верзија није креирана", + "item.version.create.notification.inProgress": "Нова верзија се не може креирати зато што је у току прихват у историји верзија", + "item.version.delete.modal.header": "Избришите верзију", + "item.version.delete.modal.text": "Да ли желите да избришете верзију {{version}}?", + "item.version.delete.modal.button.confirm": "Избришите", + "item.version.delete.modal.button.confirm.tooltip": "Избришите ову верзију", + "item.version.delete.modal.button.cancel": "Поништити, отказати", + "item.version.delete.modal.button.cancel.tooltip": "Немојте брисати ову верзију", + "item.version.delete.notification.success": "Верзија број {{version}} је избрисана", + "item.version.delete.notification.failure": "Верзија број {{version}} није избрисана", + "item.version.edit.notification.success": "Сажетак верзије број {{version}} је промењен", + "item.version.edit.notification.failure": "Сажетак верзије број {{version}} није промењен", + "itemtemplate.edit.metadata.add-button": "Додати", + "itemtemplate.edit.metadata.discard-button": "Одбацити", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Потврдити", + "itemtemplate.edit.metadata.edit.buttons.drag": "Превуците да бисте променили редослед", + "itemtemplate.edit.metadata.edit.buttons.edit": "Изменити", + "itemtemplate.edit.metadata.edit.buttons.remove": "Уклонити", + "itemtemplate.edit.metadata.edit.buttons.undo": "Поништити промене", + "itemtemplate.edit.metadata.edit.buttons.unedit": "Зауставите измене", + "itemtemplate.edit.metadata.empty": "Шаблон ставке тренутно не садржи никакве метаподатке. Кликните на Додај да бисте започели додавање вредности метаподатака.", + "itemtemplate.edit.metadata.headers.edit": "Изменити", + "itemtemplate.edit.metadata.headers.field": "Поље", + "itemtemplate.edit.metadata.headers.language": "Језик", + "itemtemplate.edit.metadata.headers.value": "Вредност", + "itemtemplate.edit.metadata.metadatafield.error": "Дошло је до грешке приликом провере поља метаподатака", + "itemtemplate.edit.metadata.metadatafield.invalid": "Молимо изаберите важеће поље метаподатака", + "itemtemplate.edit.metadata.notifications.discarded.content": "Ваше промене су одбачене. Да бисте вратили своје промене, кликните на дугме \"Поништи\".", + "itemtemplate.edit.metadata.notifications.discarded.title": "Промене су одбачене", + "itemtemplate.edit.metadata.notifications.error.title": "Дошло је до грешке", + "itemtemplate.edit.metadata.notifications.invalid.content": "Ваше промене нису сачуване. Молимо проверите да ли су сва поља исправна пре него што сачувате.", + "itemtemplate.edit.metadata.notifications.invalid.title": "Метаподаци су неважећи", + "itemtemplate.edit.metadata.notifications.outdated.content": "Други корисник је променио шаблон ставке на коме тренутно радите. Ваше тренутне промене се одбацују да би се спречили конфликти", + "itemtemplate.edit.metadata.notifications.outdated.title": "Промене су застареле", + "itemtemplate.edit.metadata.notifications.saved.content": "Ваше промене метаподатака овог шаблона ставке су сачуване.", + "itemtemplate.edit.metadata.notifications.saved.title": "Метаподаци су сачувани", + "itemtemplate.edit.metadata.reinstate-button": "Поништити", + "itemtemplate.edit.metadata.reset-order-button": "Поништити промену редоследа", + "itemtemplate.edit.metadata.save-button": "Сачувати", + "journal.listelement.badge": "Часопис", + "journal.page.description": "Опис", + "journal.page.edit": "Уредите ову ставку", + "journal.page.editor": "Главни уредник", + "journal.page.issn": "ISSN", + "journal.page.publisher": "Издавач", + "journal.page.titleprefix": "Часопис:", + "journal.search.results.head": "Резултати претраге часописа", + "journal-relationships.search.results.head": "Резултати претраге часописа", + "journal.search.title": "Претрага часописа", + "journalissue.listelement.badge": "Издање часописа", + "journalissue.page.description": "Опис", + "journalissue.page.edit": "Измените ову ставку", + "journalissue.page.issuedate": "Датум издања", + "journalissue.page.journal-issn": "Часопис ISSN", + "journalissue.page.journal-title": "Наслов часописа", + "journalissue.page.keyword": "Кључне речи", + "journalissue.page.number": "Број", + "journalissue.page.titleprefix": "Издање часописа:", + "journalvolume.listelement.badge": "Свеска часописа", + "journalvolume.page.description": "Опис", + "journalvolume.page.edit": "Измените ову ставку", + "journalvolume.page.issuedate": "Датум издања", + "journalvolume.page.titleprefix": "Свеска часописа:", + "journalvolume.page.volume": "Свеска", + "iiifsearchable.listelement.badge": "Списак медија", + "iiifsearchable.page.titleprefix": "Документ:", + "iiifsearchable.page.doi": "Трајна веза:", + "iiifsearchable.page.issue": "Издање:", + "iiifsearchable.page.description": "Опис:", + "iiifviewer.fullscreen.notice": "Користите цео екран да боље видите.", + "iiif.listelement.badge": "Имаге Медиа", + "iiif.page.titleprefix": "Слика:", + "iiif.page.doi": "Трајна веза:", + "iiif.page.issue": "Издање:", + "iiif.page.description": "Опис:", + "loading.bitstream": "Учитавање битстрим-а...", + "loading.bitstreams": "Учитавање битстрим-ова...", + "loading.browse-by": "Учитавање ставки...", + "loading.browse-by-page": "Учитавање странице...", + "loading.collection": "Учитавање колекције...", + "loading.collections": "Учитавање колекција...", + "loading.content-source": "Учитавање извора садржаја...", + "loading.community": "Учитавање заједнице...", + "loading.default": "Учитавање...", + "loading.item": "Учитавање ставке...", + "loading.items": "Учитавање ставки...", + "loading.mydspace-results": "Учитавање ставки...", + "loading.objects": "Учитавање...", + "loading.recent-submissions": "Учитавање недавних поднесака...", + "loading.search-results": "Учитавање резултата претраге...", + "loading.sub-collections": "Учитавање потколекција...", + "loading.sub-communities": "Учитавање подзаједница...", + "loading.top-level-communities": "Учитавање заједница највишег нивоа...", + "login.form.email": "Емаил адреса", + "login.form.forgot-password": "Заборавили сте лозинку?", + "login.form.header": "Молимо пријавите се на DSpace", + "login.form.new-user": "Нови корисник? Кликните овде да се региструјете.", + "login.form.or-divider": "или", + "login.form.oidc": "Пријавите се са OIDC", + "login.form.orcid": "Пријавите се са ORCID-ом", + "login.form.password": "Лозинка", + "login.form.shibboleth": "Пријавите се са Shibboleth", + "login.form.submit": "Пријавите се", + "login.title": "Пријавите се", + "login.breadcrumbs": "Пријавите се", + "logout.form.header": "Одјавите се са DSpace-а", + "logout.form.submit": "Одјавите се", + "logout.title": "Одјавите се", + "menu.header.admin": "Менаџмент", + "menu.header.image.logo": "Лого репозиторијума", + "menu.header.admin.description": "Менаџмент мени", + "menu.section.access_control": "Контрола приступа", + "menu.section.access_control_authorizations": "Овлашћења", + "menu.section.access_control_bulk": "Управљање масовним приступом", + "menu.section.access_control_groups": "Групе", + "menu.section.access_control_people": "Људи", + "menu.section.admin_search": "Админ претрага", + "menu.section.browse_community": "Ова заједница", + "menu.section.browse_community_by_author": "По аутору", + "menu.section.browse_community_by_issue_date": "По датуму издања", + "menu.section.browse_community_by_title": "По наслову", + "menu.section.browse_global": "Читав репозиторијум", + "menu.section.browse_global_by_author": "По аутору", + "menu.section.browse_global_by_dateissued": "По датуму издања", + "menu.section.browse_global_by_subject": "По предмету", + "menu.section.browse_global_by_srsc": "По категорији предмета", + "menu.section.browse_global_by_title": "По наслову", + "menu.section.browse_global_communities_and_collections": "Заједнице и колекције", + "menu.section.control_panel": "Контролна табла", + "menu.section.curation_task": "Куративни задатак", + "menu.section.edit": "Уредити", + "menu.section.edit_collection": "Колекција", + "menu.section.edit_community": "Заједница", + "menu.section.edit_item": "Ставка", + "menu.section.export": "Извоз", + "menu.section.export_collection": "Колекција", + "menu.section.export_community": "Заједница", + "menu.section.export_item": "Ставка", + "menu.section.export_metadata": "Метаподаци", + "menu.section.export_batch": "Групни извоз (ZIP)", + "menu.section.icon.access_control": "Одељак менија Контрола приступа", + "menu.section.icon.admin_search": "Одељак менија за админ претрагу", + "menu.section.icon.control_panel": "Одељак менија контролне табле", + "menu.section.icon.curation_tasks": "Одељак менија Задатак курирања", + "menu.section.icon.edit": "Уредите одељак менија", + "menu.section.icon.export": "Извезите одељак менија", + "menu.section.icon.find": "Пронађите одељак менија", + "menu.section.icon.health": "Одељак менија за здравствену проверу", + "menu.section.icon.import": "Увезите одељак менија", + "menu.section.icon.new": "Нови одељак менија", + "menu.section.icon.pin": "Закачите бочну траку", + "menu.section.icon.processes": "Процеси провере здравља", + "menu.section.icon.registries": "Одељак менија Регистри", + "menu.section.icon.statistics_task": "Одељак менија Статистички задатак", + "menu.section.icon.workflow": "Одељак менија Администрација процеса рада", + "menu.section.icon.unpin": "Откачите бочну траку", + "menu.section.import": "Увоз", + "menu.section.import_batch": "Групни увоз (ZIP)", + "menu.section.import_metadata": "Метаподаци", + "menu.section.new": "Ново", + "menu.section.new_collection": "Колекција", + "menu.section.new_community": "Заједница", + "menu.section.new_item": "Ставка", + "menu.section.new_item_version": "Верзија ставке", + "menu.section.new_process": "Процес", + "menu.section.pin": "Закачите бочну траку", + "menu.section.unpin": "Откачите бочну траку", + "menu.section.processes": "Процеси", + "menu.section.health": "Здравље", + "menu.section.registries": "Регистри", + "menu.section.registries_format": "Формат", + "menu.section.registries_metadata": "Метаподаци", + "menu.section.statistics": "Статистика", + "menu.section.statistics_task": "Статистички задатак", + "menu.section.toggle.access_control": "Укључите одељак Контрола приступа", + "menu.section.toggle.control_panel": "Укључите одељак Контролна табла", + "menu.section.toggle.curation_task": "Укључи/искључи одељак Задатак курирања", + "menu.section.toggle.edit": "Укључите одељак Уреди", + "menu.section.toggle.export": "Укључите одељак Извези", + "menu.section.toggle.find": "Укључи одељак Пронађи", + "menu.section.toggle.import": "Укључите одељак Увези", + "menu.section.toggle.new": "Укључите нови одељак", + "menu.section.toggle.registries": "Укључите одељак Регистри", + "menu.section.toggle.statistics_task": "Укључи/искључи одељак статистички задатак", + "menu.section.workflow": "Администрација процеса рада", + "metadata-export-search.tooltip": "Извезите резултате претраге као CSV", + "metadata-export-search.submit.success": "Извоз је успешно започет", + "metadata-export-search.submit.error": "Покретање извоза није успело", + "mydspace.breadcrumbs": "Мој DSpace", + "mydspace.description": "", + "mydspace.messages.controller-help": "Изаберите ову опцију да бисте послали поруку подносиоцу ставке.", + "mydspace.messages.description-placeholder": "Унесите своју поруку овде...", + "mydspace.messages.hide-msg": "Сакријте поруку", + "mydspace.messages.mark-as-read": "Означите као прочитано", + "mydspace.messages.mark-as-unread": "Означите као непрочитану", + "mydspace.messages.no-content": "Без садржаја.", + "mydspace.messages.no-messages": "Још нема порука.", + "mydspace.messages.send-btn": "Пошаљи", + "mydspace.messages.show-msg": "Прикажи поруку", + "mydspace.messages.subject-placeholder": "Предмет...", + "mydspace.messages.submitter-help": "Изаберите ову опцију да бисте послали поруку контролору.", + "mydspace.messages.title": "Поруке", + "mydspace.messages.to": "До", + "mydspace.new-submission": "Нови поднесак", + "mydspace.new-submission-external": "Увезите метаподатке из спољног извора", + "mydspace.new-submission-external-short": "Увезите метаподатке", + "mydspace.results.head": "Ваши поднесци", + "mydspace.results.no-abstract": "Нема сажетка", + "mydspace.results.no-authors": "Нема аутора", + "mydspace.results.no-collections": "Нема колекција", + "mydspace.results.no-date": "Нема датума", + "mydspace.results.no-files": "Нема фајлова", + "mydspace.results.no-results": "Нема ставки за приказ", + "mydspace.results.no-title": "Без наслова", + "mydspace.results.no-uri": "Нема URI", + "mydspace.search-form.placeholder": "Претрага у MyDSpace...", + "mydspace.show.workflow": "Радни задаци", + "mydspace.show.workspace": "Ваши поднесци", + "mydspace.show.supervisedWorkspace": "Надзиране ставке", + "mydspace.status.mydspaceArchived": "Архивирано", + "mydspace.status.mydspaceValidation": "Валидација", + "mydspace.status.mydspaceWaitingController": "Чека се контролер", + "mydspace.status.mydspaceWorkflow": "Радни процес", + "mydspace.status.mydspaceWorkspace": "Радни простор", + "mydspace.title": "MyDSpace", + "mydspace.upload.upload-failed": "Грешка при креирању новог радног простора. Молимо проверите отпремљени садржај пре него што покушате поново.", + "mydspace.upload.upload-failed-manyentries": "Необрађен фајл. Откривено је превише уноса, али је дозвољен само за један фајл.", + "mydspace.upload.upload-failed-moreonefile": "Необрађен захтев. Дозвољен је само један фајл.", + "mydspace.upload.upload-multiple-successful": "{{qty}} нових ставки радног простора је креирано.", + "mydspace.view-btn": "Поглед", + "nav.browse.header": "Читав репозиторијум", + "nav.community-browse.header": "Од заједнице", + "nav.context-help-toggle": "Укључите додатну помоћ", + "nav.language": "Промена језика", + "nav.login": "Пријави се", + "nav.user-profile-menu-and-logout": "Мени корисничког профила и одјава", + "nav.logout": "Одјавити се", + "nav.main.description": "Главна навигациона трака", + "nav.mydspace": "MyDSpace", + "nav.profile": "Профил", + "nav.search": "Претрага", + "nav.search.button": "Пошаљите претрагу", + "nav.statistics.header": "Статистика", + "nav.stop-impersonating": "Престаните да се представљате као EPerson", + "nav.subscriptions": "Претплате", + "nav.toggle": "Укључивање навигације", + "nav.user.description": "Трака корисничког профила", + "none.listelement.badge": "Ставка", + "orgunit.listelement.badge": "Организациона јединица", + "orgunit.listelement.no-title": "Без наслова", + "orgunit.page.city": "Град", + "orgunit.page.country": "Држава", + "orgunit.page.dateestablished": "Датум постављања", + "orgunit.page.description": "Опис", + "orgunit.page.edit": "Изменити ову ставку", + "orgunit.page.id": "ID", + "orgunit.page.titleprefix": "Организациона јединица:", + "pagination.options.description": "Опције страничења", + "pagination.results-per-page": "Резултати по страници", + "pagination.showing.detail": "{{ range }} од {{ total }}", + "pagination.showing.label": "Приказује се ", + "pagination.sort-direction": "Опције сортирања", + "person.listelement.badge": "Особа", + "person.listelement.no-title": "Име није пронађено", + "person.page.birthdate": "Датум рођења", + "person.page.edit": "Изменити ову ставку", + "person.page.email": "Емаил адреса", + "person.page.firstname": "Име", + "person.page.jobtitle": "Звање", + "person.page.lastname": "Презиме", + "person.page.name": "Име", + "person.page.link.full": "Прикажи све метаподатке", + "person.page.orcid": "ORCID", + "person.page.staffid": "ID запослених", + "person.page.titleprefix": "Особа:", + "person.search.results.head": "Резултати претраге особа", + "person-relationships.search.results.head": "Резултати претраге особа", + "person.search.title": "Претрага особа", + "process.new.select-parameters": "Параметри", + "process.new.cancel": "Отказати", + "process.new.submit": "Сачувати", + "process.new.select-script": "Скрипта", + "process.new.select-script.placeholder": "Изаберите скрипту...", + "process.new.select-script.required": "Скрипта је обавезна", + "process.new.parameter.file.upload-button": "Изаберите фајл...", + "process.new.parameter.file.required": "Молимо изаберите фајл", + "process.new.parameter.string.required": "Вредност параметра је обавезна", + "process.new.parameter.type.value": "вредност", + "process.new.parameter.type.file": "фајл", + "process.new.parameter.required.missing": "Следећи параметри су обавезни, али још увек недостају:", + "process.new.notification.success.title": "Успех", + "process.new.notification.success.content": "Процес је успешно креиран", + "process.new.notification.error.title": "Грешка", + "process.new.notification.error.content": "Дошло је до грешке при креирању овог процеса", + "process.new.notification.error.max-upload.content": "Фајл превазилази максималну величину за отпремање", + "process.new.header": "Креирајте нови процес", + "process.new.title": "Креирајте нови процес", + "process.new.breadcrumbs": "Креирајте нови процес", + "process.detail.arguments": "Аргументи", + "process.detail.arguments.empty": "Овај процес не садржи аргументе", + "process.detail.back": "Назад", + "process.detail.output": "Излаз процеса", + "process.detail.logs.button": "Преузмите излаз процеса", + "process.detail.logs.loading": "Преузимање", + "process.detail.logs.none": "Овај процес нема излаз", + "process.detail.output-files": "Излазни фајлови", + "process.detail.output-files.empty": "Овај процес не садржи излазне фајлове", + "process.detail.script": "Скрипта", + "process.detail.title": "Процес: {{ id }} - {{ name }}", + "process.detail.start-time": "Време почетка", + "process.detail.end-time": "Време завршетка", + "process.detail.status": "Статус", + "process.detail.create": "Направите сличан процес", + "process.detail.actions": "Акције", + "process.detail.delete.button": "Избришите процес", + "process.detail.delete.header": "Избришите процес", + "process.detail.delete.body": "Да ли сте сигурни да желите да избришете тренутни процес?", + "process.detail.delete.cancel": "Поништити, отказати", + "process.detail.delete.confirm": "Избришите процес", + "process.detail.delete.success": "Процес је успешно обрисан.", + "process.detail.delete.error": "Нешто је пошло наопако приликом брисања процеса", + "process.overview.table.finish": "Време завршетка (UTC)", + "process.overview.table.id": "ID процеса", + "process.overview.table.name": "Име", + "process.overview.table.start": "Време почетка (UTC)", + "process.overview.table.status": "Статус", + "process.overview.table.user": "Корисник", + "process.overview.title": "Преглед процеса", + "process.overview.breadcrumbs": "Преглед процеса", + "process.overview.new": "Ново", + "process.overview.table.actions": "Акције", + "process.overview.delete": "Избришите {{count}} процеса", + "process.overview.delete.clear": "Очистите избор за брисање", + "process.overview.delete.processing": "Бришу се процеси ({{count}}). Сачекајте да се брисање у потпуности заврши. Имајте на уму да ово може потрајати.", + "process.overview.delete.body": "Да ли сте сигурни да желите да избришете {{count}} процес(е)?", + "process.overview.delete.header": "Избришите процесе", + "process.bulk.delete.error.head": "Грешка у процесу брисања", + "process.bulk.delete.error.body": "Није могуће избрисати процес са ID-ом {{processId}}. Преостали процеси ће наставити да се бришу.", + "process.bulk.delete.success": "Процеси ({{count}}) су успешно избрисани", + "profile.breadcrumbs": "Ажурирање профила", + "profile.card.identify": "Идентитет", + "profile.card.security": "Безбедност", + "profile.form.submit": "Сачувати", + "profile.groups.head": "Групе овлашћења којима припадате", + "profile.special.groups.head": "Ауторизација посебних група којима припадате", + "profile.head": "Ажурирање профил", + "profile.metadata.form.error.firstname.required": "Име је обавезно", + "profile.metadata.form.error.lastname.required": "Презиме је обавезно", + "profile.metadata.form.label.email": "Емаил адреса", + "profile.metadata.form.label.firstname": "Име", + "profile.metadata.form.label.language": "Језик", + "profile.metadata.form.label.lastname": "Презиме", + "profile.metadata.form.label.phone": "Контакт телефон", + "profile.metadata.form.notifications.success.content": "Ваше промене на профилу су сачуване.", + "profile.metadata.form.notifications.success.title": "Профил је сачуван", + "profile.notifications.warning.no-changes.content": "Нису направљене никакве промене на профилу.", + "profile.notifications.warning.no-changes.title": "Без промене", + "profile.security.form.error.matching-passwords": "Лозинке се не поклапају.", + "profile.security.form.info": "Опционо, можете да унесете нову лозинку у поље испод и потврдите је тако што ћете је поново укуцати у друго поље.", + "profile.security.form.label.password": "Лозинка", + "profile.security.form.label.passwordrepeat": "Поново откуцајте да бисте потврдили", + "profile.security.form.label.current-password": "Тренутна лозинка", + "profile.security.form.notifications.success.content": "Ваше промене лозинке су сачуване.", + "profile.security.form.notifications.success.title": "Лозинка је сачувана", + "profile.security.form.notifications.error.title": "Грешка при промени лозинки", + "profile.security.form.notifications.error.change-failed": "Дошло је до грешке при покушају промене лозинке. Проверите да ли је тренутна лозинка тачна.", + "profile.security.form.notifications.error.not-same": "Наведене лозинке нису исте.", + "profile.security.form.notifications.error.general": "Попуните обавезна поља безбедносног обрасца.", + "profile.title": "Ажурирање профила", + "profile.card.researcher": "Профил истраживача", + "project.listelement.badge": "Истраживачки пројекат", + "project.page.contributor": "Сарадници", + "project.page.description": "Опис", + "project.page.edit": "Уредите ову ставку", + "project.page.expectedcompletion": "Очекивани завршетак", + "project.page.funder": "финансијери", + "project.page.id": "ID", + "project.page.keyword": "Кључне речи", + "project.page.status": "Статус", + "project.page.titleprefix": "Истраживачки пројекат:", + "project.search.results.head": "Резултати претраге пројекта", + "project-relationships.search.results.head": "Резултати претраге пројекта", + "publication.listelement.badge": "Публикација", + "publication.page.description": "Опис", + "publication.page.edit": "Уредите ову ставку", + "publication.page.journal-issn": "Часопис ISSN", + "publication.page.journal-title": "Наслов часописа", + "publication.page.publisher": "Издавач", + "publication.page.titleprefix": "Публикација:", + "publication.page.volume-title": "Наслов свеске", + "publication.search.results.head": "Резултати претраге публикације", + "publication-relationships.search.results.head": "Резултати претраге публикације", + "publication.search.title": "Претрага публикација", + "media-viewer.next": "Следеће", + "media-viewer.previous": "Претходно", + "media-viewer.playlist": "Плаy листа", + "register-email.title": "Регистрација новог корисника", + "register-page.create-profile.header": "Направите профил", + "register-page.create-profile.identification.header": "Идентификовати", + "register-page.create-profile.identification.email": "Емаил адреса", + "register-page.create-profile.identification.first-name": "Име *", + "register-page.create-profile.identification.first-name.error": "Молимо унесите име", + "register-page.create-profile.identification.last-name": "Презиме *", + "register-page.create-profile.identification.last-name.error": "Молимо унесите презиме", + "register-page.create-profile.identification.contact": "Контакт телефон", + "register-page.create-profile.identification.language": "Језик", + "register-page.create-profile.security.header": "Безбедност", + "register-page.create-profile.security.info": "Молимо унесите лозинку у поље испод и потврдите је тако што ћете је поново унети у друго поље.", + "register-page.create-profile.security.label.password": "Лозинка *", + "register-page.create-profile.security.label.passwordrepeat": "Унесите поново да потврдите *", + "register-page.create-profile.security.error.empty-password": "Молимо унесите лозинку у поље испод.", + "register-page.create-profile.security.error.matching-passwords": "Лозинке се не поклапају.", + "register-page.create-profile.submit": "Завршите регистрацију", + "register-page.create-profile.submit.error.content": "Нешто није у реду приликом регистрације новог корисника.", + "register-page.create-profile.submit.error.head": "Неуспешна регистрација", + "register-page.create-profile.submit.success.content": "Регистрација је успешна. Пријављени сте као креирани корисник.", + "register-page.create-profile.submit.success.head": "Регистрација је завршена", + "register-page.registration.header": "Регистрација новог корисника", + "register-page.registration.info": "Региструјте налог да бисте се претплатили на колекције за ажурирања путем емаил-а и пошаљите нове ставке на DSpace.", + "register-page.registration.email": "Емаил адреса *", + "register-page.registration.email.error.required": "Молимо унесите емаил адресу", + "register-page.registration.email.error.not-email-form": "Молимо унесите важећу емаил адресу.", + "register-page.registration.email.error.not-valid-domain": "Користите емаил са дозвољеним доменима: {{ domains }}", + "register-page.registration.email.hint": "Ова адреса ће бити верификована и коришћена као ваше корисничко име.", + "register-page.registration.submit": "Регистровати", + "register-page.registration.success.head": "Верификациони емаил је послат", + "register-page.registration.success.content": "Емаил је послат на {{ email }} који садржи посебан URL и даља упутства.", + "register-page.registration.error.head": "Грешка при покушају регистрације емаил-а", + "register-page.registration.error.content": "Дошло је до грешке при регистрацији следеће емаил адресе: {{ email }}", + "register-page.registration.error.recaptcha": "Грешка при покушају аутентификације помоћу recaptcha", + "register-page.registration.google-recaptcha.must-accept-cookies": "Да бисте се регистровали, морате прихватити колачиће за <b>регистрацију и враћање лозинке</b> (Google reCaptcha).", + "register-page.registration.error.maildomain": "Ова емаил адреса није на листи домена који се могу регистровати. Дозвољени домени су {{ domains }}", + "register-page.registration.google-recaptcha.open-cookie-settings": "Отворите подешавања колачића", + "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", + "register-page.registration.google-recaptcha.notification.message.error": "Дошло је до грешке током reCaptcha верификације", + "register-page.registration.google-recaptcha.notification.message.expired": "Верификација је истекла. Молимо потврдите поново.", + "register-page.registration.info.maildomain": "Налози се могу регистровати за емаил адресе домена", + "relationships.add.error.relationship-type.content": "Није пронађено одговарајуће подударање за тип везе {{ type }} између две ставке", + "relationships.add.error.server.content": "Сервер је вратио грешку", + "relationships.add.error.title": "Није могуће додати везу", + "relationships.isAuthorOf": "Аутори", + "relationships.isAuthorOf.Person": "Аутори (особа)", + "relationships.isAuthorOf.OrgUnit": "Аутори (организационе јединице)", + "relationships.isIssueOf": "Издања часописа", + "relationships.isJournalIssueOf": "Издања часопса", + "relationships.isJournalOf": "Часописи", + "relationships.isOrgUnitOf": "Организационе јединице", + "relationships.isPersonOf": "Аутори", + "relationships.isProjectOf": "Истраживачки пројекти", + "relationships.isPublicationOf": "Издања", + "relationships.isPublicationOfJournalIssue": "Чланци", + "relationships.isSingleJournalOf": "Часопис", + "relationships.isSingleVolumeOf": "Свеска часописа", + "relationships.isVolumeOf": "Свеске часописа", + "relationships.isContributorOf": "Сарадници", + "relationships.isContributorOf.OrgUnit": "Сарадник (Организациона јединица)", + "relationships.isContributorOf.Person": "Сарадник", + "relationships.isFundingAgencyOf.OrgUnit": "Оснивач", + "repository.image.logo": "Лого репозиторијума", + "repository.title": "DSpace Репозиторијум", + "repository.title.prefix": "DSpace Репозиторијум ::", + "resource-policies.add.button": "Додати", + "resource-policies.add.for.": "Додајте нове смернице", + "resource-policies.add.for.bitstream": "Додајте нове битстрим смернице", + "resource-policies.add.for.bundle": "Додајте нове смернице пакета", + "resource-policies.add.for.item": "Додајте нове смернице ставки", + "resource-policies.add.for.community": "Додајте нове смернице заједнице", + "resource-policies.add.for.collection": "Додајте нове смернице колекција", + "resource-policies.create.page.heading": "Креирајте нове смернице ресурса за", + "resource-policies.create.page.failure.content": "Дошло је до грешке при креирању смерница ресурса.", + "resource-policies.create.page.success.content": "Операција успела", + "resource-policies.create.page.title": "Креирајте нове смернице ресурса", + "resource-policies.delete.btn": "Избришите изабрано", + "resource-policies.delete.btn.title": "Избришите изабране смернице ресурса", + "resource-policies.delete.failure.content": "Дошло је до грешке приликом брисања изабраних смерница ресурса.", + "resource-policies.delete.success.content": "Операција успела", + "resource-policies.edit.page.heading": "Измените смернице ресурса", + "resource-policies.edit.page.failure.content": "Дошло је до грешке приликом измене смерница ресурса.", + "resource-policies.edit.page.target-failure.content": "Дошло је до грешке приликом измене циља (EPerson или групе) смерница ресурса.", + "resource-policies.edit.page.other-failure.content": "Дошло је до грешке приликом измене смерница ресурса. Циљ (EPerson или група) је успешно ажуриран.", + "resource-policies.edit.page.success.content": "Операција успела", + "resource-policies.edit.page.title": "Измена смерница ресурса", + "resource-policies.form.action-type.label": "Изабрати врсту акције", + "resource-policies.form.action-type.required": "Морате да изаберете акцију полисе ресурса.", + "resource-policies.form.eperson-group-list.label": "EPerson или група која ће добити овлашћење", + "resource-policies.form.eperson-group-list.select.btn": "Изабрати", + "resource-policies.form.eperson-group-list.tab.eperson": "Потражите EPerson", + "resource-policies.form.eperson-group-list.tab.group": "Потражите групу", + "resource-policies.form.eperson-group-list.table.headers.action": "Поступак", + "resource-policies.form.eperson-group-list.table.headers.id": "ID", + "resource-policies.form.eperson-group-list.table.headers.name": "Име", + "resource-policies.form.eperson-group-list.modal.header": "Не може се променити тип", + "resource-policies.form.eperson-group-list.modal.text1.toGroup": "Није могуће заменити EPerson са групом.", + "resource-policies.form.eperson-group-list.modal.text1.toEPerson": "Није могуће заменити групу са EPerson.", + "resource-policies.form.eperson-group-list.modal.text2": "Избришите тренутне полисе ресурса и креирајте нове са жељеним типом.", + "resource-policies.form.eperson-group-list.modal.close": "Ок", + "resource-policies.form.date.end.label": "Датум завршетка", + "resource-policies.form.date.start.label": "Датум почетка", + "resource-policies.form.description.label": "Опис", + "resource-policies.form.name.label": "Име", + "resource-policies.form.policy-type.label": "Изаберите тип полисе", + "resource-policies.form.policy-type.required": "Морате да изаберете тип полисе ресурса.", + "resource-policies.table.headers.action": "Поступак", + "resource-policies.table.headers.date.end": "Датум завршетка", + "resource-policies.table.headers.date.start": "Датум почетка", + "resource-policies.table.headers.edit": "Изменити", + "resource-policies.table.headers.edit.group": "Изменити групу", + "resource-policies.table.headers.edit.policy": "Изменити смернице", + "resource-policies.table.headers.eperson": "EPerson", + "resource-policies.table.headers.group": "Група", + "resource-policies.table.headers.id": "ID", + "resource-policies.table.headers.name": "Име", + "resource-policies.table.headers.policyType": "тип", + "resource-policies.table.headers.title.for.bitstream": "Смернице за битстрим", + "resource-policies.table.headers.title.for.bundle": "Смернице за пакет", + "resource-policies.table.headers.title.for.item": "Смернице за ставку", + "resource-policies.table.headers.title.for.community": "Смернице за заједницу", + "resource-policies.table.headers.title.for.collection": "Смернице за колекцију", + "search.description": "", + "search.switch-configuration.title": "Прикажи", + "search.title": "Претрага", + "search.breadcrumbs": "Претрага", + "search.search-form.placeholder": "Претражите спремиште...", + "search.filters.applied.f.author": "Аутор", + "search.filters.applied.f.dateIssued.max": "Датум завршетка", + "search.filters.applied.f.dateIssued.min": "Датум почетка", + "search.filters.applied.f.dateSubmitted": "Датум прихватања", + "search.filters.applied.f.discoverable": "Није могуће открити", + "search.filters.applied.f.entityType": "Тип ставке", + "search.filters.applied.f.has_content_in_original_bundle": "Има фајлове", + "search.filters.applied.f.itemtype": "Тип", + "search.filters.applied.f.namedresourcetype": "Статус", + "search.filters.applied.f.subject": "Предмет", + "search.filters.applied.f.submitter": "Подносилац", + "search.filters.applied.f.jobTitle": "Звање", + "search.filters.applied.f.birthDate.max": "Рођење - крајњи датум", + "search.filters.applied.f.birthDate.min": "Рођење - почетни датум", + "search.filters.applied.f.supervisedBy": "Прегледао", + "search.filters.applied.f.withdrawn": "Повучен", + "search.filters.filter.author.head": "Аутор", + "search.filters.filter.author.placeholder": "Име аутора", + "search.filters.filter.author.label": "Претражите име аутора", + "search.filters.filter.birthDate.head": "Датум рођења", + "search.filters.filter.birthDate.placeholder": "Датум рођења", + "search.filters.filter.birthDate.label": "Претражите датум рођења", + "search.filters.filter.collapse": "Скупи филтер", + "search.filters.filter.creativeDatePublished.head": "Датум објављивања", + "search.filters.filter.creativeDatePublished.placeholder": "Датум објављивања", + "search.filters.filter.creativeDatePublished.label": "Претражите датум објављивања", + "search.filters.filter.creativeWorkEditor.head": "Едитор", + "search.filters.filter.creativeWorkEditor.placeholder": "Едитор", + "search.filters.filter.creativeWorkEditor.label": "Претрага уредника", + "search.filters.filter.creativeWorkKeywords.head": "Предмет", + "search.filters.filter.creativeWorkKeywords.placeholder": "Предмет", + "search.filters.filter.creativeWorkKeywords.label": "Предмет претраге", + "search.filters.filter.creativeWorkPublisher.head": "Издавач", + "search.filters.filter.creativeWorkPublisher.placeholder": "Издавач", + "search.filters.filter.creativeWorkPublisher.label": "Претрага издавача", + "search.filters.filter.dateIssued.head": "Датум", + "search.filters.filter.dateIssued.max.placeholder": "Максимални датум", + "search.filters.filter.dateIssued.max.label": "Крај", + "search.filters.filter.dateIssued.min.placeholder": "Минимални датум", + "search.filters.filter.dateIssued.min.label": "Почетак", + "search.filters.filter.dateSubmitted.head": "Датум прихватања", + "search.filters.filter.dateSubmitted.placeholder": "Датум прихватања", + "search.filters.filter.dateSubmitted.label": "Претрага датума прихватања", + "search.filters.filter.discoverable.head": "Није могуће открити", + "search.filters.filter.withdrawn.head": "Повучен", + "search.filters.filter.entityType.head": "Тип ставке", + "search.filters.filter.entityType.placeholder": "Тип ставке", + "search.filters.filter.entityType.label": "Претражите тип ставке", + "search.filters.filter.expand": "Прошири филтер", + "search.filters.filter.has_content_in_original_bundle.head": "Има фајлове", + "search.filters.filter.itemtype.head": "Тип", + "search.filters.filter.itemtype.placeholder": "Тип", + "search.filters.filter.itemtype.label": "Тип претраге", + "search.filters.filter.jobTitle.head": "Звање", + "search.filters.filter.jobTitle.placeholder": "Звање", + "search.filters.filter.jobTitle.label": "Претрага звања", + "search.filters.filter.knowsLanguage.head": "Познати језик", + "search.filters.filter.knowsLanguage.placeholder": "Познати језик", + "search.filters.filter.knowsLanguage.label": "Претражите познати језик", + "search.filters.filter.namedresourcetype.head": "Статус", + "search.filters.filter.namedresourcetype.placeholder": "Статус", + "search.filters.filter.namedresourcetype.label": "Статус претраге", + "search.filters.filter.objectpeople.head": "Људи", + "search.filters.filter.objectpeople.placeholder": "Људи", + "search.filters.filter.objectpeople.label": "Претражите људе", + "search.filters.filter.organizationAddressCountry.head": "Држава", + "search.filters.filter.organizationAddressCountry.placeholder": "Држава", + "search.filters.filter.organizationAddressCountry.label": "Претражите државу", + "search.filters.filter.organizationAddressLocality.head": "Град", + "search.filters.filter.organizationAddressLocality.placeholder": "Град", + "search.filters.filter.organizationAddressLocality.label": "Претражите град", + "search.filters.filter.organizationFoundingDate.head": "Датум оснивања", + "search.filters.filter.organizationFoundingDate.placeholder": "Датум оснивања", + "search.filters.filter.organizationFoundingDate.label": "Претражите датум оснивања", + "search.filters.filter.scope.head": "Опсег", + "search.filters.filter.scope.placeholder": "Филтер опсега", + "search.filters.filter.scope.label": "Претражите филтер опсега", + "search.filters.filter.show-less": "Скупити", + "search.filters.filter.show-more": "Прикажи више", + "search.filters.filter.subject.head": "Предмет", + "search.filters.filter.subject.placeholder": "Предмет", + "search.filters.filter.subject.label": "Предмет претраге", + "search.filters.filter.submitter.head": "Подносилац", + "search.filters.filter.submitter.placeholder": "Подносилац", + "search.filters.filter.submitter.label": "Подносилац претраге", + "search.filters.filter.show-tree": "Прегледајте стабло {{ name }}", + "search.filters.filter.supervisedBy.head": "Прегледао", + "search.filters.filter.supervisedBy.placeholder": "Прегледао", + "search.filters.filter.supervisedBy.label": "Претрагу надгледао", + "search.filters.entityType.JournalIssue": "Издања часописа", + "search.filters.entityType.JournalVolume": "Свеска часописа", + "search.filters.entityType.OrgUnit": "Организациона јединица", + "search.filters.has_content_in_original_bundle.true": "Да", + "search.filters.has_content_in_original_bundle.false": "Не", + "search.filters.discoverable.true": "Не", + "search.filters.discoverable.false": "Да", + "search.filters.namedresourcetype.Archived": "Архивирано", + "search.filters.namedresourcetype.Validation": "Исправност", + "search.filters.namedresourcetype.Waiting for Controller": "Чека се контролор", + "search.filters.namedresourcetype.Workflow": "Процес рада", + "search.filters.namedresourcetype.Workspace": "Радни простор", + "search.filters.withdrawn.true": "Да", + "search.filters.withdrawn.false": "Не", + "search.filters.head": "Филтери", + "search.filters.reset": "Ресетовање филтера", + "search.filters.search.submit": "Прихватите", + "search.form.search": "Претрага", + "search.form.search_dspace": "Сви репозиторијуми", + "search.form.scope.all": "Читав репозиторијум", + "search.results.head": "Резултати претраге", + "search.results.no-results": "Ваша претрага није дала резултате. Имате проблема са проналажењем онога што тражите? Покушајте да ставите", + "search.results.no-results-link": "наводнике око тога", + "search.results.empty": "Ваша претрага није дала резултате.", + "search.results.view-result": "Погледати", + "search.results.response.500": "Дошло је до грешке током извршавања упита, молимо покушајте поново касније", + "default.search.results.head": "Резултати претраге", + "default-relationships.search.results.head": "Резултати претраге", + "search.sidebar.close": "Повратак на резултате", + "search.sidebar.filters.title": "Филтери", + "search.sidebar.open": "Алати за претрагу", + "search.sidebar.results": "резултати", + "search.sidebar.settings.rpp": "Резултати по страни", + "search.sidebar.settings.sort-by": "Сортирати по", + "search.sidebar.settings.title": "Подешавања", + "search.view-switch.show-detail": "Приказати детаље", + "search.view-switch.show-grid": "Приказати као мрежу", + "search.view-switch.show-list": "Приказати као листу", + "sorting.ASC": "Растуће", + "sorting.DESC": "Опадајуће", + "sorting.dc.title.ASC": "Наслов растуће", + "sorting.dc.title.DESC": "Наслов опадајуће", + "sorting.score.ASC": "Најмање релевантно", + "sorting.score.DESC": "Најрелевантније", + "sorting.dc.date.issued.ASC": "Датум издања растуће", + "sorting.dc.date.issued.DESC": "Датум издања опадајуће", + "sorting.dc.date.accessioned.ASC": "Датум приступа растуће", + "sorting.dc.date.accessioned.DESC": "Датум приступа опадајуће", + "sorting.lastModified.ASC": "Последња измена растуће", + "sorting.lastModified.DESC": "Последња измена опадајуће", + "statistics.title": "Статистика", + "statistics.header": "Статистика за {{ scope }}", + "statistics.breadcrumbs": "Статистика", + "statistics.page.no-data": "Нема доступних података", + "statistics.table.no-data": "Нема доступних података", + "statistics.table.title.TotalVisits": "Укупно посета", + "statistics.table.title.TotalVisitsPerMonth": "Укупно посета месечно", + "statistics.table.title.TotalDownloads": "Посете фајловима", + "statistics.table.title.TopCountries": "Највише прегледа по државама", + "statistics.table.title.TopCities": "Највише прегледа по градовима", + "statistics.table.header.views": "Погледи", + "statistics.table.no-name": "(име објекта се не може учитати)", + "submission.edit.breadcrumbs": "Измена поднеска", + "submission.edit.title": "Измена поднеска", + "submission.general.cancel": "Отказати", + "submission.general.cannot_submit": "Немате дозволу да поднесете нову пријаву.", + "submission.general.deposit": "Депоновати", + "submission.general.discard.confirm.cancel": "Отказати", + "submission.general.discard.confirm.info": "Ова операција се не може опозвати. Да ли сте сигурни?", + "submission.general.discard.confirm.submit": "Да сигуран сам", + "submission.general.discard.confirm.title": "Одбаците поднесак", + "submission.general.discard.submit": "Одбацити", + "submission.general.info.saved": "Сачувано", + "submission.general.info.pending-changes": "Несачуване промене", + "submission.general.save": "Сачувати", + "submission.general.save-later": "Сачувати за касније", + "submission.import-external.page.title": "Увезите метаподатке из спољног извора", + "submission.import-external.title": "Увезите метаподатке из спољног извора", + "submission.import-external.title.Journal": "Увезите часопис из спољног извора", + "submission.import-external.title.JournalIssue": "Увезите издање часописа из спољног извора", + "submission.import-external.title.JournalVolume": "Увезите волуме часописа из спољног извора", + "submission.import-external.title.OrgUnit": "Увезите издавача из спољног извора", + "submission.import-external.title.Person": "Увезите особу из спољног извора", + "submission.import-external.title.Project": "Увезите пројекат из спољног извора", + "submission.import-external.title.Publication": "Увезите публикацију из спољног извора", + "submission.import-external.title.none": "Увезите метаподатке из спољног извора", + "submission.import-external.page.hint": "Унесите упит изнад да бисте пронашли ставке са веба за увоз у DSpace.", + "submission.import-external.back-to-my-dspace": "Назад на MyDSpace", + "submission.import-external.search.placeholder": "Претрага спољног извора", + "submission.import-external.search.button": "Претрага", + "submission.import-external.search.button.hint": "Напишите неколико речи за претрагу", + "submission.import-external.search.source.hint": "Изаберите спољни извор", + "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": "Научна мрежа", + "submission.import-external.source.orcidWorks": "ORCID", + "submission.import-external.source.epo": "Европски завод за патенте (EPO)", + "submission.import-external.source.loading": "Учитавање...", + "submission.import-external.source.sherpaJournal": "SHERPA часописи", + "submission.import-external.source.sherpaJournalIssn": "SHERPA часописи од ISSN", + "submission.import-external.source.sherpaPublisher": "SHERPA Publishers", + "submission.import-external.source.openAIREFunding": "Финансирање OpenAIRE API-ја", + "submission.import-external.source.orcid": "ORCID", + "submission.import-external.source.pubmed": "Pubmed", + "submission.import-external.source.pubmedeu": "Pubmed Europe", + "submission.import-external.source.lcname": "Библиотека Конгресних имена", + "submission.import-external.preview.title": "Преглед ставке", + "submission.import-external.preview.title.Publication": "Преглед публикације", + "submission.import-external.preview.title.none": "Преглед ставке", + "submission.import-external.preview.title.Journal": "Преглед часописа", + "submission.import-external.preview.title.OrgUnit": "Преглед организационе јединице", + "submission.import-external.preview.title.Person": "Преглед особе", + "submission.import-external.preview.title.Project": "Преглед пројекта", + "submission.import-external.preview.subtitle": "Метаподаци у наставку су увезени из спољног извора. Биће унапред попуњен када започнете прихватање.", + "submission.import-external.preview.button.import": "Почните са прихватањем", + "submission.import-external.preview.error.import.title": "Грешка при прихватању", + "submission.import-external.preview.error.import.body": "Дошло је до грешке током улазног процеса увоза спољашњег извора.", + "submission.sections.describe.relationship-lookup.close": "Затвори", + "submission.sections.describe.relationship-lookup.external-source.added": "Успешно је додат локални улаз у избор", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isAuthorOfPublication": "Увезите удаљеног аутора", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Увезите удаљени дневник", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Увезите удаљено издање часописа", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Увезите удаљени опсег часописа", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.isProjectOfPublication": "Пројекат", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.none": "Увезите удаљену ставку", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Event": "Увезите удаљени догађај", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Product": "Увезите удаљени производ", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Equipment": "Увезите удаљену опрему", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.OrgUnit": "Увезите удаљену организациону јединицу", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Funding": "Увезите удаљени фонд", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Person": "Увезите удаљену особу", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Patent": "Увезите удаљени патент", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Project": "Увезите удаљени пројекат", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Publication": "Увезите удаљену публикацију", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.added.new-entity": "Додат је нови ентитет!", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isProjectOfPublication.title": "Пројекат", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.openAIREFunding": "Финансирање OpenAIRE API-ја", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.title": "Увези удаљеног аутора", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.local-entity": "Локални аутор је успешно додат у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.isAuthorOfPublication.added.new-entity": "Спољашњи аутор је успешно увезен и додат у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority": "Управа", + "submission.sections.describe.relationship-lookup.external-source.import-modal.authority.new": "Увезите као нови улаз локалне управе", + "submission.sections.describe.relationship-lookup.external-source.import-modal.cancel": "Поништити, отказати", + "submission.sections.describe.relationship-lookup.external-source.import-modal.collection": "Изаберите колекцију у коју ћете увести нове улазе", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities": "Ентитети", + "submission.sections.describe.relationship-lookup.external-source.import-modal.entities.new": "Увезите као нови локални ентитет", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.lcname": "Увезите из LC имена", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.orcid": "Увезите из ORCID-а", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaJournal": "Увезите из часописа SHERPA", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.sherpaPublisher": "Увезите из SHERPA издавача", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.pubmed": "Увезите из PubMed-а", + "submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Увезите из arXiv", + "submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Увоз", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Увезите удаљени часопис", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.local-entity": "Успешно додат локални часопис у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Успешно увезен и додат спољашњи часопис у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Увезите удаљено издање часописа", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Успешно је додат локални број часописа у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Успешно увезен и додат спољашњи број часописа у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Увезите удаљени опсег часописа", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.local-entity": "Успешно је додат локални волумен часописа у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.added.new-entity": "Успешно увезен и додат спољашњи опсег часописа у избор", + "submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Изаберите локално подударање:", + "submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Поништите све", + "submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Опозовите избор странице", + "submission.sections.describe.relationship-lookup.search-tab.loading": "Учитавање...", + "submission.sections.describe.relationship-lookup.search-tab.placeholder": "Упит за претрагу", + "submission.sections.describe.relationship-lookup.search-tab.search": "Иди", + "submission.sections.describe.relationship-lookup.search-tab.search-form.placeholder": "Претрага...", + "submission.sections.describe.relationship-lookup.search-tab.select-all": "Изабери све", + "submission.sections.describe.relationship-lookup.search-tab.select-page": "Изаберите страницу", + "submission.sections.describe.relationship-lookup.selected": "Изабране ставке {{ size }}", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isAuthorOfPublication": "Локални аутори ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Локални часописи ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Локални пројекти ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Publication": "Локалне публикације ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Person": "Локални аутори ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.OrgUnit": "Локалне организационе јединице ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataPackage": "Локални пакети података ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.DataFile": "Локални фајлови података ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.Journal": "Локални часописи ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Локална издања часописа ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Локална издања часописа ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Локални опсег часописа ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Локални опсег часописа ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaJournal": "SHERPA часописи ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.sherpaPublisher": "SHERPA издавачи({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.orcid": "ORCID ({{ count }})", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.lcname": "LC имена ({{ 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": "Потражите финансијере", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingOfPublication": "Потражите средства", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isChildOrgUnitOf": "Потражите организационе јединице", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.openAIREFunding": "Финансирање OpenAIRE API-ја", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isProjectOfPublication": "Пројекти", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Финансијер пројекта", + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Публикација аутора", + "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Финансирање OpenAIRE API-ја", + "submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Пројекат", + "submission.sections.describe.relationship-lookup.title.isProjectOfPublication": "Пројекти", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfProject": "Финансијер пројекта", + "submission.sections.describe.relationship-lookup.selection-tab.search-form.placeholder": "Претрага...", + "submission.sections.describe.relationship-lookup.selection-tab.tab-title": "Тренутни избор ({{ count }})", + "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Издања часописа", + "submission.sections.describe.relationship-lookup.title.JournalIssue": "Издања часописа", + "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Свеске часописа", + "submission.sections.describe.relationship-lookup.title.JournalVolume": "Свеске часописа", + "submission.sections.describe.relationship-lookup.title.isJournalOfPublication": "Часописи", + "submission.sections.describe.relationship-lookup.title.isAuthorOfPublication": "Аутори", + "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Финансијска агенција", + "submission.sections.describe.relationship-lookup.title.Project": "Пројекти", + "submission.sections.describe.relationship-lookup.title.Publication": "Публикације", + "submission.sections.describe.relationship-lookup.title.Person": "Аутори", + "submission.sections.describe.relationship-lookup.title.OrgUnit": "Организационе јединице", + "submission.sections.describe.relationship-lookup.title.DataPackage": "Пакети података", + "submission.sections.describe.relationship-lookup.title.DataFile": "Фајлови са подацима", + "submission.sections.describe.relationship-lookup.title.Funding Agency": "Финансијска агенција", + "submission.sections.describe.relationship-lookup.title.isFundingOfPublication": "Финансирање", + "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Матична организациона јединица", + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Публикација", + "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Укључите падајући мени", + "submission.sections.describe.relationship-lookup.selection-tab.settings": "Подешавања", + "submission.sections.describe.relationship-lookup.selection-tab.no-selection": "Ваш избор је тренутно празан.", + "submission.sections.describe.relationship-lookup.selection-tab.title.isAuthorOfPublication": "Изабрани аутори", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalOfPublication": "Изабрани часописи", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Изабрана свеска часописа", + "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Изабрани пројекти", + "submission.sections.describe.relationship-lookup.selection-tab.title.Publication": "Изабране публикације", + "submission.sections.describe.relationship-lookup.selection-tab.title.Person": "Изабрани аутори", + "submission.sections.describe.relationship-lookup.selection-tab.title.OrgUnit": "Изабране организационе јединице", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataPackage": "Изабрани пакети података", + "submission.sections.describe.relationship-lookup.selection-tab.title.DataFile": "Изабрани фајлови са подацима", + "submission.sections.describe.relationship-lookup.selection-tab.title.Journal": "Изабрани часописи", + "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Изабрано издање", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Изабрана свеска часописа", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingAgencyOfPublication": "Изабрана финансијска агенција", + "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Изабрано финансирање", + "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Изабрано издање", + "submission.sections.describe.relationship-lookup.selection-tab.title.isChildOrgUnitOf": "Изабрана организациона јединица", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaJournal": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.sherpaPublisher": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcid": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.orcidv2": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.lcname": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.pubmed": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.arxiv": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.crossref": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.epo": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.scopus": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.scielo": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Резултати претраге", + "submission.sections.describe.relationship-lookup.selection-tab.title": "Резултати претраге", + "submission.sections.describe.relationship-lookup.name-variant.notification.content": "Да ли желите да сачувате \"{{ value }}\" као варијанту имена за ову особу да бисте ви и други могли да га поново користите за будуће слање? Ако то не урадите, и даље можете да га користите за овај поднесак.", + "submission.sections.describe.relationship-lookup.name-variant.notification.confirm": "Сачувајте нову варијанту имена", + "submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Користи се само за овај поднесак", + "submission.sections.ccLicense.type": "Тип лиценце", + "submission.sections.ccLicense.select": "Изаберите тип лиценце…", + "submission.sections.ccLicense.change": "Промените тип лиценце…", + "submission.sections.ccLicense.none": "Нема доступних лиценци", + "submission.sections.ccLicense.option.select": "Изаберите опцију…", + "submission.sections.ccLicense.link": "Изабрали сте следећу лиценцу:", + "submission.sections.ccLicense.confirmation": "Додељујем лиценцу изнад", + "submission.sections.general.add-more": "Додајте још", + "submission.sections.general.cannot_deposit": "Пријава се не може довршити због грешака у обрасцу.<br>Попуните сва обавезна поља да бисте довршили пријаву.", + "submission.sections.general.collection": "Колекција", + "submission.sections.general.deposit_error_notice": "Дошло је до проблема приликом слања ставке, молимо покушајте поново касније.", + "submission.sections.general.deposit_success_notice": "Пријава је успешно поднета.", + "submission.sections.general.discard_error_notice": "Дошло је до проблема при одбацивању ставке, молимо покушајте поново касније.", + "submission.sections.general.discard_success_notice": "Слање је успешно одбачено.", + "submission.sections.general.metadata-extracted": "Нови метаподаци су издвојени и додати у одељак <strong>{{sectionId}}</strong>.", + "submission.sections.general.metadata-extracted-new-section": "Нови одељак <strong>{{sectionId}}</strong> је додат у пријаву.", + "submission.sections.general.no-collection": "Није пронађена колекција", + "submission.sections.general.no-sections": "Нема доступних опција", + "submission.sections.general.save_error_notice": "Дошло је до проблема приликом чувања ставке, молимо покушајте поново касније.", + "submission.sections.general.save_success_notice": "Пријава је успешно сачувана.", + "submission.sections.general.search-collection": "Потражите колекцију", + "submission.sections.general.sections_not_valid": "Постоје непотпуни одељци.", + "submission.sections.identifiers.info": "Следећи идентификатори ће бити креирани за вашу ставку:", + "submission.sections.identifiers.no_handle": "За ову ставку није везан Handle.", + "submission.sections.identifiers.no_doi": "Ниједан DOIs није везан за ову ставку.", + "submission.sections.identifiers.handle_label": "Handle:", + "submission.sections.identifiers.doi_label": "DOI:", + "submission.sections.identifiers.otherIdentifiers_label": "Остали идентификатори:", + "submission.sections.submit.progressbar.accessCondition": "Услови приступања ставки", + "submission.sections.submit.progressbar.CClicense": "Creative Commons лиценца", + "submission.sections.submit.progressbar.describe.recycle": "Рециклажа", + "submission.sections.submit.progressbar.describe.stepcustom": "Описати", + "submission.sections.submit.progressbar.describe.stepone": "Описати", + "submission.sections.submit.progressbar.describe.steptwo": "Описати", + "submission.sections.submit.progressbar.detect-duplicate": "Потенцијални дупликати", + "submission.sections.submit.progressbar.identifiers": "Идентификатори", + "submission.sections.submit.progressbar.license": "Дозвола за депозит", + "submission.sections.submit.progressbar.sherpapolicy": "SHERPA прописи", + "submission.sections.submit.progressbar.upload": "Додај фајлове", + "submission.sections.submit.progressbar.sherpaPolicies": "Информације о политици отвореног приступа издавача", + "submission.sections.sherpa-policy.title-empty": "Нема доступних информација о смерницама за издаваче. Ако ваш рад има придружени ISSN, унесите га изнад да бисте видели све повезане смернице отвореног приступа за издаваче.", + "submission.sections.status.errors.title": "Грешке", + "submission.sections.status.valid.title": "Важеће", + "submission.sections.status.warnings.title": "Упозорења", + "submission.sections.status.errors.aria": "Има грешке", + "submission.sections.status.valid.aria": "Важеће је", + "submission.sections.status.warnings.aria": "Има упозорења", + "submission.sections.status.info.title": "Додатне Информације", + "submission.sections.status.info.aria": "Додатне Информације", + "submission.sections.toggle.open": "Отвори одељак", + "submission.sections.toggle.close": "Затвори одељак", + "submission.sections.toggle.aria.open": "Проширите {{sectionHeader}} одељак", + "submission.sections.toggle.aria.close": "Скупите {{sectionHeader}} одељак", + "submission.sections.upload.delete.confirm.cancel": "Поништити, отказати", + "submission.sections.upload.delete.confirm.info": "Ова операција се не може опозвати. Јесте ли сигурни?", + "submission.sections.upload.delete.confirm.submit": "Да, сигуран сам", + "submission.sections.upload.delete.confirm.title": "Избришите битстрим", + "submission.sections.upload.delete.submit": "Избришите", + "submission.sections.upload.download.title": "Преузмите битстрим", + "submission.sections.upload.drop-message": "Спустите фајлове да бисте их приложили ставци", + "submission.sections.upload.edit.title": "Уредите битстрим", + "submission.sections.upload.form.access-condition-label": "Тип услова приступа", + "submission.sections.upload.form.access-condition-hint": "Изаберите услов приступа који ћете применити на битстрим када се ставка депонује", + "submission.sections.upload.form.date-required": "Датум је обавезан.", + "submission.sections.upload.form.date-required-from": "Обавезно одобрење приступа од датума.", + "submission.sections.upload.form.date-required-until": "Обавезно одобрење приступа до датума.", + "submission.sections.upload.form.from-label": "Одобрење приступа од", + "submission.sections.upload.form.from-hint": "Изаберите датум од кога се примењује одговарајући услов приступа", + "submission.sections.upload.form.from-placeholder": "Од", + "submission.sections.upload.form.group-label": "Група", + "submission.sections.upload.form.group-required": "Група је обавезна.", + "submission.sections.upload.form.until-label": "Одобрење приступа до", + "submission.sections.upload.form.until-hint": "Изаберите датум до којег се примењује одговарајући услов приступа", + "submission.sections.upload.form.until-placeholder": "Све док", + "submission.sections.upload.header.policy.default.nolist": "Отпремљени фајлови у колекцији {{collectionName}} биће доступне према следећим групама:", + "submission.sections.upload.header.policy.default.withlist": "Имајте на уму да ће отпремљени фајлови у колекцији {{collectionName}} бити доступни, поред онога што је изричито одлучено за један фајл, са следећим групама:", + "submission.sections.upload.info": "Овде ћете пронаћи све фајлове који се тренутно налазе у ставци. Можете да ажурирате метаподатке фајла и услове приступа или <strong> отпремите додатне фајлове тако што ћете их превући и отпустити било где на страници.</strong>", + "submission.sections.upload.no-entry": "Не", + "submission.sections.upload.no-file-uploaded": "Још увек није отпремљен ниједан фајл.", + "submission.sections.upload.save-metadata": "Сачувај метаподатке", + "submission.sections.upload.undo": "Поништити, отказати", + "submission.sections.upload.upload-failed": "Отпремање није успело", + "submission.sections.upload.upload-successful": "Отпремање је успешно", + "submission.sections.accesses.form.discoverable-description": "Када је означено, ова ставка ће бити видљива у претрази/прегледу. Када није означено, ставка ће бити доступна само преко директне везе и никада се неће појавити у претрази/прегледу.", + "submission.sections.accesses.form.discoverable-label": "Откривање", + "submission.sections.accesses.form.access-condition-label": "Тип услова приступа", + "submission.sections.accesses.form.access-condition-hint": "Изаберите услов приступа који ћете применити на ставку када се депонује", + "submission.sections.accesses.form.date-required": "Датум је обавезан.", + "submission.sections.accesses.form.date-required-from": "Обавезно одобрење приступа од датума.", + "submission.sections.accesses.form.date-required-until": "Обавезно одобрење приступа до датума.", + "submission.sections.accesses.form.from-label": "Одобрење приступа од", + "submission.sections.accesses.form.from-hint": "Изаберите датум од кога се примењује одговарајући услов приступа", + "submission.sections.accesses.form.from-placeholder": "Од", + "submission.sections.accesses.form.group-label": "Група", + "submission.sections.accesses.form.group-required": "Група је обавезна.", + "submission.sections.accesses.form.until-label": "Одобрење приступа до", + "submission.sections.accesses.form.until-hint": "Изаберите датум до којег се примењује одговарајући услов приступа", + "submission.sections.accesses.form.until-placeholder": "Све док", + "submission.sections.license.granted-label": "Потврђујем горе наведену лиценцу", + "submission.sections.license.required": "Морате прихватити лиценцу", + "submission.sections.license.notgranted": "Морате прихватити лиценцу", + "submission.sections.sherpa.publication.information": "Информације о публикацији", + "submission.sections.sherpa.publication.information.title": "Наслов", + "submission.sections.sherpa.publication.information.issns": "ISSN-ови", + "submission.sections.sherpa.publication.information.url": "URL", + "submission.sections.sherpa.publication.information.publishers": "Издавач", + "submission.sections.sherpa.publication.information.romeoPub": "Romeo Pub", + "submission.sections.sherpa.publication.information.zetoPub": "Zeto Pub", + "submission.sections.sherpa.publisher.policy": "Пропис за издаваче", + "submission.sections.sherpa.publisher.policy.description": "Информације у наставку су пронађене преко SherpaRomea. На основу смерница вашег издавача, он пружа савете о томе да ли је ембарго можда неопходан и/или које датотеке можете да отпремите. Ако имате питања, контактирајте свог администратора сајта путем обрасца за повратне информације у подножју.", + "submission.sections.sherpa.publisher.policy.openaccess": "Путеви отвореног приступа дозвољени политиком овог часописа наведени су у наставку према верзији чланка. Кликните на путању за детаљнији приказ", + "submission.sections.sherpa.publisher.policy.more.information": "За више информација погледајте следеће линкове:", + "submission.sections.sherpa.publisher.policy.version": "Верзија", + "submission.sections.sherpa.publisher.policy.embargo": "Ембарго", + "submission.sections.sherpa.publisher.policy.noembargo": "Нема ембарга", + "submission.sections.sherpa.publisher.policy.nolocation": "Ниједан", + "submission.sections.sherpa.publisher.policy.license": "Лиценца", + "submission.sections.sherpa.publisher.policy.prerequisites": "Предуслови", + "submission.sections.sherpa.publisher.policy.location": "Локација", + "submission.sections.sherpa.publisher.policy.conditions": "Услови", + "submission.sections.sherpa.publisher.policy.refresh": "Освежите", + "submission.sections.sherpa.record.information": "Запишите информацију", + "submission.sections.sherpa.record.information.id": "ID", + "submission.sections.sherpa.record.information.date.created": "Датум креирања", + "submission.sections.sherpa.record.information.date.modified": "Последња измена", + "submission.sections.sherpa.record.information.uri": "URI", + "submission.sections.sherpa.error.message": "Дошло је до грешке при преузимању SHERPA информација", + "submission.submit.breadcrumbs": "Нови поднесак", + "submission.submit.title": "Нови поднесак", + "submission.workflow.generic.delete": "Избришите", + "submission.workflow.generic.delete-help": "Изаберите ову опцију да бисте одбацили ову ставку. Затим ће бити затражено да то потврдите.", + "submission.workflow.generic.edit": "Уредите", + "submission.workflow.generic.edit-help": "Изаберите ову опцију да бисте променили метаподатке ставке.", + "submission.workflow.generic.view": "Погледајте", + "submission.workflow.generic.view-help": "Изаберите ову опцију да бисте видели метаподатке ставке.", + "submission.workflow.generic.submit_select_reviewer": "Изаберите рецензента", + "submission.workflow.generic.submit_select_reviewer-help": "изаберите помоћ рецензента", + "submission.workflow.generic.submit_score": "Оцена", + "submission.workflow.generic.submit_score-help": "резултат-помоћ", + "submission.workflow.tasks.claimed.approve": "Одобрити", + "submission.workflow.tasks.claimed.approve_help": "Ако сте прегледали ставку и ако је погодна за придруживање колекцији, изаберите \"Одобрити\".", + "submission.workflow.tasks.claimed.edit": "Изменити", + "submission.workflow.tasks.claimed.edit_help": "Изаберите ову опцију да бисте променили метаподатке ставке.", + "submission.workflow.tasks.claimed.decline": "Одбити", + "submission.workflow.tasks.claimed.decline_help": "одбити помоћ", + "submission.workflow.tasks.claimed.reject.reason.info": "Унесите разлог за одбијање пријаве у поље испод, наводећи да ли подносилац може да реши проблем и поново пошаље.", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Опишите разлог одбијања", + "submission.workflow.tasks.claimed.reject.reason.submit": "Одбаците ставку", + "submission.workflow.tasks.claimed.reject.reason.title": "Разлог", + "submission.workflow.tasks.claimed.reject.submit": "Одбити", + "submission.workflow.tasks.claimed.reject_help": "Ако сте прегледали ставку и утврдили да <strong>није</strong> прикладна за придруживање колекцији, изаберите \"Одбиј\". Од вас ће се затим тражити да унесете поруку која наводи зашто је ставка неприкладна и да ли подносилац треба нешто да промени и поново пошаље.", + "submission.workflow.tasks.claimed.return": "Повратак у групу", + "submission.workflow.tasks.claimed.return_help": "Вратите задатак у групу тако да други корисник може да изврши задатак.", + "submission.workflow.tasks.generic.error": "Дошло је до грешке у раду...", + "submission.workflow.tasks.generic.processing": "Обрада...", + "submission.workflow.tasks.generic.submitter": "Подносилац", + "submission.workflow.tasks.generic.success": "Операција успела", + "submission.workflow.tasks.pool.claim": "Потраживање", + "submission.workflow.tasks.pool.claim_help": "Доделите овај задатак себи.", + "submission.workflow.tasks.pool.hide-detail": "Сакрити детаље", + "submission.workflow.tasks.pool.show-detail": "Приказати детаље", + "submission.workspace.generic.view": "Погледати", + "submission.workspace.generic.view-help": "Изаберите ову опцију да бисте видели метаподатке ставке.", + "submitter.empty": "N/A", + "subscriptions.title": "Претплате", + "subscriptions.item": "Претплате на ставке", + "subscriptions.collection": "Претплате на колекције", + "subscriptions.community": "Претплате за заједнице", + "subscriptions.subscription_type": "Врста претплате", + "subscriptions.frequency": "Учесталост претплате", + "subscriptions.frequency.D": "Дневно", + "subscriptions.frequency.M": "Месечно", + "subscriptions.frequency.W": "Недељно", + "subscriptions.tooltip": "Претплатити се", + "subscriptions.modal.title": "Претплате", + "subscriptions.modal.type-frequency": "Врста и учесталост", + "subscriptions.modal.close": "Затворити", + "subscriptions.modal.delete-info": "Да бисте уклонили ову претплату, молимо посетите страницу \"Претплате\" испод вашег корисничког профила", + "subscriptions.modal.new-subscription-form.type.content": "Садржај", + "subscriptions.modal.new-subscription-form.frequency.D": "Дневно", + "subscriptions.modal.new-subscription-form.frequency.W": "Недељно", + "subscriptions.modal.new-subscription-form.frequency.M": "Месечно", + "subscriptions.modal.new-subscription-form.submit": "Поднеси", + "subscriptions.modal.new-subscription-form.processing": "Обрада...", + "subscriptions.modal.create.success": "Успешно сте претплаћени на {{ type }}.", + "subscriptions.modal.delete.success": "Претплата је успешно избрисана", + "subscriptions.modal.update.success": "Претплата на {{ type }} је успешно ажурирана", + "subscriptions.modal.create.error": "Дошло је до грешке током креирања претплате", + "subscriptions.modal.delete.error": "Дошло је до грешке током брисања претплате", + "subscriptions.modal.update.error": "Дошло је до грешке током ажурирања претплате", + "subscriptions.table.dso": "Предмет", + "subscriptions.table.subscription_type": "Врста претплате", + "subscriptions.table.subscription_frequency": "Учесталост претплате", + "subscriptions.table.action": "Поступак", + "subscriptions.table.edit": "Изменити", + "subscriptions.table.delete": "Избрисати", + "subscriptions.table.not-available": "Није доступно", + "subscriptions.table.not-available-message": "Претплаћена ставка је избрисана или тренутно немате дозволу да је видите", + "subscriptions.table.empty.message": "Тренутно немате ниједну претплату. Да бисте се претплатили на ажурирања путем емаил-а за заједницу или колекцију, користите дугме за претплату на страници објекта.", + "thumbnail.default.alt": "Умањена слика", + "thumbnail.default.placeholder": "Нема доступних умањених слика", + "thumbnail.project.alt": "Лого пројекта", + "thumbnail.project.placeholder": "Слика референта пројекта", + "thumbnail.orgunit.alt": "Лого организационе јединице", + "thumbnail.orgunit.placeholder": "Слика референта организационе јединице", + "thumbnail.person.alt": "Профилна слика", + "thumbnail.person.placeholder": "Слика профила није доступна", + "title": "DSpace", + "vocabulary-treeview.header": "Приказ хијерархијског стабла", + "vocabulary-treeview.load-more": "Учитати још", + "vocabulary-treeview.search.form.reset": "Ресетовати", + "vocabulary-treeview.search.form.search": "Претрага", + "vocabulary-treeview.search.no-result": "Није било ставки за приказ", + "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", + "vocabulary-treeview.tree.description.srsc": "Категорије предмета истраживања", + "vocabulary-treeview.info": "Изаберите тему коју желите да додате као филтер за претрагу", + "uploader.browse": "претражи", + "uploader.drag-message": "Превуците и ставите своје фајлове овде", + "uploader.delete.btn-title": "Обриши", + "uploader.or": ", или", + "uploader.processing": "Обрада отпремљених фајлова... (сада је безбедно затворити ову страницу)", + "uploader.queue-length": "Дужина реда", + "virtual-metadata.delete-item.info": "Изаберите типове за које желите да сачувате виртуелне метаподатке као стварне метаподатке", + "virtual-metadata.delete-item.modal-head": "Виртуелни метаподаци ове релације", + "virtual-metadata.delete-relationship.modal-head": "Изаберите ставке за које желите да сачувате виртуелне метаподатке као стварне метаподатке", + "supervisedWorkspace.search.results.head": "Надзиране ставке", + "workspace.search.results.head": "Ваши поднесци", + "workflowAdmin.search.results.head": "Управљање радним процесом", + "workflow.search.results.head": "Радни задаци", + "supervision.search.results.head": "Задаци радног процеса и радног простора", + "workflow-item.edit.breadcrumbs": "Измена ставке радног процеса", + "workflow-item.edit.title": "Измена ставке радног процеса", + "workflow-item.delete.notification.success.title": "Избрисано", + "workflow-item.delete.notification.success.content": "Ова ставка радног процеса је успешно избрисана", + "workflow-item.delete.notification.error.title": "Нешто није у реду", + "workflow-item.delete.notification.error.content": "Није могуће избрисати ставку процеса рада", + "workflow-item.delete.title": "Избришите ставку радног процеса", + "workflow-item.delete.header": "Избришите ставку радног процеса", + "workflow-item.delete.button.cancel": "Поништити, отказати", + "workflow-item.delete.button.confirm": "Избришите", + "workflow-item.send-back.notification.success.title": "Враћено подносиоцу", + "workflow-item.send-back.notification.success.content": "Ова ставка радног процеса је успешно враћена подносиоцу", + "workflow-item.send-back.notification.error.title": "Нешто није у реду", + "workflow-item.send-back.notification.error.content": "Ставка радног процеса није могла да се врати подносиоцу", + "workflow-item.send-back.title": "Вратите ставку радног процеса подносиоцу", + "workflow-item.send-back.header": "Вратите ставку радног процеса подносиоцу", + "workflow-item.send-back.button.cancel": "Поништити, отказати", + "workflow-item.send-back.button.confirm": "Вратити", + "workflow-item.view.breadcrumbs": "Приказ радног процеса", + "workspace-item.view.breadcrumbs": "Приказ радног простора", + "workspace-item.view.title": "Приказ радног простора", + "workspace-item.delete.breadcrumbs": "Избришите радни простор", + "workspace-item.delete.header": "Избришите ставку радног простора", + "workspace-item.delete.button.confirm": "Избришите", + "workspace-item.delete.button.cancel": "Поништити, отказати", + "workspace-item.delete.notification.success.title": "Избрисан", + "workspace-item.delete.title": "Ова ставка радног простора је успешно избрисана", + "workspace-item.delete.notification.error.title": "Нешто није у реду", + "workspace-item.delete.notification.error.content": "Није могуће избрисати ставку радног простора", + "workflow-item.advanced.title": "Напредни радни процес", + "workflow-item.selectrevieweraction.notification.success.title": "Изабрани рецензент", + "workflow-item.selectrevieweraction.notification.success.content": "Рецензент за ову ставку радног процеса је успешно изабран", + "workflow-item.selectrevieweraction.notification.error.title": "Нешто није у реду", + "workflow-item.selectrevieweraction.notification.error.content": "Није могуће изабрати рецензента за ову ставку радног процеса", + "workflow-item.selectrevieweraction.title": "Изаберите рецензента", + "workflow-item.selectrevieweraction.header": "Изаберите рецензента", + "workflow-item.selectrevieweraction.button.cancel": "Поништити, отказати", + "workflow-item.selectrevieweraction.button.confirm": "Потврдите", + "workflow-item.scorereviewaction.notification.success.title": "Оцена прегледа", + "workflow-item.scorereviewaction.notification.success.content": "Оцена за ову ставку радног процеса је успешно послата", + "workflow-item.scorereviewaction.notification.error.title": "Нешто није у реду", + "workflow-item.scorereviewaction.notification.error.content": "Није могуће оценити ову ставку", + "workflow-item.scorereviewaction.title": "Оцените ову ставку", + "workflow-item.scorereviewaction.header": "Оцените ову ставку", + "workflow-item.scorereviewaction.button.cancel": "Поништити, отказати", + "workflow-item.scorereviewaction.button.confirm": "Потврдите", + "idle-modal.header": "Сесија ускоро истиче", + "idle-modal.info": "Из безбедносних разлога, корисничке сесије истичу после {{ timeToExpire }} минута неактивности. Ваша сесија ускоро истиче. Да ли желите да продужите или да се одјавите?", + "idle-modal.log-out": "Одјавити се", + "idle-modal.extend-session": "Продужите сесију", + "researcher.profile.action.processing": "Обрада...", + "researcher.profile.associated": "Повезани профил истраживача", + "researcher.profile.change-visibility.fail": "Дошло је до неочекиване грешке приликом промене видљивости профила", + "researcher.profile.create.new": "Креирај нови", + "researcher.profile.create.success": "Профил истраживача је успешно креиран", + "researcher.profile.create.fail": "Дошло је до грешке током креирања профила истраживача", + "researcher.profile.delete": "Избришите", + "researcher.profile.expose": "Излагање", + "researcher.profile.hide": "Сакријте", + "researcher.profile.not.associated": "Профил истраживача још није повезан", + "researcher.profile.view": "Поглед", + "researcher.profile.private.visibility": "ПРИВАТНО", + "researcher.profile.public.visibility": "ЈАВНО", + "researcher.profile.status": "Статус:", + "researcherprofile.claim.not-authorized": "Нисте овлашћени да потврдите ову ставку. За више детаља контактирајте администратора(е).", + "researcherprofile.error.claim.body": "Дошло је до грешке при потврђивању профила, молимо вас покушајте поново касније", + "researcherprofile.error.claim.title": "Грешка", + "researcherprofile.success.claim.body": "Профил је успешно потврђен", + "researcherprofile.success.claim.title": "Успешно", + "person.page.orcid.create": "Креирајте ORCID ID", + "person.page.orcid.granted-authorizations": "Одобрена овлашћења", + "person.page.orcid.grant-authorizations": "Одобрите овлашћења", + "person.page.orcid.link": "Повежите се на ORCID ID", + "person.page.orcid.link.processing": "Повезивање профила са ORCID-ом...", + "person.page.orcid.link.error.message": "Нешто је пошло наопако при повезивању профила са ORCID-ом. Ако се проблем и даље јавља, контактирајте администратора.", + "person.page.orcid.orcid-not-linked-message": "ORCID ID овог профила ({{ orcid }}) још увек није повезан са налогом у ORCID регистру или је веза истекла.", + "person.page.orcid.unlink": "Прекините везу са ORCID-ом", + "person.page.orcid.unlink.processing": "Обрада...", + "person.page.orcid.missing-authorizations": "Недостају овлашћења", + "person.page.orcid.missing-authorizations-message": "Недостају следећа овлашћења:", + "person.page.orcid.no-missing-authorizations-message": "Дивно! Ово поље је празно, тако да сте одобрили сва права приступа за коришћење свих функција које нуди ваша институција.", + "person.page.orcid.no-orcid-message": "Још увек није повезан ORCID ID. Кликом на дугме испод могуће је повезати овај профил са ORCID налогом.", + "person.page.orcid.profile-preferences": "Приоритети профила", + "person.page.orcid.funding-preferences": "Приоритети финансирања", + "person.page.orcid.publications-preferences": "Приоритети публикације", + "person.page.orcid.remove-orcid-message": "Ако треба да уклоните свој ORCID, контактирајте администратора репозиторијума", + "person.page.orcid.save.preference.changes": "Подешавања ажурирања", + "person.page.orcid.sync-profile.affiliation": "Припадност", + "person.page.orcid.sync-profile.biographical": "Биографски подаци", + "person.page.orcid.sync-profile.education": "Образовање", + "person.page.orcid.sync-profile.identifiers": "Идентификатори", + "person.page.orcid.sync-fundings.all": "Сва средства", + "person.page.orcid.sync-fundings.mine": "Моја средства", + "person.page.orcid.sync-fundings.my_selected": "Одабрана средства", + "person.page.orcid.sync-fundings.disabled": "Онемогућено", + "person.page.orcid.sync-publications.all": "Све публикације", + "person.page.orcid.sync-publications.mine": "Моје публикације", + "person.page.orcid.sync-publications.my_selected": "Изабране публикације", + "person.page.orcid.sync-publications.disabled": "Онемогућено", + "person.page.orcid.sync-queue.discard": "Одбаците промену и немојте да се синхронизујете са ORCID регистром", + "person.page.orcid.sync-queue.discard.error": "Одбацивање записа ORCID реда није успело", + "person.page.orcid.sync-queue.discard.success": "Запис ORCID реда је успешно одбачен", + "person.page.orcid.sync-queue.empty-message": "Запис ORCID регистра је празан", + "person.page.orcid.sync-queue.table.header.type": "Тип", + "person.page.orcid.sync-queue.table.header.description": "Опис", + "person.page.orcid.sync-queue.table.header.action": "Поступак", + "person.page.orcid.sync-queue.description.affiliation": "Припадности", + "person.page.orcid.sync-queue.description.country": "Држава", + "person.page.orcid.sync-queue.description.education": "Образовања", + "person.page.orcid.sync-queue.description.external_ids": "Спољашњи ID", + "person.page.orcid.sync-queue.description.other_names": "Друга имена", + "person.page.orcid.sync-queue.description.qualification": "Квалификације", + "person.page.orcid.sync-queue.description.researcher_urls": "URL-ови истраживача", + "person.page.orcid.sync-queue.description.keywords": "Кључне речи", + "person.page.orcid.sync-queue.tooltip.insert": "Додајте нови унос у ORCID регистар", + "person.page.orcid.sync-queue.tooltip.update": "Ажурирајте овај унос у ORCID регистру", + "person.page.orcid.sync-queue.tooltip.delete": "Уклоните овај унос из ORCID регистра", + "person.page.orcid.sync-queue.tooltip.publication": "Публикација", + "person.page.orcid.sync-queue.tooltip.project": "Пројекат", + "person.page.orcid.sync-queue.tooltip.affiliation": "Припадност", + "person.page.orcid.sync-queue.tooltip.education": "Образовање", + "person.page.orcid.sync-queue.tooltip.qualification": "Квалификација", + "person.page.orcid.sync-queue.tooltip.other_names": "Друго име", + "person.page.orcid.sync-queue.tooltip.country": "Држава", + "person.page.orcid.sync-queue.tooltip.keywords": "Кључна реч", + "person.page.orcid.sync-queue.tooltip.external_ids": "Спољашњи идентификатор", + "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL истраживача", + "person.page.orcid.sync-queue.send": "Синхронизација са ORCID регистром", + "person.page.orcid.sync-queue.send.unauthorized-error.title": "Приступање ORCID-у није успело због недостајућих овлашћења.", + "person.page.orcid.sync-queue.send.unauthorized-error.content": "Кликните <a href='{{orcid}}'>овде</a> да поново доделите потребне дозволе. Ако се проблем настави, контактирајте администратора", + "person.page.orcid.sync-queue.send.bad-request-error": "Слање ORCID-у није успело јер ресурс послат у ORCID регистар није важећи", + "person.page.orcid.sync-queue.send.error": "Слање ORCID-у није успело", + "person.page.orcid.sync-queue.send.conflict-error": "Слање ORCID-у није успело јер се ресурс већ налази у ORCID регистру", + "person.page.orcid.sync-queue.send.not-found-warning": "Ресурс се више не налази у ORCID регистру.", + "person.page.orcid.sync-queue.send.success": "Слање ORCID-у је успешно завршено", + "person.page.orcid.sync-queue.send.validation-error": "Подаци које желите да синхронизујете са ORCID-ом нису исправни", + "person.page.orcid.sync-queue.send.validation-error.amount-currency.required": "Валута је обавезна", + "person.page.orcid.sync-queue.send.validation-error.external-id.required": "Ресурс који се шаље захтева најмање један идентификатор", + "person.page.orcid.sync-queue.send.validation-error.title.required": "Наслов је обавезан", + "person.page.orcid.sync-queue.send.validation-error.type.required": "dc.type је обавезан", + "person.page.orcid.sync-queue.send.validation-error.start-date.required": "Датум почетка је обавезан", + "person.page.orcid.sync-queue.send.validation-error.funder.required": "Финансијер је неопходан", + "person.page.orcid.sync-queue.send.validation-error.country.invalid": "Неважеће 2 цифре ISO 3166 земља", + "person.page.orcid.sync-queue.send.validation-error.organization.required": "Потребна је организација", + "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "Назив организације је обавезан", + "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "Датум објављивања мора бити годину дана после 1900. године", + "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "Организација захтева адресу", + "person.page.orcid.sync-queue.send.validation-error.organization.city-required": "Адреса организације која се шаље захтева град", + "person.page.orcid.sync-queue.send.validation-error.organization.country-required": "Адреса организације која се шаље захтева важеће 2 цифре ISO 3166 земље", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.required": "Потребан је идентификатор за недвосмисленост организација. Подржани ID-ови су GRID, Ringgold, Legal Entity identifiers (LEIs) и Crossref Funder Registry identifiers", + "person.page.orcid.sync-queue.send.validation-error.disambiguated-organization.value-required": "Идентификатори организације захтевају вредност", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.required": "Идентификаторима организације је потребан извор", + "person.page.orcid.sync-queue.send.validation-error.disambiguation-source.invalid": "Извор једног од идентификатора организације је неважећи. Подржани извори су RINGGOLD, GRID, LEI и FUNDREF", + "person.page.orcid.synchronization-mode": "Начин синхронизације", + "person.page.orcid.synchronization-mode.batch": "Batch", + "person.page.orcid.synchronization-mode.label": "Начин синхронизације", + "person.page.orcid.synchronization-mode-message": "Молимо изаберите како желите да се синхронизација са ORCID-ом одвија. Опције укључују \"Manual\" (морате ручно да пошаљете своје податке ORCID-у) или \"Batch\" (систем ће послати ваше податке ORCID-у преко планиране скрипте).", + "person.page.orcid.synchronization-mode-funding-message": "Изаберите да ли желите да пошаљете ваше повезане ентитете пројекта на листу информација о финансирању вашег ORCID записа.", + "person.page.orcid.synchronization-mode-publication-message": "Изаберите да ли желите да пошаљете ваше повезане ентитете публикације на листу радова вашег ORCID записа.", + "person.page.orcid.synchronization-mode-profile-message": "Изаберите да ли желите да пошаљете ваше биографске податке или личне идентификаторе у ваш ORCID запис.", + "person.page.orcid.synchronization-settings-update.success": "Подешавања синхронизације су успешно ажурирана", + "person.page.orcid.synchronization-settings-update.error": "Ажурирање подешавања синхронизације није успело", + "person.page.orcid.synchronization-mode.manual": "Упутство", + "person.page.orcid.scope.authenticate": "Преузмите свој ORCID ID", + "person.page.orcid.scope.read-limited": "Читајте своје информације уз видљивост подешену на Поуздане стране", + "person.page.orcid.scope.activities-update": "Додајте/ажурирајте ваше истраживачке активности", + "person.page.orcid.scope.person-update": "Додајте/ажурирајте друге информације о себи", + "person.page.orcid.unlink.success": "Прекид везе између профила и ORCID регистра је био успешан", + "person.page.orcid.unlink.error": "Дошло је до грешке приликом прекида везе између профила и ORCID регистра. Покушајте поново", + "person.orcid.sync.setting": "ORCID подешавања синхронизације", + "person.orcid.registry.queue": "ORCID Registry Queue", + "person.orcid.registry.auth": "ORCID овлашћења", + "home.recent-submissions.head": "Недавни поднесци", + "listable-notification-object.default-message": "Није могуће преузети овај објекат", + "system-wide-alert-banner.retrieval.error": "Нешто није у реду при преузимању банера системског упозорења", + "system-wide-alert-banner.countdown.prefix": "У", + "system-wide-alert-banner.countdown.days": "{{days}} дан(и),", + "system-wide-alert-banner.countdown.hours": "{{hours}} сат(и) и", + "system-wide-alert-banner.countdown.minutes": "{{minutes}} минут(и):", + "menu.section.system-wide-alert": "Системско упозорење", + "system-wide-alert.form.header": "Системско упозорење", + "system-wide-alert-form.retrieval.error": "Нешто није у реду при преузимању системског упозорења", + "system-wide-alert.form.cancel": "Отказати", + "system-wide-alert.form.save": "Сачувати", + "system-wide-alert.form.label.active": "АКТИВНО", + "system-wide-alert.form.label.inactive": "НЕАКТИВНО", + "system-wide-alert.form.error.message": "Системско упозорење мора садржати поруку", + "system-wide-alert.form.label.message": "Порука упозорења", + "system-wide-alert.form.label.countdownTo.enable": "Укључите временско одбројавање", + "system-wide-alert.form.label.countdownTo.hint": "Савет: Подесите тајмер за одбројавање. Када је укључен, датум се може подесити у будућности и банер системског упозорења ће извршити одбројавање до постављеног датума. Када тајмер заврши, нестаће из упозорења. Сервер НЕЋЕ бити аутоматски заустављен.", + "system-wide-alert.form.label.preview": "Преглед системског упозорења", + "system-wide-alert.form.update.success": "Системско упозорење је успешно ажурирано", + "system-wide-alert.form.update.error": "Нешто није у реду са ажурирањем системског упозорења", + "system-wide-alert.form.create.success": "Системско упозорење је успешно креирано", + "system-wide-alert.form.create.error": "Нешто није у реду са креирањем системског упозорења", + "admin.system-wide-alert.breadcrumbs": "Системска упозорења", + "admin.system-wide-alert.title": "Системска упозорења", + "item-access-control-title": "Овај образац вам омогућава да извршите промене услова приступа метаподацима ставке или њеним битстрим-овима.", + "collection-access-control-title": "Овај образац вам омогућава да извршите измене услова приступа свим ставкама ове колекције. Промене могу да се изврше или на свим метаподацима ставке или на целом садржају (битстрим-ова).", + "community-access-control-title": "Овај образац вам омогућава да извршите промене услова приступа свим ставкама било које колекције у овој заједници. Промене могу да се изврше или на свим метаподацима ставке или на целом садржају (битстрим-ова).", + "access-control-item-header-toggle": "Метаподаци ставке", + "access-control-bitstream-header-toggle": "битстрим-ови", + "access-control-mode": "Начин", + "access-control-access-conditions": "Услови приступа", + "access-control-no-access-conditions-warning-message": "Тренутно нису наведени услови приступа испод. Ако се изврши, то ће заменити тренутне услове приступа подразумеваним условима приступа наслеђеним из власничке колекције.", + "access-control-replace-all": "Замена услова приступа", + "access-control-add-to-existing": "Додати постојећим", + "access-control-limit-to-specific": "Ограничите промене на одређене битстрим-ове", + "access-control-process-all-bitstreams": "Ажурирајте све битстрим-ове у ставци", + "access-control-bitstreams-selected": "изабрани битстрим-ови", + "access-control-cancel": "Отказати", + "access-control-execute": "Извршити", + "access-control-add-more": "Додати још", + "access-control-select-bitstreams-modal.title": "Изаберите битстрим-ове", + "access-control-select-bitstreams-modal.no-items": "Нема ставки за приказ.", + "access-control-select-bitstreams-modal.close": "Затворити", + "access-control-option-label": "Врста услова приступа", + "access-control-option-note": "Изаберите услов приступа који ћете применити на изабране објекте.", + "access-control-option-start-date": "Приступ одобрен од", + "access-control-option-start-date-note": "Изаберите датум од којег се примењује одговарајући услов приступа", + "access-control-option-end-date": "Приступ одобрен до", + "access-control-option-end-date-note": "Изаберите датум до којег се примењује одговарајући услов приступа", +} diff --git a/src/assets/i18n/sr-lat.json5 b/src/assets/i18n/sr-lat.json5 index df8cfa18c9d..ebcc8aeb9af 100644 --- a/src/assets/i18n/sr-lat.json5 +++ b/src/assets/i18n/sr-lat.json5 @@ -208,7 +208,7 @@ "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.notification.deleted.failure.content": "Uzrok: \"{{ cause }}\"", "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", @@ -666,12 +666,12 @@ "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: <strong>Provera autentičnosti, podešavanja, potvrda i statistika</strong>. <br/> Da biste saznali više, pročitajte našu {privaciPolicy}.", + "cookies.consent.content-notice.description": "Prikupljamo i obrađujemo vaše lične podatke u sledeće svrhe: <strong>Provera autentičnosti, podešavanja, potvrda i statistika</strong>. <br/> Da biste saznali više, pročitajte našu {privacyPolicy}.", "cookies.consent.content-notice.description.no-privacy": "Prikupljamo i obrađujemo vaše lične podatke u sledeće svrhe: <strong>Provera autentičnosti, podešavanja, potvrda i statistika</strong>.", "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.privacy-policy.text": "Da saznate više, pročitajte našu {privacyPolicy}.", "cookies.consent.content-modal.title": "Informacije koje prikupljamo", "cookies.consent.content-modal.services": "Usluge", "cookies.consent.content-modal.service": "Usluga", @@ -1258,7 +1258,7 @@ "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.selected.alert": "Trenutno gledate verziju {{version}} stavke.", "item.version.history.table.version": "Verzija", "item.version.history.table.item": "Stavka", "item.version.history.table.editor": "Urednik", @@ -1547,7 +1547,7 @@ "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.showing.label": "Prikazuje se ", "pagination.sort-direction": "Opcije sortiranja", "person.listelement.badge": "Osoba", "person.listelement.no-title": "Ime nije pronađeno", @@ -1965,7 +1965,7 @@ "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.deposit": "Deponovati", "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", diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 523ccf4f504..61e7abcd62c 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -238,6 +238,7 @@ export class DefaultAppConfig implements AppConfig { { code: 'bn', label: 'বাংলা', active: true }, { code: 'hi', label: 'हिंदी', active: true}, { code: 'el', label: 'Ελληνικά', active: true }, + { code: 'sr-cyr', label: 'Српски', active: true}, { code: 'uk', label: 'Yкраї́нська', active: true} ]; From aa9e12dcfe10fab31d9fcc9f96088ccf31f8e843 Mon Sep 17 00:00:00 2001 From: imilos <imilos@gmail.com> Date: Fri, 20 Oct 2023 11:27:22 +0200 Subject: [PATCH 155/282] Added Serbian cyrilic translation and corrected Serbian latin translation. --- src/assets/i18n/sr-cyr.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/sr-cyr.json5 b/src/assets/i18n/sr-cyr.json5 index 5f2dc12f358..81b776529c9 100644 --- a/src/assets/i18n/sr-cyr.json5 +++ b/src/assets/i18n/sr-cyr.json5 @@ -706,7 +706,7 @@ "curation.form.submit.error.invalid-handle": "Није могуће одредити handle за овај објекат", "curation.form.handle.label": "Handle:", "curation.form.handle.hint": "Савет: Унесите [your-handle-prefix]/0 да бисте покренули задатак на целом сајту (ову могућност не подржавају сви задаци)", - "deny-request-copy.email.message": "Поштовани {{ recipientName }}, \н Као одговор на ваш захтев, са жаљењем вас обавештавам да није могуће послати копију фајла коју сте тражили, у вези са документом: \"{{ itemUrl }}\" ({{ itemName }}), чији сам аутор. \н Срдачан поздрав, \н{{ authorName }} <{{ authorEmail }}>", + "deny-request-copy.email.message": "Поштовани {{ recipientName }}, \n Као одговор на ваш захтев, са жаљењем вас обавештавам да није могуће послати копију фајла коју сте тражили, у вези са документом: \"{{ itemUrl }}\" ({{ itemName }}), чији сам аутор. \n Срдачан поздрав, \n{{ authorName }} <{{ authorEmail }}>", "deny-request-copy.email.subject": "Затражите копију документа", "deny-request-copy.error": "Дошло је до грешке", "deny-request-copy.header": "Одбијен захтев за копирање документа", From 6f73b65d530ad8d2e8297af179e111f401823bce Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 20 Oct 2023 10:34:29 -0500 Subject: [PATCH 156/282] Revert "Check cssRules before css variables are read from stylesheet (#2454)" This reverts commit fa79c358c09cb52ed142ef122e08b77de880685d. --- src/app/shared/sass-helper/css-variable.service.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/app/shared/sass-helper/css-variable.service.ts b/src/app/shared/sass-helper/css-variable.service.ts index ca6384e0ee5..0190a05036f 100644 --- a/src/app/shared/sass-helper/css-variable.service.ts +++ b/src/app/shared/sass-helper/css-variable.service.ts @@ -26,15 +26,6 @@ export class CSSVariableService { return styleSheet.href.indexOf(window.location.origin) === 0; }; - /** - * Checks whether the specific stylesheet object has the property cssRules - * @param styleSheet The stylesheet - */ - hasCssRules = (styleSheet) => { - // Injected styles might have no css rules value - return styleSheet.hasOwnProperty('cssRules') && styleSheet.cssRules; - }; - /* Determine if the given rule is a CSSStyleRule See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants @@ -102,10 +93,8 @@ export class CSSVariableService { if (isNotEmpty(document.styleSheets)) { // styleSheets is array-like, so we convert it to an array. // Filter out any stylesheets not on this domain - // Filter out any stylesheets that have no cssRules property return [...document.styleSheets] .filter(this.isSameDomain) - .filter(this.hasCssRules) .reduce( (finalArr, sheet) => finalArr.concat( From fb315335c90a0e2dde367e473a2e73729fedc429 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 21 Oct 2023 14:45:37 +0200 Subject: [PATCH 157/282] Fix RequestService test failing because of different lastUpdated time --- src/app/core/data/request.service.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index d1a1f66e41a..61091c79404 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -661,7 +661,9 @@ describe('RequestService', () => { spyOn(service, 'getByHref').and.returnValue(observableOf(staleRE)); spyOn(store, 'dispatch'); service.setStaleByHref(href).subscribe(() => { - expect(store.dispatch).toHaveBeenCalledWith(new RequestStaleAction(uuid)); + const requestStaleAction = new RequestStaleAction(uuid); + requestStaleAction.lastUpdated = jasmine.any(Number) as any; + expect(store.dispatch).toHaveBeenCalledWith(requestStaleAction); done(); }); }); From 987a92f5293cb7aec95664c4faefcd99aa71c830 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 21 Oct 2023 18:07:16 +0200 Subject: [PATCH 158/282] Filter out all the AuthMethods who don't have a component to render before rendering LogInContainerComponent --- .../container/log-in-container.component.ts | 16 +++++--------- src/app/shared/log-in/log-in.component.html | 10 +++------ src/app/shared/log-in/log-in.component.ts | 22 +++++-------------- .../methods/log-in.methods-decorator.ts | 5 +++-- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/app/shared/log-in/container/log-in-container.component.ts b/src/app/shared/log-in/container/log-in-container.component.ts index f6a08a1e1ec..28e9f2f7e18 100644 --- a/src/app/shared/log-in/container/log-in-container.component.ts +++ b/src/app/shared/log-in/container/log-in-container.component.ts @@ -1,5 +1,4 @@ -import { Component, Injector, Input, OnInit } from '@angular/core'; - +import { Component, Injector, Input, OnInit, Type } from '@angular/core'; import { rendersAuthMethodType } from '../methods/log-in.methods-decorator'; import { AuthMethod } from '../../../core/auth/models/auth.method'; @@ -27,12 +26,9 @@ export class LogInContainerComponent implements OnInit { */ public objectInjector: Injector; - /** - * Initialize instance variables - * - * @param {Injector} injector - */ - constructor(private injector: Injector) { + constructor( + protected injector: Injector, + ) { } /** @@ -51,8 +47,8 @@ export class LogInContainerComponent implements OnInit { /** * Find the correct component based on the AuthMethod's type */ - getAuthMethodContent(): string { - return rendersAuthMethodType(this.authMethod.authMethodType); + getAuthMethodContent(): Type<Component> { + return rendersAuthMethodType(this.authMethod.authMethodType); } } diff --git a/src/app/shared/log-in/log-in.component.html b/src/app/shared/log-in/log-in.component.html index 173e0f8e303..7ce14cdeb2e 100644 --- a/src/app/shared/log-in/log-in.component.html +++ b/src/app/shared/log-in/log-in.component.html @@ -1,11 +1,7 @@ <ds-themed-loading *ngIf="(loading | async) || (isAuthenticated | async)" class="m-5"></ds-themed-loading> <div *ngIf="!(loading | async) && !(isAuthenticated | async)" class="px-4 py-3 login-container"> - <ng-container *ngFor="let authMethod of getOrderedAuthMethods(authMethods | async); let last = last"> - <div [class.d-none]="contentRef.innerText.trim().length === 0"> - <div #contentRef> - <ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container> - </div> - <div *ngIf="!last" class="dropdown-divider my-2"></div> - </div> + <ng-container *ngFor="let authMethod of (authMethods | async); let last = last"> + <ds-log-in-container [authMethod]="authMethod" [isStandalonePage]="isStandalonePage"></ds-log-in-container> + <div *ngIf="!last" class="dropdown-divider my-2"></div> </ng-container> </div> diff --git a/src/app/shared/log-in/log-in.component.ts b/src/app/shared/log-in/log-in.component.ts index 9cc466dcfe2..9d596a2a154 100644 --- a/src/app/shared/log-in/log-in.component.ts +++ b/src/app/shared/log-in/log-in.component.ts @@ -11,11 +11,9 @@ import { import { hasValue } from '../empty.util'; import { AuthService } from '../../core/auth/auth.service'; import { CoreState } from '../../core/core-state.model'; +import { rendersAuthMethodType } from './methods/log-in.methods-decorator'; +import { map } from 'rxjs/operators'; -/** - * /users/sign-in - * @class LogInComponent - */ @Component({ selector: 'ds-log-in', templateUrl: './log-in.component.html', @@ -57,6 +55,10 @@ export class LogInComponent implements OnInit { this.authMethods = this.store.pipe( select(getAuthenticationMethods), + map((methods: AuthMethod[]) => methods + .filter((authMethod: AuthMethod) => rendersAuthMethodType(authMethod.authMethodType) !== undefined) + .sort((method1: AuthMethod, method2: AuthMethod) => method1.position - method2.position) + ), ); // set loading @@ -73,16 +75,4 @@ export class LogInComponent implements OnInit { }); } - /** - * Returns an ordered list of {@link AuthMethod}s based on their position. - * - * @param authMethods The {@link AuthMethod}s to sort - */ - getOrderedAuthMethods(authMethods: AuthMethod[] | null): AuthMethod[] { - if (hasValue(authMethods)) { - return [...authMethods].sort((method1: AuthMethod, method2: AuthMethod) => method1.position - method2.position); - } else { - return []; - } - } } diff --git a/src/app/shared/log-in/methods/log-in.methods-decorator.ts b/src/app/shared/log-in/methods/log-in.methods-decorator.ts index 0614bdeb511..e30a4813dd8 100644 --- a/src/app/shared/log-in/methods/log-in.methods-decorator.ts +++ b/src/app/shared/log-in/methods/log-in.methods-decorator.ts @@ -1,6 +1,7 @@ +import { Component, Type } from '@angular/core'; import { AuthMethodType } from '../../../core/auth/models/auth.method-type'; -const authMethodsMap = new Map(); +const authMethodsMap: Map<AuthMethodType, Type<Component>> = new Map(); export function renderAuthMethodFor(authMethodType: AuthMethodType) { return function decorator(objectElement: any) { @@ -11,6 +12,6 @@ export function renderAuthMethodFor(authMethodType: AuthMethodType) { }; } -export function rendersAuthMethodType(authMethodType: AuthMethodType) { +export function rendersAuthMethodType(authMethodType: AuthMethodType): Type<Component> | undefined { return authMethodsMap.get(authMethodType); } From 51b13fb78cac180ab27f117e63d975c8b0b5497d Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 21 Oct 2023 18:08:02 +0200 Subject: [PATCH 159/282] Fix AuthorizationDataService.isAuthorized throwing a console error when the searchByObject request doesn't succeed --- .../data/feature-authorization/authorization-data.service.ts | 2 +- .../core/data/feature-authorization/authorization-utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/core/data/feature-authorization/authorization-data.service.ts b/src/app/core/data/feature-authorization/authorization-data.service.ts index c43d335234b..95730422726 100644 --- a/src/app/core/data/feature-authorization/authorization-data.service.ts +++ b/src/app/core/data/feature-authorization/authorization-data.service.ts @@ -74,7 +74,7 @@ export class AuthorizationDataService extends BaseDataService<Authorization> imp return []; } }), - catchError(() => observableOf(false)), + catchError(() => observableOf([])), oneAuthorizationMatchesFeature(featureId) ); } diff --git a/src/app/core/data/feature-authorization/authorization-utils.ts b/src/app/core/data/feature-authorization/authorization-utils.ts index d1b65f61235..a4e5e4d997c 100644 --- a/src/app/core/data/feature-authorization/authorization-utils.ts +++ b/src/app/core/data/feature-authorization/authorization-utils.ts @@ -68,13 +68,13 @@ export const oneAuthorizationMatchesFeature = (featureID: FeatureID) => source.pipe( switchMap((authorizations: Authorization[]) => { if (isNotEmpty(authorizations)) { - return observableCombineLatest( + return observableCombineLatest([ ...authorizations .filter((authorization: Authorization) => hasValue(authorization.feature)) .map((authorization: Authorization) => authorization.feature.pipe( getFirstSucceededRemoteDataPayload() )) - ); + ]); } else { return observableOf([]); } From 2f26e686cc472a0929e27b6c70cda823dab55fc5 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe <kristof.delanghe@atmire.com> Date: Wed, 25 Oct 2023 11:20:39 +0200 Subject: [PATCH 160/282] 107685: menu-component re-render section on store update --- src/app/shared/menu/menu.component.ts | 3 +-- src/app/shared/menu/menu.service.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts index 35e180b4761..805f5888ead 100644 --- a/src/app/shared/menu/menu.component.ts +++ b/src/app/shared/menu/menu.component.ts @@ -6,7 +6,6 @@ import { GenericConstructor } from '../../core/shared/generic-constructor'; import { hasValue, isNotEmptyOperator } from '../empty.util'; import { MenuSectionComponent } from './menu-section/menu-section.component'; import { getComponentForMenu } from './menu-section.decorator'; -import { compareArraysUsingIds } from '../../item-page/simple/item-types/shared/item-relationships-utils'; import { MenuSection } from './menu-section.model'; import { MenuID } from './menu-id.model'; import { ActivatedRoute } from '@angular/router'; @@ -86,7 +85,7 @@ export class MenuComponent implements OnInit, OnDestroy { this.menuCollapsed = this.menuService.isMenuCollapsed(this.menuID); this.menuPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID); this.menuVisible = this.menuService.isMenuVisible(this.menuID); - this.sections = this.menuService.getMenuTopSections(this.menuID).pipe(distinctUntilChanged(compareArraysUsingIds())); + this.sections = this.menuService.getMenuTopSections(this.menuID); this.subs.push( this.sections.pipe( diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts index f44ddea649b..1412acf09b2 100644 --- a/src/app/shared/menu/menu.service.ts +++ b/src/app/shared/menu/menu.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { AppState, keySelector } from '../../app.reducer'; import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; -import { map, switchMap } from 'rxjs/operators'; +import { distinctUntilChanged, map, switchMap } from 'rxjs/operators'; import { ActivateMenuSectionAction, AddMenuSectionAction, @@ -22,6 +22,7 @@ import { MenuState } from './menu-state.model'; import { MenuSections } from './menu-sections.model'; import { MenuSection } from './menu-section.model'; import { MenuID } from './menu-id.model'; +import { compareArraysUsingIds } from '../../item-page/simple/item-types/shared/item-relationships-utils'; export function menuKeySelector<T>(key: string, selector): MemoizedSelector<MenuState, T> { return createSelector(selector, (state) => { @@ -76,8 +77,10 @@ export class MenuService { return this.store.pipe( select(menuByIDSelector(menuID)), select(menuSectionStateSelector), - map((sections: MenuSections) => { - return Object.values(sections) + map((sections: MenuSections) => Object.values(sections)), + distinctUntilChanged(compareArraysUsingIds()), + map((sections: MenuSection[]) => { + return sections .filter((section: MenuSection) => hasNoValue(section.parentID)) .filter((section: MenuSection) => !mustBeVisible || section.visible); } From 09aaa46875146081cf812ed6f904178740ae8d30 Mon Sep 17 00:00:00 2001 From: Andreas Mahnke <andreas.mahnke@leuphana.de> Date: Wed, 25 Oct 2023 16:10:05 +0200 Subject: [PATCH 161/282] Support type-bind of elements based on repeatable list type-bound element (CHECKBOX_GROUP) --- .../ds-dynamic-type-bind-relation.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts index d5e735ed1a9..5f7e2e3e228 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts @@ -183,7 +183,8 @@ export class DsDynamicTypeBindRelationService { const initValue = (hasNoValue(relatedModel.value) || typeof relatedModel.value === 'string') ? relatedModel.value : (Array.isArray(relatedModel.value) ? relatedModel.value : relatedModel.value.value); - const valueChanges = relatedModel.valueChanges.pipe( + const updateSubject = (relatedModel.type === 'CHECKBOX_GROUP' ? relatedModel.valueUpdates : relatedModel.valueChanges); + const valueChanges = updateSubject.pipe( startWith(initValue) ); From e847e4ef51aab604d1d07b79860003551eafe467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= <paulo1978@gmail.com> Date: Thu, 26 Oct 2023 14:14:22 +0100 Subject: [PATCH 162/282] adding new access-status-list-element-badge css classes --- .../access-status-badge/access-status-badge.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html index a0180a761aa..264bd3621ca 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html @@ -1,5 +1,5 @@ <ng-container *ngIf="showAccessStatus"> <span *ngIf="accessStatus$ | async as accessStatus"> - <span class="badge badge-secondary">{{ accessStatus | translate }}</span> + <span [class]="'badge badge-secondary access-status-list-element-badge ' + accessStatus.replaceAll('.','-')">{{ accessStatus | translate }}</span> </span> </ng-container> From 4dd334f2e76adfabb972095acc80a391c6c91b38 Mon Sep 17 00:00:00 2001 From: "Gantner, Florian Klaus" <florian.gantner@uni-bamberg.de> Date: Thu, 26 Oct 2023 15:56:52 +0200 Subject: [PATCH 163/282] more error-prone check of cssRules existence before css variables are get from stylesheet check the existence off cssRules property before the variables are readed from this stylesheet https://github.com/DSpace/dspace-angular/issues/2450 --- .../shared/sass-helper/css-variable.service.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/app/shared/sass-helper/css-variable.service.ts b/src/app/shared/sass-helper/css-variable.service.ts index 0190a05036f..5ff7345d85d 100644 --- a/src/app/shared/sass-helper/css-variable.service.ts +++ b/src/app/shared/sass-helper/css-variable.service.ts @@ -26,6 +26,19 @@ export class CSSVariableService { return styleSheet.href.indexOf(window.location.origin) === 0; }; + /** + * Checks whether the specific stylesheet object has the property cssRules + * @param styleSheet The stylesheet + */ + hasCssRules = (styleSheet) => { + // Injected (cross-origin) styles might have no css rules value and throw some exception + try { + return styleSheet.cssRules; + } catch (e) { + return false; + } + }; + /* Determine if the given rule is a CSSStyleRule See: https://developer.mozilla.org/en-US/docs/Web/API/CSSRule#Type_constants @@ -93,8 +106,10 @@ export class CSSVariableService { if (isNotEmpty(document.styleSheets)) { // styleSheets is array-like, so we convert it to an array. // Filter out any stylesheets not on this domain + // Filter out any stylesheets that have no cssRules property return [...document.styleSheets] .filter(this.isSameDomain) + .filter(this.hasCssRules) .reduce( (finalArr, sheet) => finalArr.concat( From f261264beba06ddd906aad9d860692b17f231454 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 26 Aug 2023 22:02:33 +0200 Subject: [PATCH 164/282] Implemented i18n cache busting (cherry picked from commit 07a2e333ca5cb0f55178f9352d93b09f4fb311b2) --- package.json | 2 +- .../translate-browser.loader.ts | 4 +- .../translate-server.loader.ts | 3 +- webpack/helpers.ts | 47 +++++++++++++++---- webpack/webpack.common.ts | 11 +++-- 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 2116da6a0e3..f8644477900 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "analyze": "webpack-bundle-analyzer dist/browser/stats.json", "build": "ng build --configuration development", "build:stats": "ng build --stats-json", - "build:prod": "yarn run build:ssr", + "build:prod": "cross-env NODE_ENV=production yarn run build:ssr", "build:ssr": "ng build --configuration production && ng run dspace-angular:server:production", "test": "ng test --source-map=true --watch=false --configuration test", "test:watch": "nodemon --exec \"ng test --source-map=true --watch=true --configuration test\"", diff --git a/src/ngx-translate-loaders/translate-browser.loader.ts b/src/ngx-translate-loaders/translate-browser.loader.ts index a6188c9f15c..85d59c96f0a 100644 --- a/src/ngx-translate-loaders/translate-browser.loader.ts +++ b/src/ngx-translate-loaders/translate-browser.loader.ts @@ -5,6 +5,7 @@ import { NGX_TRANSLATE_STATE, NgxTranslateState } from './ngx-translate-state'; import { hasValue } from '../app/shared/empty.util'; import { map } from 'rxjs/operators'; import { of as observableOf, Observable } from 'rxjs'; +import { environment } from '../environments/environment'; /** * A TranslateLoader for ngx-translate to retrieve i18n messages from the TransferState, or download @@ -33,9 +34,10 @@ export class TranslateBrowserLoader implements TranslateLoader { if (hasValue(messages)) { return observableOf(messages); } else { + const translationHash: string = environment.production ? `.${(process.env.languageHashes as any)[lang + '.json5']}` : ''; // If they're not available on the transfer state (e.g. when running in dev mode), retrieve // them using HttpClient - return this.http.get('' + this.prefix + lang + this.suffix, { responseType: 'text' }).pipe( + return this.http.get(`${this.prefix}${lang}${translationHash}${this.suffix}`, { responseType: 'text' }).pipe( map((json: any) => JSON.parse(json)) ); } diff --git a/src/ngx-translate-loaders/translate-server.loader.ts b/src/ngx-translate-loaders/translate-server.loader.ts index c09c71f0499..1f47dfe95b5 100644 --- a/src/ngx-translate-loaders/translate-server.loader.ts +++ b/src/ngx-translate-loaders/translate-server.loader.ts @@ -23,8 +23,9 @@ export class TranslateServerLoader implements TranslateLoader { * @param lang the language code */ public getTranslation(lang: string): Observable<any> { + const translationHash: string = (process.env.languageHashes as any)[lang + '.json5']; // Retrieve the file for the given language, and parse it - const messages = JSON.parse(readFileSync(`${this.prefix}${lang}${this.suffix}`, 'utf8')); + const messages = JSON.parse(readFileSync(`${this.prefix}${lang}.${translationHash}${this.suffix}`, 'utf8')); // Store the parsed messages in the transfer state so they'll be available immediately when the // app loads on the client this.storeInTransferState(lang, messages); diff --git a/webpack/helpers.ts b/webpack/helpers.ts index 43855f6c729..f0b42a8a690 100644 --- a/webpack/helpers.ts +++ b/webpack/helpers.ts @@ -1,18 +1,49 @@ -const path = require('path'); +import { readFileSync, readdirSync, statSync, Stats } from 'fs'; +import { join, resolve } from 'path'; + +const md5 = require('md5'); export const projectRoot = (relativePath) => { - return path.resolve(__dirname, '..', relativePath); + return resolve(__dirname, '..', relativePath); }; export const globalCSSImports = () => { return [ - projectRoot(path.join('src', 'styles', '_variables.scss')), - projectRoot(path.join('src', 'styles', '_mixins.scss')), + projectRoot(join('src', 'styles', '_variables.scss')), + projectRoot(join('src', 'styles', '_mixins.scss')), ]; }; +/** + * Calculates the md5 hash of a file + * + * @param filePath The path of the file + */ +export function calculateFileHash(filePath: string): string { + const fileContent: Buffer = readFileSync(filePath); + return md5(fileContent); +} -module.exports = { - projectRoot, - globalCSSImports -}; +/** + * Calculate the hashes of all the files (matching the given regex) in a certain folder + * + * @param folderPath The path of the folder + * @param regExp A regex of the files in the folder for which a hash needs to be generated + */ +export function getFileHashes(folderPath: string, regExp: RegExp): { [fileName: string]: string } { + const files: string[] = readdirSync(folderPath); + let hashes: { [fileName: string]: string } = {}; + + for (const file of files) { + if (file.match(regExp)) { + const filePath: string = join(folderPath, file); + const stats: Stats = statSync(filePath); + + if (stats.isFile()) { + hashes[file] = calculateFileHash(filePath); + } + } + } + + return hashes; +} diff --git a/webpack/webpack.common.ts b/webpack/webpack.common.ts index 1a1ecfd6efe..8d433edf393 100644 --- a/webpack/webpack.common.ts +++ b/webpack/webpack.common.ts @@ -1,4 +1,5 @@ -import { globalCSSImports, projectRoot } from './helpers'; +import { globalCSSImports, projectRoot, getFileHashes, calculateFileHash } from './helpers'; +import { EnvironmentPlugin } from 'webpack'; const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); @@ -18,12 +19,13 @@ export const copyWebpackOptions = { // use [\/|\\] to match both POSIX and Windows separators const matches = absoluteFilename.match(/.*[\/|\\]assets[\/|\\](.+)\.json5$/); if (matches) { + const fileHash: string = process.env.NODE_ENV === 'production' ? `.${calculateFileHash(absoluteFilename)}` : ''; // matches[1] is the relative path from src/assets to the JSON5 file, without the extension - return path.join('assets', matches[1] + '.json'); + return path.join('assets', `${matches[1]}${fileHash}.json`); } }, transform(content) { - return JSON.stringify(JSON5.parse(content.toString())) + return JSON.stringify(JSON5.parse(content.toString())); } }, { @@ -77,6 +79,9 @@ const SCSS_LOADERS = [ export const commonExports = { plugins: [ + new EnvironmentPlugin({ + languageHashes: getFileHashes(path.join(__dirname, '..', 'src', 'assets', 'i18n'), /.*\.json5/g), + }), new CopyWebpackPlugin(copyWebpackOptions), ], module: { From ab171648b6b78453644891a306d3fea5068ff6ca Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Thu, 26 Oct 2023 23:04:44 +0200 Subject: [PATCH 165/282] New themed components & minor CSS fixes (#2442) * 100839: Created themeable BrowseByComponent * 100839: Added themed BrowseByComponent to custom theme * 100839: Added themed BrowseEntryListElementComponent to custom theme * Added PersonComponent to custom theme * Themed LogInComponent * Fix focus on navbar using different color * Fix ccLicense checkbox margin * Fix long search facets name not displaying correctly * Removed RecentItemListComponent's unnecessary float causing alignment issues when adding components underneath it * Themed RegisterEmailFormComponent --- .../browse-by-date-page.component.ts | 12 +-- .../browse-by-metadata-page.component.html | 4 +- src/app/browse-by/browse-by.module.ts | 2 + .../forgot-email.component.html | 4 +- .../recent-item-list.component.html | 4 +- src/app/login-page/login-page.component.html | 4 +- src/app/navbar/navbar.component.scss | 7 +- .../register-email-form.module.ts | 10 ++- .../themed-registry-email-form.component.ts | 36 +++++++++ .../register-email.component.html | 4 +- .../auth-nav-menu.component.html | 4 +- .../browse-by/shared-browse-by.module.ts | 13 +++- .../browse-by/themed-browse-by.component.ts | 76 +++++++++++++++++++ .../shared/log-in/log-in.component.spec.ts | 5 +- .../shared/log-in/themed-log-in.component.ts | 33 ++++++++ .../search-filter.component.html | 2 +- .../search-filter.component.scss | 1 - src/app/shared/shared.module.ts | 2 + ...mission-section-cc-licenses.component.html | 1 + .../item-pages/person/person.component.html | 0 .../item-pages/person/person.component.scss | 0 .../item-pages/person/person.component.ts | 20 +++++ .../app/login-page/login-page.component.html | 4 +- .../register-email-form.component.html | 0 .../register-email-form.component.ts | 12 +++ .../shared/browse-by/browse-by.component.html | 0 .../shared/browse-by/browse-by.component.scss | 0 .../shared/browse-by/browse-by.component.ts | 17 +++++ .../app/shared/log-in/log-in.component.html | 0 .../app/shared/log-in/log-in.component.scss | 0 .../app/shared/log-in/log-in.component.ts | 12 +++ .../browse-entry-list-element.component.html | 0 .../browse-entry-list-element.component.scss | 0 .../browse-entry-list-element.component.ts | 19 +++++ src/themes/custom/eager-theme.module.ts | 6 ++ src/themes/custom/lazy-theme.module.ts | 4 + .../dspace/app/navbar/navbar.component.scss | 7 +- 37 files changed, 290 insertions(+), 35 deletions(-) create mode 100644 src/app/register-email-form/themed-registry-email-form.component.ts create mode 100644 src/app/shared/browse-by/themed-browse-by.component.ts create mode 100644 src/app/shared/log-in/themed-log-in.component.ts create mode 100644 src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.html create mode 100644 src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.scss create mode 100644 src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.ts create mode 100644 src/themes/custom/app/register-email-form/register-email-form.component.html create mode 100644 src/themes/custom/app/register-email-form/register-email-form.component.ts create mode 100644 src/themes/custom/app/shared/browse-by/browse-by.component.html create mode 100644 src/themes/custom/app/shared/browse-by/browse-by.component.scss create mode 100644 src/themes/custom/app/shared/browse-by/browse-by.component.ts create mode 100644 src/themes/custom/app/shared/log-in/log-in.component.html create mode 100644 src/themes/custom/app/shared/log-in/log-in.component.scss create mode 100644 src/themes/custom/app/shared/log-in/log-in.component.ts create mode 100644 src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html create mode 100644 src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.scss create mode 100644 src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts diff --git a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts index 7074190e1eb..c52731a421f 100644 --- a/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/browse-by/browse-by-date-page/browse-by-date-page.component.ts @@ -89,11 +89,11 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { const lastItemRD = this.browseService.getFirstItemFor(definition, scope, SortDirection.DESC); this.subs.push( observableCombineLatest([firstItemRD, lastItemRD]).subscribe(([firstItem, lastItem]) => { - let lowerLimit = this.getLimit(firstItem, metadataKeys, this.appConfig.browseBy.defaultLowerLimit); - let upperLimit = this.getLimit(lastItem, metadataKeys, new Date().getUTCFullYear()); - const options = []; - const oneYearBreak = Math.floor((upperLimit - this.appConfig.browseBy.oneYearLimit) / 5) * 5; - const fiveYearBreak = Math.floor((upperLimit - this.appConfig.browseBy.fiveYearLimit) / 10) * 10; + let lowerLimit: number = this.getLimit(firstItem, metadataKeys, this.appConfig.browseBy.defaultLowerLimit); + let upperLimit: number = this.getLimit(lastItem, metadataKeys, new Date().getUTCFullYear()); + const options: number[] = []; + const oneYearBreak: number = Math.floor((upperLimit - this.appConfig.browseBy.oneYearLimit) / 5) * 5; + const fiveYearBreak: number = Math.floor((upperLimit - this.appConfig.browseBy.fiveYearLimit) / 10) * 10; if (lowerLimit <= fiveYearBreak) { lowerLimit -= 10; } else if (lowerLimit <= oneYearBreak) { @@ -101,7 +101,7 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { } else { lowerLimit -= 1; } - let i = upperLimit; + let i: number = upperLimit; while (i > lowerLimit) { options.push(i); if (i <= fiveYearBreak) { diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html index 8d062d739f5..cfc2cbe3056 100644 --- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html +++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html @@ -32,7 +32,7 @@ <section class="comcol-page-browse-section"> <div class="browse-by-metadata w-100"> - <ds-browse-by *ngIf="startsWithOptions" class="col-xs-12 w-100" + <ds-themed-browse-by *ngIf="startsWithOptions" class="col-xs-12 w-100" title="{{'browse.title' | translate: { collection: dsoNameService.getName((parent$ | async)?.payload), @@ -48,7 +48,7 @@ [startsWithOptions]="startsWithOptions" (prev)="goPrev()" (next)="goNext()"> - </ds-browse-by> + </ds-themed-browse-by> <ds-themed-loading *ngIf="!startsWithOptions" message="{{'loading.browse-by-page' | translate}}"></ds-themed-loading> </div> </section> diff --git a/src/app/browse-by/browse-by.module.ts b/src/app/browse-by/browse-by.module.ts index c0e2d3f9ff8..ec9f22347f7 100644 --- a/src/app/browse-by/browse-by.module.ts +++ b/src/app/browse-by/browse-by.module.ts @@ -14,6 +14,7 @@ import { ThemedBrowseByTaxonomyPageComponent } from './browse-by-taxonomy-page/t import { SharedBrowseByModule } from '../shared/browse-by/shared-browse-by.module'; import { DsoPageModule } from '../shared/dso-page/dso-page.module'; import { FormModule } from '../shared/form/form.module'; +import { SharedModule } from '../shared/shared.module'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -35,6 +36,7 @@ const ENTRY_COMPONENTS = [ ComcolModule, DsoPageModule, FormModule, + SharedModule, ], declarations: [ BrowseBySwitcherComponent, diff --git a/src/app/forgot-password/forgot-password-email/forgot-email.component.html b/src/app/forgot-password/forgot-password-email/forgot-email.component.html index 995108cdbc3..aaa0c27b466 100644 --- a/src/app/forgot-password/forgot-password-email/forgot-email.component.html +++ b/src/app/forgot-password/forgot-password-email/forgot-email.component.html @@ -1,3 +1,3 @@ -<ds-register-email-form +<ds-themed-register-email-form [MESSAGE_PREFIX]="'forgot-email.form'" [typeRequest]="typeRequest"> -</ds-register-email-form> +</ds-themed-register-email-form> diff --git a/src/app/home-page/recent-item-list/recent-item-list.component.html b/src/app/home-page/recent-item-list/recent-item-list.component.html index cd14891b3ff..82262be1b34 100644 --- a/src/app/home-page/recent-item-list/recent-item-list.component.html +++ b/src/app/home-page/recent-item-list/recent-item-list.component.html @@ -1,12 +1,12 @@ <ng-container *ngVar="(itemRD$ | async) as itemRD"> <div class="mt-4" [ngClass]="placeholderFontClass" *ngIf="itemRD?.hasSucceeded && itemRD?.payload?.page.length > 0" @fadeIn> - <div class="d-flex flex-row border-bottom mb-4 pb-4 ng-tns-c416-2"></div> + <div class="d-flex flex-row border-bottom mb-4 pb-4"></div> <h2> {{'home.recent-submissions.head' | translate}}</h2> <div class="my-4" *ngFor="let item of itemRD?.payload?.page"> <ds-listable-object-component-loader [object]="item" [viewMode]="viewMode" class="pb-4"> </ds-listable-object-component-loader> </div> - <button (click)="onLoadMore()" class="btn btn-primary search-button mt-4 float-left ng-tns-c290-40"> {{'vocabulary-treeview.load-more' | translate }} ...</button> + <button (click)="onLoadMore()" class="btn btn-primary search-button mt-4"> {{'vocabulary-treeview.load-more' | translate }} ...</button> </div> <ds-error *ngIf="itemRD?.hasFailed" message="{{'error.recent-submissions' | translate}}"></ds-error> <ds-loading *ngIf="!itemRD || itemRD.isLoading" message="{{'loading.recent-submissions' | translate}}"> diff --git a/src/app/login-page/login-page.component.html b/src/app/login-page/login-page.component.html index 2a95e0ce1c5..c38444bec8c 100644 --- a/src/app/login-page/login-page.component.html +++ b/src/app/login-page/login-page.component.html @@ -3,8 +3,8 @@ <div> <img class="mb-4 login-logo" src="assets/images/dspace-logo.png" alt="{{'repository.image.logo' | translate}}"> <h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1> - <ds-log-in - [isStandalonePage]="true"></ds-log-in> + <ds-themed-log-in + [isStandalonePage]="true"></ds-themed-log-in> </div> </div> </div> diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss index 9dc530607cf..42e72aaffd8 100644 --- a/src/app/navbar/navbar.component.scss +++ b/src/app/navbar/navbar.component.scss @@ -39,8 +39,9 @@ nav.navbar { .navbar-nav { ::ng-deep a.nav-link { color: var(--ds-navbar-link-color); - } - ::ng-deep a.nav-link:hover { - color: var(--ds-navbar-link-color-hover); + + &:hover, &:focus { + color: var(--ds-navbar-link-color-hover); + } } } diff --git a/src/app/register-email-form/register-email-form.module.ts b/src/app/register-email-form/register-email-form.module.ts index a7657594137..2fa2ddcd6e3 100644 --- a/src/app/register-email-form/register-email-form.module.ts +++ b/src/app/register-email-form/register-email-form.module.ts @@ -2,6 +2,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '../shared/shared.module'; import { RegisterEmailFormComponent } from './register-email-form.component'; +import { ThemedRegisterEmailFormComponent } from './themed-registry-email-form.component'; + +const DECLARATIONS = [ + RegisterEmailFormComponent, + ThemedRegisterEmailFormComponent, +]; @NgModule({ imports: [ @@ -9,11 +15,11 @@ import { RegisterEmailFormComponent } from './register-email-form.component'; SharedModule ], declarations: [ - RegisterEmailFormComponent, + ...DECLARATIONS, ], providers: [], exports: [ - RegisterEmailFormComponent, + ...DECLARATIONS, ] }) diff --git a/src/app/register-email-form/themed-registry-email-form.component.ts b/src/app/register-email-form/themed-registry-email-form.component.ts new file mode 100644 index 00000000000..4f627e5b830 --- /dev/null +++ b/src/app/register-email-form/themed-registry-email-form.component.ts @@ -0,0 +1,36 @@ +import { Component, Input } from '@angular/core'; +import { ThemedComponent } from '../shared/theme-support/themed.component'; +import { RegisterEmailFormComponent } from './register-email-form.component'; + +/** + * Themed wrapper for {@link RegisterEmailFormComponent} + */ +@Component({ + selector: 'ds-themed-register-email-form', + styleUrls: [], + templateUrl: '../shared/theme-support/themed.component.html', +}) +export class ThemedRegisterEmailFormComponent extends ThemedComponent<RegisterEmailFormComponent> { + + @Input() MESSAGE_PREFIX: string; + + @Input() typeRequest: string; + + protected inAndOutputNames: (keyof RegisterEmailFormComponent & keyof this)[] = [ + 'MESSAGE_PREFIX', + 'typeRequest', + ]; + + protected getComponentName(): string { + return 'RegisterEmailFormComponent'; + } + + protected importThemedComponent(themeName: string): Promise<any> { + return import(`../../themes/${themeName}/app/register-email-form/register-email-form.component`); + } + + protected importUnthemedComponent(): Promise<any> { + return import('./register-email-form.component'); + } + +} diff --git a/src/app/register-page/register-email/register-email.component.html b/src/app/register-page/register-email/register-email.component.html index 1829bb2914c..6a87a4e9e08 100644 --- a/src/app/register-page/register-email/register-email.component.html +++ b/src/app/register-page/register-email/register-email.component.html @@ -1,3 +1,3 @@ -<ds-register-email-form +<ds-themed-register-email-form [MESSAGE_PREFIX]="'register-page.registration'" [typeRequest]="typeRequest"> -</ds-register-email-form> +</ds-themed-register-email-form> 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 f3ae261ca7f..eba37fa4160 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 @@ -7,8 +7,8 @@ ngbDropdownToggle>{{ 'nav.login' | translate }}</a> <div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu [attr.aria-label]="'nav.login' | translate"> - <ds-log-in - [isStandalonePage]="false"></ds-log-in> + <ds-themed-log-in + [isStandalonePage]="false"></ds-themed-log-in> </div> </div> </li> diff --git a/src/app/shared/browse-by/shared-browse-by.module.ts b/src/app/shared/browse-by/shared-browse-by.module.ts index ae42576e9b9..4041f296c86 100644 --- a/src/app/shared/browse-by/shared-browse-by.module.ts +++ b/src/app/shared/browse-by/shared-browse-by.module.ts @@ -1,15 +1,21 @@ import { NgModule } from '@angular/core'; import { BrowseByComponent } from './browse-by.component'; +import { ThemedBrowseByComponent } from './themed-browse-by.component'; import { CommonModule } from '@angular/common'; import { SharedModule } from '../shared.module'; import { ResultsBackButtonModule } from '../results-back-button/results-back-button.module'; import { BrowseByRoutingModule } from '../../browse-by/browse-by-routing.module'; import { AccessControlRoutingModule } from '../../access-control/access-control-routing.module'; +const DECLARATIONS = [ + BrowseByComponent, + ThemedBrowseByComponent, +]; + @NgModule({ declarations: [ - BrowseByComponent, -], + ...DECLARATIONS, + ], imports: [ ResultsBackButtonModule, BrowseByRoutingModule, @@ -18,8 +24,7 @@ import { AccessControlRoutingModule } from '../../access-control/access-control- SharedModule, ], exports: [ - BrowseByComponent, - SharedModule, + ...DECLARATIONS, ] }) export class SharedBrowseByModule { } diff --git a/src/app/shared/browse-by/themed-browse-by.component.ts b/src/app/shared/browse-by/themed-browse-by.component.ts new file mode 100644 index 00000000000..eaa17ebf164 --- /dev/null +++ b/src/app/shared/browse-by/themed-browse-by.component.ts @@ -0,0 +1,76 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { ThemedComponent } from '../theme-support/themed.component'; +import { BrowseByComponent } from './browse-by.component'; +import { Observable } from 'rxjs'; +import { RemoteData } from '../../core/data/remote-data'; +import { PaginatedList } from '../../core/data/paginated-list.model'; +import { ListableObject } from '../object-collection/shared/listable-object.model'; +import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { SortOptions, SortDirection } from '../../core/cache/models/sort-options.model'; +import { StartsWithType } from '../starts-with/starts-with-decorator'; + +/** + * Themed wrapper for {@link BrowseByComponent} + */ +@Component({ + selector: 'ds-themed-browse-by', + styleUrls: [], + templateUrl: '../theme-support/themed.component.html', +}) +export class ThemedBrowseByComponent extends ThemedComponent<BrowseByComponent> { + + @Input() title: string; + + @Input() parentname: string; + + @Input() objects$: Observable<RemoteData<PaginatedList<ListableObject>>>; + + @Input() paginationConfig: PaginationComponentOptions; + + @Input() sortConfig: SortOptions; + + @Input() type: StartsWithType; + + @Input() startsWithOptions: number[]; + + @Input() showPaginator: boolean; + + @Input() hideGear: boolean; + + @Output() prev: EventEmitter<boolean> = new EventEmitter(); + + @Output() next: EventEmitter<boolean> = new EventEmitter(); + + @Output() pageSizeChange: EventEmitter<number> = new EventEmitter(); + + @Output() sortDirectionChange: EventEmitter<SortDirection> = new EventEmitter(); + + protected inAndOutputNames: (keyof BrowseByComponent & keyof this)[] = [ + 'title', + 'parentname', + 'objects$', + 'paginationConfig', + 'sortConfig', + 'type', + 'startsWithOptions', + 'showPaginator', + 'hideGear', + 'prev', + 'next', + 'pageSizeChange', + 'sortDirectionChange', + ]; + + protected getComponentName(): string { + return 'BrowseByComponent'; + } + + protected importThemedComponent(themeName: string): Promise<any> { + return import(`../../../themes/${themeName}/app/shared/browse-by/browse-by.component.ts`); + } + + protected importUnthemedComponent(): Promise<any> { + return import('./browse-by.component'); + } + +} diff --git a/src/app/shared/log-in/log-in.component.spec.ts b/src/app/shared/log-in/log-in.component.spec.ts index 57ed3e46946..e44aa1aa71e 100644 --- a/src/app/shared/log-in/log-in.component.spec.ts +++ b/src/app/shared/log-in/log-in.component.spec.ts @@ -21,6 +21,8 @@ import { RouterTestingModule } from '@angular/router/testing'; import { HardRedirectService } from '../../core/services/hard-redirect.service'; import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; import { of } from 'rxjs'; +import { ThemeService } from '../theme-support/theme.service'; +import { getMockThemeService } from '../mocks/theme-service.mock'; describe('LogInComponent', () => { @@ -75,6 +77,7 @@ describe('LogInComponent', () => { { provide: HardRedirectService, useValue: hardRedirectService }, { provide: AuthorizationDataService, useValue: authorizationService }, provideMockStore({ initialState }), + { provide: ThemeService, useValue: getMockThemeService() }, LogInComponent ], schemas: [ @@ -91,7 +94,7 @@ describe('LogInComponent', () => { // synchronous beforeEach beforeEach(() => { - const html = `<ds-log-in [isStandalonePage]="isStandalonePage"> </ds-log-in>`; + const html = `<ds-themed-log-in [isStandalonePage]="isStandalonePage"> </ds-themed-log-in>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; testComp = testFixture.componentInstance; diff --git a/src/app/shared/log-in/themed-log-in.component.ts b/src/app/shared/log-in/themed-log-in.component.ts new file mode 100644 index 00000000000..cc182746462 --- /dev/null +++ b/src/app/shared/log-in/themed-log-in.component.ts @@ -0,0 +1,33 @@ +import { Component, Input } from '@angular/core'; +import { ThemedComponent } from '../theme-support/themed.component'; +import { LogInComponent } from './log-in.component'; + +/** + * Themed wrapper for {@link LogInComponent} + */ +@Component({ + selector: 'ds-themed-log-in', + styleUrls: [], + templateUrl: './../theme-support/themed.component.html' +}) +export class ThemedLogInComponent extends ThemedComponent<LogInComponent> { + + @Input() isStandalonePage: boolean; + + protected inAndOutputNames: (keyof LogInComponent & keyof this)[] = [ + 'isStandalonePage', + ]; + + protected getComponentName(): string { + return 'LogInComponent'; + } + + protected importThemedComponent(themeName: string): Promise<any> { + return import(`../../../themes/${themeName}/app/shared/log-in/log-in.component`); + } + + protected importUnthemedComponent(): Promise<any> { + return import('./log-in.component'); + } + +} diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-filter.component.html index 421d1ede2c0..25c218166ef 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.html @@ -6,7 +6,7 @@ [attr.aria-label]="(((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate) + ' ' + (('search.filters.filter.' + filter.name + '.head') | translate | lowercase)" [attr.data-test]="'filter-toggle' | dsBrowserOnly" > - <h4 class="d-inline-block mb-0"> + <h4 class="d-inline-block text-left mt-auto mb-auto"> {{'search.filters.filter.' + filter.name + '.head'| translate}} </h4> <span class="filter-toggle flex-grow-1 fas p-auto" diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.scss b/src/app/shared/search/search-filters/search-filter/search-filter.component.scss index 7e2631b55f7..6a13d630ebc 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.scss +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.scss @@ -17,7 +17,6 @@ line-height: var(--bs-line-height-base); text-align: right; position: relative; - top: -0.125rem; // Fix weird outline shape in Chrome } > button { diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 1345ac6607e..dc6772aba76 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -192,6 +192,7 @@ import { import { LogInContainerComponent } from './log-in/container/log-in-container.component'; import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component'; import { LogInComponent } from './log-in/log-in.component'; +import { ThemedLogInComponent } from './log-in/themed-log-in.component'; import { MissingTranslationHelper } from './translate/missing-translation.helper'; import { FileValidator } from './utils/require-file.validator'; import { FileValueAccessorDirective } from './utils/file-value-accessor.directive'; @@ -339,6 +340,7 @@ const COMPONENTS = [ LoadingComponent, ThemedLoadingComponent, LogInComponent, + ThemedLogInComponent, LogOutComponent, ObjectListComponent, ThemedObjectListComponent, diff --git a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html index 0796da5a64a..61e420b23a3 100644 --- a/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html +++ b/src/app/submission/sections/cc-license/submission-section-cc-licenses.component.html @@ -134,6 +134,7 @@ <h5> <div class="m-2"> <div (click)="setAccepted(!accepted)"> <input type="checkbox" + class="mr-2" title="accepted" [checked]="accepted"> <span> {{ 'submission.sections.ccLicense.confirmation' | translate }}</span> diff --git a/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.html b/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.scss b/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.ts b/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.ts new file mode 100644 index 00000000000..3d3f69409f3 --- /dev/null +++ b/src/themes/custom/app/entity-groups/research-entities/item-pages/person/person.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../../../app/core/shared/view-mode.model'; +import { + listableObjectComponent +} from '../../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { + PersonComponent as BaseComponent +} from '../../../../../../../app/entity-groups/research-entities/item-pages/person/person.component'; +import { Context } from '../../../../../../../app/core/shared/context.model'; + +@listableObjectComponent('Person', ViewMode.StandalonePage, Context.Any, 'custom') +@Component({ + selector: 'ds-person', + // styleUrls: ['./person.component.scss'], + styleUrls: ['../../../../../../../app/entity-groups/research-entities/item-pages/person/person.component.scss'], + // templateUrl: './person.component.html', + templateUrl: '../../../../../../../app/entity-groups/research-entities/item-pages/person/person.component.html', +}) +export class PersonComponent extends BaseComponent { +} diff --git a/src/themes/custom/app/login-page/login-page.component.html b/src/themes/custom/app/login-page/login-page.component.html index 84059877f4b..1a83892c241 100644 --- a/src/themes/custom/app/login-page/login-page.component.html +++ b/src/themes/custom/app/login-page/login-page.component.html @@ -3,8 +3,8 @@ <div> <img class="mb-4 login-logo" src="assets/images/dspace-logo.png"> <h1 class="h3 mb-0 font-weight-normal">{{"login.form.header" | translate}}</h1> - <ds-log-in - [isStandalonePage]="true"></ds-log-in> + <ds-themed-log-in + [isStandalonePage]="true"></ds-themed-log-in> </div> </div> </div> diff --git a/src/themes/custom/app/register-email-form/register-email-form.component.html b/src/themes/custom/app/register-email-form/register-email-form.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/register-email-form/register-email-form.component.ts b/src/themes/custom/app/register-email-form/register-email-form.component.ts new file mode 100644 index 00000000000..8489a1d89c6 --- /dev/null +++ b/src/themes/custom/app/register-email-form/register-email-form.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { + RegisterEmailFormComponent as BaseComponent +} from '../../../../app/register-email-form/register-email-form.component'; + +@Component({ + selector: 'ds-register-email-form', + // templateUrl: './register-email-form.component.html', + templateUrl: '../../../../app/register-email-form/register-email-form.component.html', +}) +export class RegisterEmailFormComponent extends BaseComponent { +} diff --git a/src/themes/custom/app/shared/browse-by/browse-by.component.html b/src/themes/custom/app/shared/browse-by/browse-by.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/browse-by/browse-by.component.scss b/src/themes/custom/app/shared/browse-by/browse-by.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/browse-by/browse-by.component.ts b/src/themes/custom/app/shared/browse-by/browse-by.component.ts new file mode 100644 index 00000000000..81435b9b372 --- /dev/null +++ b/src/themes/custom/app/shared/browse-by/browse-by.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { fadeIn, fadeInOut } from '../../../../../app/shared/animations/fade'; +import { BrowseByComponent as BaseComponent } from '../../../../../app/shared/browse-by/browse-by.component'; + +@Component({ + selector: 'ds-browse-by', + // styleUrls: ['./browse-by.component.scss'], + styleUrls: ['../../../../../app/shared/browse-by/browse-by.component.scss'], + // templateUrl: './browse-by.component.html', + templateUrl: '../../../../../app/shared/browse-by/browse-by.component.html', + animations: [ + fadeIn, + fadeInOut, + ], +}) +export class BrowseByComponent extends BaseComponent { +} diff --git a/src/themes/custom/app/shared/log-in/log-in.component.html b/src/themes/custom/app/shared/log-in/log-in.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/log-in/log-in.component.scss b/src/themes/custom/app/shared/log-in/log-in.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/log-in/log-in.component.ts b/src/themes/custom/app/shared/log-in/log-in.component.ts new file mode 100644 index 00000000000..5d1df59699a --- /dev/null +++ b/src/themes/custom/app/shared/log-in/log-in.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { LogInComponent as BaseComponent } from '../../../../../app/shared/log-in/log-in.component'; + +@Component({ + selector: 'ds-log-in', + // templateUrl: './log-in.component.html', + templateUrl: '../../../../../app/shared/log-in/log-in.component.html', + // styleUrls: ['./log-in.component.scss'], + styleUrls: ['../../../../../app/shared/log-in/log-in.component.scss'], +}) +export class LogInComponent extends BaseComponent { +} diff --git a/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html b/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.scss b/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts b/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts new file mode 100644 index 00000000000..0b1fd94e6a7 --- /dev/null +++ b/src/themes/custom/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { BrowseEntry } from '../../../../../../app/core/shared/browse-entry.model'; +import { ViewMode } from '../../../../../../app/core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../../../app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../../../app/core/shared/context.model'; +import { + BrowseEntryListElementComponent as BaseComponent +} from '../../../../../../app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component'; + +@Component({ + selector: 'ds-browse-entry-list-element', + // styleUrls: ['./browse-entry-list-element.component.scss'], + styleUrls: ['../../../../../../app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.scss'], + // templateUrl: './browse-entry-list-element.component.html', + templateUrl: '../../../../../../app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html', +}) +@listableObjectComponent(BrowseEntry, ViewMode.ListElement, Context.Any, 'custom') +export class BrowseEntryListElementComponent extends BaseComponent { +} diff --git a/src/themes/custom/eager-theme.module.ts b/src/themes/custom/eager-theme.module.ts index a181487ea7a..31047e239ac 100644 --- a/src/themes/custom/eager-theme.module.ts +++ b/src/themes/custom/eager-theme.module.ts @@ -54,6 +54,9 @@ import { ItemSearchResultListElementComponent } from './app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TopLevelCommunityListComponent } from './app/home-page/top-level-community-list/top-level-community-list.component'; +import { LogInComponent } from './app/shared/log-in/log-in.component'; +import { BrowseEntryListElementComponent } from './app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component'; +import { PersonComponent } from './app/entity-groups/research-entities/item-pages/person/person.component'; import { LangSwitchComponent } from './app/shared/lang-switch/lang-switch.component'; @@ -65,6 +68,7 @@ const ENTRY_COMPONENTS = [ JournalComponent, JournalIssueComponent, JournalVolumeComponent, + PersonComponent, PublicationComponent, UntypedItemComponent, CommunityListElementComponent, @@ -76,6 +80,7 @@ const ENTRY_COMPONENTS = [ PublicationSidebarSearchListElementComponent, ItemSearchResultListElementComponent, TopLevelCommunityListComponent, + BrowseEntryListElementComponent, ]; const DECLARATIONS = [ @@ -92,6 +97,7 @@ const DECLARATIONS = [ EditCollectionSelectorComponent, EditCommunitySelectorComponent, EditItemSelectorComponent, + LogInComponent, LangSwitchComponent, ]; diff --git a/src/themes/custom/lazy-theme.module.ts b/src/themes/custom/lazy-theme.module.ts index 937e174b7f8..73400e78806 100644 --- a/src/themes/custom/lazy-theme.module.ts +++ b/src/themes/custom/lazy-theme.module.ts @@ -157,6 +157,8 @@ import { EditBitstreamPageComponent } from './app/bitstream-page/edit-bitstream- 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'; +import { BrowseByComponent } from './app/shared/browse-by/browse-by.component'; +import { RegisterEmailFormComponent } from './app/register-email-form/register-email-form.component'; const DECLARATIONS = [ FileSectionComponent, @@ -241,6 +243,8 @@ const DECLARATIONS = [ ItemStatusComponent, EditBitstreamPageComponent, UserMenuComponent, + BrowseByComponent, + RegisterEmailFormComponent, ]; @NgModule({ diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index b3d4fdb2aa5..b4b7a02e502 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -53,9 +53,10 @@ a.navbar-brand img { .navbar-nav { ::ng-deep a.nav-link { color: var(--ds-navbar-link-color); - } - ::ng-deep a.nav-link:hover { - color: var(--ds-navbar-link-color-hover); + + &:hover, &:focus { + color: var(--ds-navbar-link-color-hover); + } } } From 543b4ad576b740b27ecf7b3bfc607f021bde1494 Mon Sep 17 00:00:00 2001 From: Alisa Ismailati <alisa.ismailati@atis.al> Date: Thu, 12 Oct 2023 16:12:32 +0000 Subject: [PATCH 166/282] Merged in DSC-106 (pull request #643) [DSC-106] Date input usable via keyboard using tab Approved-by: Vincenzo Mecca --- .../date-picker/date-picker.component.spec.ts | 109 +++++++++++++++++- .../date-picker/date-picker.component.ts | 74 +++++++++++- 2 files changed, 178 insertions(+), 5 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts index ffc36008c69..8ee90fb230b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts @@ -1,7 +1,7 @@ // Load the implementations that should be tested -import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { ComponentFixture, inject, TestBed, waitForAsync, } from '@angular/core/testing'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, Renderer2 } from '@angular/core'; +import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync, } from '@angular/core/testing'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; @@ -13,6 +13,7 @@ import { mockDynamicFormLayoutService, mockDynamicFormValidationService } from '../../../../../testing/dynamic-form-mock-services'; +import { By } from '@angular/platform-browser'; export const DATE_TEST_GROUP = new UntypedFormGroup({ @@ -39,6 +40,11 @@ describe('DsDatePickerComponent test suite', () => { let dateFixture: ComponentFixture<DsDatePickerComponent>; let html; + const renderer2: Renderer2 = { + selectRootElement: jasmine.createSpy('selectRootElement'), + querySelector: jasmine.createSpy('querySelector'), + } as unknown as Renderer2; + // waitForAsync beforeEach beforeEach(waitForAsync(() => { @@ -54,7 +60,8 @@ describe('DsDatePickerComponent test suite', () => { ChangeDetectorRef, DsDatePickerComponent, { provide: DynamicFormLayoutService, useValue: mockDynamicFormLayoutService }, - { provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService } + { provide: DynamicFormValidationService, useValue: mockDynamicFormValidationService }, + { provide: Renderer2, useValue: renderer2 }, ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); @@ -233,6 +240,102 @@ describe('DsDatePickerComponent test suite', () => { expect(dateComp.disabledMonth).toBeFalsy(); expect(dateComp.disabledDay).toBeFalsy(); }); + + it('should move focus on month field when on year field and tab pressed', fakeAsync(() => { + const event = { + field: 'day', + value: null + }; + const event1 = { + field: 'month', + value: null + }; + dateComp.onChange(event); + dateComp.onChange(event1); + + const yearElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_year`)); + const monthElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_month`)); + + yearElement.nativeElement.focus(); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(yearElement.nativeElement); + + dateFixture.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab' })); + dateFixture.detectChanges(); + + tick(200); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(monthElement.nativeElement); + })); + + it('should move focus on day field when on month field and tab pressed', fakeAsync(() => { + const event = { + field: 'day', + value: null + }; + dateComp.onChange(event); + + const monthElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_month`)); + const dayElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_day`)); + + monthElement.nativeElement.focus(); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(monthElement.nativeElement); + + dateFixture.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'tab' })); + dateFixture.detectChanges(); + + tick(200); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(dayElement.nativeElement); + })); + + it('should move focus on month field when on day field and shift tab pressed', fakeAsync(() => { + const event = { + field: 'day', + value: null + }; + dateComp.onChange(event); + + const monthElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_month`)); + const dayElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_day`)); + + dayElement.nativeElement.focus(); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(dayElement.nativeElement); + + dateFixture.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'shift.tab' })); + dateFixture.detectChanges(); + + tick(200); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(monthElement.nativeElement); + })); + + it('should move focus on year field when on month field and shift tab pressed', fakeAsync(() => { + const yearElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_year`)); + const monthElement = dateFixture.debugElement.query(By.css(`#${dateComp.model.id}_month`)); + + monthElement.nativeElement.focus(); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(monthElement.nativeElement); + + dateFixture.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'shift.tab' })); + dateFixture.detectChanges(); + + tick(200); + dateFixture.detectChanges(); + + expect(document.activeElement).toBe(yearElement.nativeElement); + })); + }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts index 8d5ce5b48ee..717aa88d44d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts @@ -1,5 +1,5 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; +import { Component, EventEmitter, HostListener, Inject, Input, OnInit, Output, Renderer2 } from '@angular/core'; import { DynamicDsDatePickerModel } from './date-picker.model'; import { hasValue } from '../../../../../empty.util'; import { @@ -7,6 +7,11 @@ import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; +import { DOCUMENT } from '@angular/common'; +import isEqual from 'lodash/isEqual'; + + +export type DatePickerFieldType = '_year' | '_month' | '_day'; export const DS_DATE_PICKER_SEPARATOR = '-'; @@ -50,8 +55,12 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement disabledMonth = true; disabledDay = true; + private readonly fields: DatePickerFieldType[] = ['_year', '_month', '_day']; + constructor(protected layoutService: DynamicFormLayoutService, - protected validationService: DynamicFormValidationService + protected validationService: DynamicFormValidationService, + private renderer: Renderer2, + @Inject(DOCUMENT) private _document: Document ) { super(layoutService, validationService); } @@ -166,6 +175,67 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement this.change.emit(value); } + /** + * Listen to keydown Tab event. + * Get the active element and blur it, in order to focus the next input field. + */ + @HostListener('keydown.tab', ['$event']) + onTabKeydown(event: KeyboardEvent) { + event.preventDefault(); + const activeElement: Element = this._document.activeElement; + (activeElement as any).blur(); + const index = this.selectedFieldIndex(activeElement); + if (index < 0) { + return; + } + let fieldToFocusOn = index + 1; + if (fieldToFocusOn < this.fields.length) { + this.focusInput(this.fields[fieldToFocusOn]); + } + } + + @HostListener('keydown.shift.tab', ['$event']) + onShiftTabKeyDown(event: KeyboardEvent) { + event.preventDefault(); + const activeElement: Element = this._document.activeElement; + (activeElement as any).blur(); + const index = this.selectedFieldIndex(activeElement); + let fieldToFocusOn = index - 1; + if (fieldToFocusOn >= 0) { + this.focusInput(this.fields[fieldToFocusOn]); + } + } + + private selectedFieldIndex(activeElement: Element): number { + return this.fields.findIndex(field => isEqual(activeElement.id, this.model.id.concat(field))); + } + + /** + * Focus the input field for the given type + * based on the model id. + * Used to focus the next input field + * in case of a disabled field. + * @param type DatePickerFieldType + */ + focusInput(type: DatePickerFieldType) { + const field = this._document.getElementById(this.model.id.concat(type)); + if (field) { + + if (hasValue(this.year) && isEqual(type, '_year')) { + this.disabledMonth = true; + this.disabledDay = true; + } + if (hasValue(this.year) && isEqual(type, '_month')) { + this.disabledMonth = false; + } else if (hasValue(this.month) && isEqual(type, '_day')) { + this.disabledDay = false; + } + setTimeout(() => { + this.renderer.selectRootElement(field).focus(); + }, 100); + } + } + onFocus(event) { this.focus.emit(event); } From c412c1fa13b30ac5140259ff2542a60e8646382e Mon Sep 17 00:00:00 2001 From: Alisa Ismailati <alisa.ismailati@4science.com> Date: Mon, 30 Oct 2023 16:14:13 +0100 Subject: [PATCH 167/282] [DURACOM-194] fixed year input value on input type date --- .../models/date-picker/date-picker.component.ts | 5 ++--- src/app/shared/form/number-picker/number-picker.component.ts | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts index 717aa88d44d..404e8514933 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts @@ -89,9 +89,8 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement } } - this.maxYear = this.initialYear + 100; - - } + this.maxYear = now.getUTCFullYear() + 100; + } onBlur(event) { this.blur.emit(); diff --git a/src/app/shared/form/number-picker/number-picker.component.ts b/src/app/shared/form/number-picker/number-picker.component.ts index 82240c41d11..40562dd61c0 100644 --- a/src/app/shared/form/number-picker/number-picker.component.ts +++ b/src/app/shared/form/number-picker/number-picker.component.ts @@ -103,13 +103,12 @@ export class NumberPickerComponent implements OnInit, ControlValueAccessor { if (i >= this.min && i <= this.max) { this.value = i; - this.emitChange(); } else if (event.target.value === null || event.target.value === '') { this.value = null; - this.emitChange(); } else { this.value = undefined; } + this.emitChange(); } catch (e) { this.value = undefined; } From 930a381e4a6beda611a87510e5b76a94d1c4c9af Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Tue, 11 Jul 2023 16:05:33 +0200 Subject: [PATCH 168/282] [DURACOM-177] gap-* classes --- src/styles/_global-styles.scss | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index 00fcb0f86f1..81d4fe0787a 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -268,6 +268,30 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { vertical-align: middle; } +/* Flexbox gap */ + +.gap-0 { gap: 0; } +.gap-1 { gap: calc(#{$spacer} * .25); } +.gap-2 { gap: calc(#{$spacer} * .5); } +.gap-3 { gap: #{$spacer}; } +.gap-4 { gap: calc(#{$spacer} * 1.5); } +.gap-5 { gap: calc(#{$spacer} * 3); } + +.gapx-0 { column-gap: 0; } +.gapx-1 { column-gap: calc(#{$spacer} * .25); } +.gapx-2 { column-gap: calc(#{$spacer} * .5); } +.gapx-3 { column-gap: #{$spacer}; } +.gapx-4 { column-gap: calc(#{$spacer} * 1.5); } +.gapx-5 { column-gap: calc(#{$spacer} * 3); } + +.gapy-0 { row-gap: 0; } +.gapy-1 { row-gap: calc(#{$spacer} * .25); } +.gapy-2 { row-gap: calc(#{$spacer} * .5); } +.gapy-3 { row-gap: #{$spacer}; } +.gapy-4 { row-gap: calc(#{$spacer} * 1.5); } +.gapy-5 { row-gap: calc(#{$spacer} * 3); } + + .pt-0\.5 { padding-top: 0.125rem !important; } From 3228c457a33710354c85b92efad5f6945af66e58 Mon Sep 17 00:00:00 2001 From: William Welling <wwelling@tamu.edu> Date: Wed, 1 Nov 2023 14:39:08 -0500 Subject: [PATCH 169/282] Add UI nameSpace context path to Mirador viewer path --- src/app/item-page/mirador-viewer/mirador-viewer.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/mirador-viewer/mirador-viewer.component.ts b/src/app/item-page/mirador-viewer/mirador-viewer.component.ts index fee80462721..15ebfc61bc6 100644 --- a/src/app/item-page/mirador-viewer/mirador-viewer.component.ts +++ b/src/app/item-page/mirador-viewer/mirador-viewer.component.ts @@ -70,7 +70,8 @@ export class MiradorViewerComponent implements OnInit { const manifestApiEndpoint = encodeURIComponent(environment.rest.baseUrl + '/iiif/' + this.object.id + '/manifest'); // The Express path to Mirador viewer. - let viewerPath = '/iiif/mirador/index.html?manifest=' + manifestApiEndpoint; + let viewerPath = `${environment.ui.nameSpace}${environment.ui.nameSpace.length > 1 ? '/' : ''}` + + `iiif/mirador/index.html?manifest=${manifestApiEndpoint}`; if (this.searchable) { // Tell the viewer add search to menu. viewerPath += '&searchable=' + this.searchable; From f992ff66713ea820e47cb44a28b5fd612d64fae2 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio <giuseppe.digilio@4science.com> Date: Thu, 2 Nov 2023 16:46:33 +0100 Subject: [PATCH 170/282] [DURACOM-197] Fix cache issue when depositing a submission --- src/app/submission/objects/submission-objects.effects.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index 98646009d5b..2c19224336d 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -210,7 +210,7 @@ export class SubmissionObjectEffects { action.payload.submissionId, 'sections') as Observable<SubmissionObject[]>; } else { - response$ = this.submissionObjectService.findById(action.payload.submissionId, false, true).pipe( + response$ = this.submissionObjectService.findById(action.payload.submissionId, false, true, followLink('item'), followLink('collection')).pipe( getFirstSucceededRemoteDataPayload(), map((submissionObject: SubmissionObject) => [submissionObject]) ); From a35629536e70f8d4b691fa95fd0b8342a8d717a1 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Mon, 6 Nov 2023 11:39:48 +0100 Subject: [PATCH 171/282] [DURACOM-177] Use gap-* classes on navbar buttons --- 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 | 2 +- src/themes/dspace/app/navbar/navbar.component.scss | 6 ------ 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/themes/dspace/app/header/header.component.html b/src/themes/dspace/app/header/header.component.html index 4b0046bc834..205abfd463a 100644 --- a/src/themes/dspace/app/header/header.component.html +++ b/src/themes/dspace/app/header/header.component.html @@ -5,7 +5,7 @@ <img src="assets/images/dspace-logo.svg" [attr.alt]="'menu.header.image.logo' | translate"/> </a> </div> - <div class="navbar-buttons d-flex flex-grow-1 ml-auto justify-content-end align-items-center"> + <div class="navbar-buttons d-flex flex-grow-1 ml-auto justify-content-end align-items-center gapx-1"> <ds-themed-search-navbar></ds-themed-search-navbar> <ds-themed-lang-switch></ds-themed-lang-switch> <ds-context-help-toggle></ds-context-help-toggle> diff --git a/src/themes/dspace/app/header/header.component.scss b/src/themes/dspace/app/header/header.component.scss index 14c46a2316a..2fc857826f9 100644 --- a/src/themes/dspace/app/header/header.component.scss +++ b/src/themes/dspace/app/header/header.component.scss @@ -24,9 +24,3 @@ color: var(--ds-header-icon-color-hover); } } - -.navbar-buttons { - display: flex; - gap: calc(var(--bs-spacer) / 3); - align-items: center; -} diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index c14671cf683..f2e231d46ce 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -15,7 +15,7 @@ </li> </ul> </div> - <div class="navbar-buttons"> + <div class="navbar-buttons d-flex align-items-center gapx-1"> <ds-themed-search-navbar class="navbar-collapsed"></ds-themed-search-navbar> <ds-themed-lang-switch class="navbar-collapsed"></ds-themed-lang-switch> <ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle> diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index b4b7a02e502..300d1f419ad 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -59,9 +59,3 @@ a.navbar-brand img { } } } - -.navbar-buttons { - display: flex; - gap: calc(var(--bs-spacer) / 3); - align-items: center; -} From 7dcaae846547a48bf1cbe1fe4241ac661e20d71f Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Mon, 6 Nov 2023 10:25:08 -0600 Subject: [PATCH 172/282] Ensure e2e tests run in production mode --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f8644477900..3e23de10151 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "test:headless": "ng test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage", "lint": "ng lint", "lint-fix": "ng lint --fix=true", - "e2e": "ng e2e", + "e2e": "cross-env NODE_ENV=production ng e2e", "clean:dev:config": "rimraf src/assets/config.json", "clean:coverage": "rimraf coverage", "clean:dist": "rimraf dist", From 0dcf6cb8855cc5c74f781fd7490f2daaeea29092 Mon Sep 17 00:00:00 2001 From: Jens Vannerum <jens.vannerum@atmire.com> Date: Wed, 8 Nov 2023 10:25:27 +0100 Subject: [PATCH 173/282] 108055: fix issue 8686: unable to enter freetext values in the submission form for vocabulary --- .../vocabulary-treeview.component.html | 3 +++ .../vocabulary-treeview/vocabulary-treeview.component.ts | 9 +++++++++ src/assets/i18n/en.json5 | 2 ++ 3 files changed, 14 insertions(+) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index 3b858faac45..db3dc31948f 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -10,6 +10,9 @@ <button class="btn btn-outline-secondary" type="button" (click)="reset()"> {{'vocabulary-treeview.search.form.reset' | translate}} </button> + <button class="btn btn-outline-primary" type="button" (click)="add()" [disabled]="this.vocabularyOptions.closed"> + {{'vocabulary-treeview.search.form.add' | translate}} + </button> </div> </div> </div> diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts index 804ae634913..d5a5dee1f5e 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts @@ -293,6 +293,15 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges } } + add() { + const userVocabularyEntry = { + value: this.searchText, + display: this.searchText, + } as VocabularyEntryDetail; + this.select.emit(userVocabularyEntry); + } + + /** * Unsubscribe from all subscriptions */ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 3b3578fac5d..741ff0ffc9c 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -5240,4 +5240,6 @@ "access-control-option-end-date-note": "Select the date until which the related access condition is applied", + "vocabulary-treeview.search.form.add": "Add", + } From aac58e612d7fb01f87dc7a6a46b92c9c4c2fe685 Mon Sep 17 00:00:00 2001 From: Jens Vannerum <jens.vannerum@atmire.com> Date: Wed, 8 Nov 2023 12:00:46 +0100 Subject: [PATCH 174/282] 108055: add user input to tag list --- .../models/tag/dynamic-tag.component.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts index 4abb68a53be..7805dad1f32 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts @@ -89,6 +89,18 @@ export class DsDynamicTagComponent extends DsDynamicVocabularyComponent implemen } }), map((list: PaginatedList<VocabularyEntry>) => list.page), + // Add user input as last item of the list + map((list: VocabularyEntry[]) => { + if (list && list.length > 0) { + if (isNotEmpty(this.currentValue)) { + let vocEntry = new VocabularyEntry(); + vocEntry.display = this.currentValue; + vocEntry.value = this.currentValue; + list.push(vocEntry); + } + } + return list; + }), tap(() => this.changeSearchingStatus(false)), merge(this.hideSearchingWhenUnsubscribed)); From 1bbc053c0038de7ca37c43e92af6bf6fb3234b78 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 8 Nov 2023 14:57:54 +0100 Subject: [PATCH 175/282] 107902: Created test case for 2f26e686cc --- src/app/shared/menu/menu.component.spec.ts | 134 +++++++++++++++++++-- src/app/shared/menu/menu.component.ts | 2 +- 2 files changed, 122 insertions(+), 14 deletions(-) diff --git a/src/app/shared/menu/menu.component.spec.ts b/src/app/shared/menu/menu.component.spec.ts index f0660fab4a2..e6566d97c3c 100644 --- a/src/app/shared/menu/menu.component.spec.ts +++ b/src/app/shared/menu/menu.component.spec.ts @@ -1,12 +1,12 @@ +// eslint-disable-next-line max-classes-per-file import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { TranslateModule } from '@ngx-translate/core'; -import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA, Component } from '@angular/core'; import { MenuService } from './menu.service'; import { MenuComponent } from './menu.component'; -import { MenuServiceStub } from '../testing/menu-service.stub'; -import { of as observableOf } from 'rxjs'; -import { Router, ActivatedRoute } from '@angular/router'; +import { of as observableOf, BehaviorSubject } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MenuSection } from './menu-section.model'; import { MenuID } from './menu-id.model'; @@ -15,14 +15,39 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/ import { createSuccessfulRemoteDataObject } from '../remote-data.utils'; import { ThemeService } from '../theme-support/theme.service'; import { getMockThemeService } from '../mocks/theme-service.mock'; +import { MenuItemType } from './menu-item-type.model'; +import { LinkMenuItemModel } from './menu-item/models/link.model'; +import { provideMockStore, MockStore } from '@ngrx/store/testing'; +import { StoreModule, Store } from '@ngrx/store'; +import { authReducer } from '../../core/auth/auth.reducer'; +import { storeModuleConfig, AppState } from '../../app.reducer'; +import { rendersSectionForMenu } from './menu-section.decorator'; + +const mockMenuID = 'mock-menuID' as MenuID; + +@Component({ + // eslint-disable-next-line @angular-eslint/component-selector + selector: '', + template: '', +}) +@rendersSectionForMenu(mockMenuID, true) +class TestExpandableMenuComponent { +} + +@Component({ + // eslint-disable-next-line @angular-eslint/component-selector + selector: '', + template: '', +}) +@rendersSectionForMenu(mockMenuID, false) +class TestMenuComponent { +} describe('MenuComponent', () => { let comp: MenuComponent; let fixture: ComponentFixture<MenuComponent>; let menuService: MenuService; - let router: any; - - const mockMenuID = 'mock-menuID' as MenuID; + let store: MockStore; const mockStatisticSection = { 'id': 'statistics_site', 'active': true, 'visible': true, 'index': 2, 'type': 'statistics', 'model': { 'type': 1, 'text': 'menu.section.statistics', 'link': 'statistics' } }; @@ -48,21 +73,55 @@ describe('MenuComponent', () => { children: [] }; + const initialState = { + menus: { + [mockMenuID]: { + collapsed: true, + id: mockMenuID, + previewCollapsed: true, + sectionToSubsectionIndex: { + section1: [], + }, + sections: { + section1: { + id: 'section1', + active: false, + visible: true, + model: { + type: MenuItemType.LINK, + text: 'test', + link: '/test', + } as LinkMenuItemModel, + }, + }, + visible: true, + }, + }, + }; + beforeEach(waitForAsync(() => { authorizationService = jasmine.createSpyObj('authorizationService', { isAuthorized: observableOf(false) }); - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule], + void TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot(), + NoopAnimationsModule, + RouterTestingModule, + StoreModule.forRoot(authReducer, storeModuleConfig), + ], declarations: [MenuComponent], providers: [ Injector, { provide: ThemeService, useValue: getMockThemeService() }, - { provide: MenuService, useClass: MenuServiceStub }, + MenuService, + provideMockStore({ initialState }), { provide: AuthorizationDataService, useValue: authorizationService }, { provide: ActivatedRoute, useValue: routeStub }, + TestExpandableMenuComponent, + TestMenuComponent, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(MenuComponent, { @@ -74,13 +133,62 @@ describe('MenuComponent', () => { fixture = TestBed.createComponent(MenuComponent); comp = fixture.componentInstance; // SearchPageComponent test instance comp.menuID = mockMenuID; - menuService = (comp as any).menuService; - router = TestBed.inject(Router); + menuService = TestBed.inject(MenuService); + store = TestBed.inject(Store) as MockStore<AppState>; spyOn(comp as any, 'getSectionDataInjector').and.returnValue(MenuSection); - spyOn(comp as any, 'getSectionComponent').and.returnValue(observableOf({})); fixture.detectChanges(); }); + describe('ngOnInit', () => { + it('should trigger the section observable again when a new sub section has been added', () => { + spyOn(comp.sectionMap$, 'next').and.callThrough(); + const hasSubSections = new BehaviorSubject(false); + spyOn(menuService, 'hasSubSections').and.returnValue(hasSubSections.asObservable()); + spyOn(store, 'dispatch').and.callThrough(); + + store.setState({ + menus: { + [mockMenuID]: { + collapsed: true, + id: mockMenuID, + previewCollapsed: true, + sectionToSubsectionIndex: { + section1: ['test'], + }, + sections: { + section1: { + id: 'section1', + active: false, + visible: true, + model: { + type: MenuItemType.LINK, + text: 'test', + link: '/test', + } as LinkMenuItemModel, + }, + test: { + id: 'test', + parentID: 'section1', + active: false, + visible: true, + model: { + type: MenuItemType.LINK, + text: 'test', + link: '/test', + } as LinkMenuItemModel, + } + }, + visible: true, + }, + }, + }); + expect(menuService.hasSubSections).toHaveBeenCalled(); + hasSubSections.next(true); + + expect(comp.sectionMap$.next).toHaveBeenCalled(); + }); + }); + describe('toggle', () => { beforeEach(() => { spyOn(menuService, 'toggleMenu'); diff --git a/src/app/shared/menu/menu.component.ts b/src/app/shared/menu/menu.component.ts index 805f5888ead..7b1394ddd2e 100644 --- a/src/app/shared/menu/menu.component.ts +++ b/src/app/shared/menu/menu.component.ts @@ -102,7 +102,7 @@ export class MenuComponent implements OnInit, OnDestroy { switchMap((section: MenuSection) => this.getSectionComponent(section).pipe( map((component: GenericConstructor<MenuSectionComponent>) => ({ section, component })) )), - distinctUntilChanged((x, y) => x.section.id === y.section.id) + distinctUntilChanged((x, y) => x.section.id === y.section.id && x.component.prototype === y.component.prototype), ).subscribe(({ section, component }) => { const nextMap = this.sectionMap$.getValue(); nextMap.set(section.id, { From 72cda4173124c2d2b3125e4cfed106338dc70ad9 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 8 Nov 2023 10:08:49 -0600 Subject: [PATCH 176/282] Specify user agent to avoid being detected as a "bot" by backend --- cypress/support/commands.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index c70c4e37e12..92f0b1aeeb6 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -177,6 +177,8 @@ function generateViewEvent(uuid: string, dsoType: string): void { [XSRF_REQUEST_HEADER] : csrfToken, // use a known public IP address to avoid being seen as a "bot" 'X-Forwarded-For': '1.1.1.1', + // Use a user-agent of a Firefox browser on Windows. This again avoids being seen as a "bot" + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0', }, //form: true, // indicates the body should be form urlencoded body: { targetId: uuid, targetType: dsoType }, From c4205163f9c8a7ca97466f6f78d2de51bf259e5d Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 8 Nov 2023 23:43:17 +0100 Subject: [PATCH 177/282] Added skip to main content button --- .../feedback-form/feedback-form.component.html | 2 +- src/app/root/root.component.html | 6 +++++- src/app/root/root.component.scss | 16 ++++++++++++++++ src/app/root/root.component.ts | 8 ++++++++ src/assets/i18n/en.json5 | 2 ++ src/styles/_global-styles.scss | 2 +- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.html b/src/app/info/feedback/feedback-form/feedback-form.component.html index 02745f2580d..a3bab3a6a38 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.html +++ b/src/app/info/feedback/feedback-form/feedback-form.component.html @@ -1,5 +1,5 @@ <div class="row row-offcanvas row-offcanvas-right"> - <div class="col-xs-12 col-sm-12 col-md-9 main-content"> + <div class="col-xs-12 col-sm-12 col-md-9"> <form class="primary" [formGroup]="feedbackForm" (ngSubmit)="createFeedback()"> <h2>{{ 'info.feedback.head' | translate }}</h2> <p>{{ 'info.feedback.info' | translate }}</p> diff --git a/src/app/root/root.component.html b/src/app/root/root.component.html index bf49e507c0b..39640ffbd49 100644 --- a/src/app/root/root.component.html +++ b/src/app/root/root.component.html @@ -1,3 +1,7 @@ +<button (click)="skipToMainContent()" class="btn btn-primary" id="skip-to-main-content"> + {{ 'root.skip-to-content' | translate }} +</button> + <div class="outer-wrapper" [class.d-none]="shouldShowFullscreenLoader" [@slideSidebarPadding]="{ value: (!(sidebarVisible | async) ? 'hidden' : (slideSidebarOver | async) ? 'shown' : 'expanded'), params: {collapsedSidebarWidth: (collapsedSidebarWidth | async), totalSidebarWidth: (totalSidebarWidth | async)} @@ -6,7 +10,7 @@ <div class="inner-wrapper"> <ds-system-wide-alert-banner></ds-system-wide-alert-banner> <ds-themed-header-navbar-wrapper></ds-themed-header-navbar-wrapper> - <main class="main-content"> + <main id="main-content"> <ds-themed-breadcrumbs></ds-themed-breadcrumbs> <div class="container d-flex justify-content-center align-items-center h-100" *ngIf="shouldShowRouteLoader"> diff --git a/src/app/root/root.component.scss b/src/app/root/root.component.scss index e69de29bb2d..9eb198417ad 100644 --- a/src/app/root/root.component.scss +++ b/src/app/root/root.component.scss @@ -0,0 +1,16 @@ +#skip-to-main-content { + position: absolute; + top: -40px; + left: 0; + opacity: 0; + transition: opacity 0.3s; + z-index: calc(var(--ds-nav-z-index) + 1); + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 0; + + &:focus { + opacity: 1; + top: 0; + } +} diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index 3c2d65fc1f5..aef43b510a8 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -78,4 +78,12 @@ export class RootComponent implements OnInit { this.shouldShowRouteLoader = false; } } + + skipToMainContent() { + const mainContent = document.getElementById('main-content'); + if (mainContent) { + mainContent.tabIndex = -1; + mainContent.focus(); + } + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6c91bae4c16..60a4c21a494 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3610,6 +3610,8 @@ "resource-policies.table.headers.title.for.collection": "Policies for Collection", + "root.skip-to-content": "Skip to main content", + "search.description": "", "search.switch-configuration.title": "Show", diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index b714d399a08..a2642b1fdd3 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -23,7 +23,7 @@ body { position: relative; } -.main-content { +#main-content { z-index: var(--ds-main-z-index); flex: 1 1 100%; margin-top: var(--ds-content-spacing); From 0bcbd2f329ce974e7bd757a014f6647bb0ddb975 Mon Sep 17 00:00:00 2001 From: Marco Aurelio Cardoso <marcoaurelio.cardoso@gmail.com> Date: Sun, 29 Oct 2023 06:49:20 -0300 Subject: [PATCH 178/282] fix(pt-BR.json5): fix and update the language file Fix and update the pt-BR language file (cherry picked from commit e1494c0518888b806ede277f345aa83cb2283b8f) --- src/assets/i18n/pt-BR.json5 | 1424 ++++++++++++++++++++++++++++++----- 1 file changed, 1225 insertions(+), 199 deletions(-) diff --git a/src/assets/i18n/pt-BR.json5 b/src/assets/i18n/pt-BR.json5 index 5d852129bc3..79d332baced 100644 --- a/src/assets/i18n/pt-BR.json5 +++ b/src/assets/i18n/pt-BR.json5 @@ -1,5 +1,4 @@ { - // "401.help": "You're not authorized to access this page. You can use the button below to get back to the home page.", "401.help": "Você não tem autorização para acessar esta página. Clique no botão abaixo para ir à página inicial.", @@ -27,7 +26,6 @@ // "500.link.home-page": "Take me to the home page", "500.link.home-page": "Ir à página inicial", - // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "404.help": "Não encontramos a página que você procura. A página pode ter sido movida ou apagada. Você pode utilizar o botão abaixo para voltar à página inicial. ", @@ -193,7 +191,7 @@ // "admin.registries.bitstream-formats.table.name": "Name", "admin.registries.bitstream-formats.table.name": "Nome", - // TODO New key - Add a translation + // "admin.registries.bitstream-formats.table.id": "ID", "admin.registries.bitstream-formats.table.id": "ID", // "admin.registries.bitstream-formats.table.return": "Back", @@ -271,7 +269,7 @@ // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Campo", - // TODO New key - Add a translation + // "admin.registries.schema.fields.table.id": "ID", "admin.registries.schema.fields.table.id": "ID", // "admin.registries.schema.fields.table.scopenote": "Scope Note", @@ -331,6 +329,30 @@ // "admin.registries.schema.title": "Metadata Schema Registry", "admin.registries.schema.title": "Registro de Esquema de Metadados", + // "admin.access-control.bulk-access.breadcrumbs": "Bulk Access Management", (Auto-Translated) + "admin.access-control.bulk-access.breadcrumbs": "Gerenciamento de acesso em massa", + + // "administrativeBulkAccess.search.results.head": "Search Results", (Auto-Translated) + "administrativeBulkAccess.search.results.head": "Resultados da Busca", + + // "admin.access-control.bulk-access": "Bulk Access Management", (Auto-Translated) + "admin.access-control.bulk-access": "Gerenciamento de acesso em massa", + + // "admin.access-control.bulk-access.title": "Bulk Access Management", (Auto-Translated) + "admin.access-control.bulk-access.title": "Gerenciamento de acesso em massa", + + // "admin.access-control.bulk-access-browse.header": "Step 1: Select Objects", (Auto-Translated) + "admin.access-control.bulk-access-browse.header": "Etapa 1: Selecione objetos", + + // "admin.access-control.bulk-access-browse.search.header": "Search", (Auto-Translated) + "admin.access-control.bulk-access-browse.search.header": "Procurar", + + // "admin.access-control.bulk-access-browse.selected.header": "Current selection({{number}})", (Auto-Translated) + "admin.access-control.bulk-access-browse.selected.header": "Seleção atual ({{number}})", + + // "admin.access-control.bulk-access-settings.header": "Step 2: Operation to Perform", (Auto-Translated) + "admin.access-control.bulk-access-settings.header": "Etapa 2: Operação para executar", + // "admin.access-control.epeople.actions.delete": "Delete EPerson", "admin.access-control.epeople.actions.delete": "Apagar EPerson", @@ -355,7 +377,6 @@ // "admin.access-control.epeople.search.head": "Search", "admin.access-control.epeople.search.head": "Procurar", - // "admin.access-control.epeople.button.see-all": "Browse All", "admin.access-control.epeople.button.see-all": "Pesquisar Todos", @@ -419,7 +440,6 @@ // "admin.access-control.epeople.form.canLogIn": "Can log in", "admin.access-control.epeople.form.canLogIn": "Pode entrar", - // "admin.access-control.epeople.form.requireCertificate": "Requires certificate", "admin.access-control.epeople.form.requireCertificate": "Requer certificado", @@ -450,7 +470,6 @@ // "admin.access-control.epeople.form.notification.deleted.failure": "Failed to delete EPerson \"{{name}}\"", "admin.access-control.epeople.form.notification.deleted.failure": "Falha ao apagar EPerson \"{{name}}\"", - // "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Member of these groups:", "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Membro destes grupos:", @@ -739,32 +758,14 @@ // "admin.access-control.groups.form.return": "Back", "admin.access-control.groups.form.return": "Voltar", - //"admin.batch-import.breadcrumbs": "Import Batch", - "admin.batch-import.breadcrumbs": "Importar um Lote", + // "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.", (Auto-Translated) + "admin.access-control.groups.form.tooltip.editGroupPage": "Nesta página, você pode modificar as propriedades e os membros de um grupo. Na seção superior, você pode editar o nome e a descrição do grupo, a menos que este seja um grupo de administração para uma coleção ou comunidade; nesse caso, o nome e a descrição do grupo são gerados automaticamente e não podem ser editados. Nas seções a seguir, você pode editar a associação ao grupo.Veja [o wiki] (https://wiki.lyrasis.org/display/DSDOC7x/Create+or+manage+a+user+group) para obter mais detalhes.", - //"admin.batch-import.title": "Import Batch", - "admin.batch-import.title": "Importar um Lote", - - //"admin.batch-import.page.header": "Import Batch", - "admin.batch-import.page.header": "Importar um Lote", - - //"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": "Selecione a Coleção para o qual deseja importar. Arraste ou selecione um arquivo zip no formato Simple Archive Format (SAF) que inclua os Items para importar", - - //"admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", - "admin.batch-import.page.dropMsg": "Arraste e solte um lote ZIP para importar", - - //"admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", - "admin.batch-import.page.dropMsgReplace": "Arraste e solte um lote ZIP para substituir o lote para importar", - - //"admin.batch-import.page.error.addFile": "Select Zip file first!", - "admin.batch-import.page.error.addFile": "Selecione um arquivo ZIP primeiro!", - - //"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": "Quando selecionado , o ZIP enviado sera validado. Você receberá um relatório das alterações detectadas, mas nenhuma alteração será salva.", + // "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.", (Auto-Translated) + "admin.access-control.groups.form.tooltip.editGroup.addEpeople": "Para adicionar ou remover uma EPerson para/deste grupo, clique no botão 'Navegar por tudo' ou use a barra de pesquisa abaixo para pesquisar usuários (use o dropdown à esquerda da barra de pesquisa para escolher se deve pesquisar por metadados ou por e-mail). Em seguida, clique no ícone mais para cada usuário que você deseja adicionar na lista abaixo, ou o ícone da lata de lixo para cada usuário que você deseja remover. A lista abaixo pode ter várias páginas: use os controles da página abaixo da lista para navegar até as próximas páginas.", - //"admin.batch-import.page.remove": "remove", - "admin.batch-import.page.remove": "remover", + // "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 groups. Then click the plus icon for each group you wish to add in the list below, or the trash can icon for each group you wish to remove. The list below may have several pages: use the page controls below the list to navigate to the next pages.", (Auto-Translated) + "admin.access-control.groups.form.tooltip.editGroup.addSubgroups": "Para adicionar ou remover um subgrupo de/para este grupo, clique no botão 'Navegar por tudo' ou use a barra de pesquisa abaixo para pesquisar por grupos. Em seguida, clique no ícone mais para cada grupo que você deseja adicionar na lista abaixo, ou o ícone da lata de lixo para cada grupo que você deseja remover. A lista abaixo pode ter várias páginas: use os controles da página abaixo da lista para navegar até as próximas páginas.", // "admin.search.breadcrumbs": "Administrative Search", "admin.search.breadcrumbs": "Pesquisa Administrativa", @@ -811,48 +812,192 @@ // "admin.workflow.item.workflow": "Workflow", "admin.workflow.item.workflow": "Workflow", + // "admin.workflow.item.workspace": "Workspace", (Auto-Translated) + "admin.workflow.item.workspace": "Área de trabalho", + // "admin.workflow.item.delete": "Delete", "admin.workflow.item.delete": "Apagar", // "admin.workflow.item.send-back": "Send back", "admin.workflow.item.send-back": "Devolver", + // "admin.workflow.item.policies": "Policies", (Auto-Translated) + "admin.workflow.item.policies": "Políticas", + + // "admin.workflow.item.supervision": "Supervision", (Auto-Translated) + "admin.workflow.item.supervision": "Supervisão", + // "admin.metadata-import.breadcrumbs": "Import Metadata", "admin.metadata-import.breadcrumbs": "Importar Metadados", + // "admin.batch-import.breadcrumbs": "Import Batch", + "admin.batch-import.breadcrumbs": "Importar um Lote", + // "admin.metadata-import.title": "Import Metadata", "admin.metadata-import.title": "Importar Metadados", + // "admin.batch-import.title": "Import Batch", + "admin.batch-import.title": "Importar um Lote", + // "admin.metadata-import.page.header": "Import Metadata", "admin.metadata-import.page.header": "Importar Metadados", + // "admin.batch-import.page.header": "Import Batch", + "admin.batch-import.page.header": "Importar um Lote", + // "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": "Você arrastar soltar ou procurar arquivos CSV que contêm operações de metadados em lote em arquivos aqui", + // "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": "Selecione a Coleção para o qual deseja importar. Arraste ou selecione um arquivo zip no formato Simple Archive Format (SAF) que inclua os Items para importar", + + // "admin.batch-import.page.toggle.help": "It is possible to perform import either with file upload or via URL, use above toggle to set the input source", (Auto-Translated) + "admin.batch-import.page.toggle.help": "É possível executar a importação com o upload de arquivo ou via URL, use o controle acima para definir a fonte de entrada", + // "admin.metadata-import.page.dropMsg": "Drop a metadata CSV to import", "admin.metadata-import.page.dropMsg": "Arraste um CSV de metadados para importar", + // "admin.batch-import.page.dropMsg": "Drop a batch ZIP to import", + "admin.batch-import.page.dropMsg": "Arraste e solte um lote ZIP para importar", + // "admin.metadata-import.page.dropMsgReplace": "Drop to replace the metadata CSV to import", "admin.metadata-import.page.dropMsgReplace": "Solte para substituir o CSV de metadados a ser importado", + // "admin.batch-import.page.dropMsgReplace": "Drop to replace the batch ZIP to import", + "admin.batch-import.page.dropMsgReplace": "Arraste e solte um lote ZIP para substituir o lote para importar", + // "admin.metadata-import.page.button.return": "Back", "admin.metadata-import.page.button.return": "Voltar", // "admin.metadata-import.page.button.proceed": "Proceed", "admin.metadata-import.page.button.proceed": "Continuar", - //"admin.metadata-import.page.button.select-collection": "Select Collection", + // "admin.metadata-import.page.button.select-collection": "Select Collection", "admin.metadata-import.page.button.select-collection": "Selecione a Coleção", // "admin.metadata-import.page.error.addFile": "Select file first!", "admin.metadata-import.page.error.addFile": "Selecione o arquivo primeiro!", + // "admin.metadata-import.page.error.addFileUrl": "Insert file url first!", (Auto-Translated) + "admin.metadata-import.page.error.addFileUrl": "Insira o URL do arquivo primeiro!", + + // "admin.batch-import.page.error.addFile": "Select Zip file first!", + "admin.batch-import.page.error.addFile": "Selecione um arquivo ZIP primeiro!", + + // "admin.metadata-import.page.toggle.upload": "Upload", (Auto-Translated) + "admin.metadata-import.page.toggle.upload": "Carregar", + + // "admin.metadata-import.page.toggle.url": "URL", (Auto-Translated) + "admin.metadata-import.page.toggle.url": "URL", + + // "admin.metadata-import.page.urlMsg": "Insert the batch ZIP url to import", (Auto-Translated) + "admin.metadata-import.page.urlMsg": "Insira o URL do lote em ZIP para importar", + // "admin.metadata-import.page.validateOnly": "Validate Only", "admin.metadata-import.page.validateOnly": "Validar Somente", // "admin.metadata-import.page.validateOnly.hint": "When selected, the uploaded CSV will be validated. You will receive a report of detected changes, but no changes will be saved.", "admin.metadata-import.page.validateOnly.hint": "Quando selecionado, o CSV carregado será validado. Você receberá um relatório das alterações detectadas, mas nenhuma alteração será salva.", + // "advanced-workflow-action.rating.form.rating.label": "Rating", (Auto-Translated) + "advanced-workflow-action.rating.form.rating.label": "Avaliação", + + // "advanced-workflow-action.rating.form.rating.error": "You must rate the item", (Auto-Translated) + "advanced-workflow-action.rating.form.rating.error": "Você deve avaliar o item", + + // "advanced-workflow-action.rating.form.review.label": "Review", (Auto-Translated) + "advanced-workflow-action.rating.form.review.label": "Análise", + + // "advanced-workflow-action.rating.form.review.error": "You must enter a review to submit this rating", (Auto-Translated) + "advanced-workflow-action.rating.form.review.error": "Você deve inserir uma revisão para enviar esta classificação", + + // "advanced-workflow-action.rating.description": "Please select a rating below", (Auto-Translated) + "advanced-workflow-action.rating.description": "Selecione uma classificação abaixo", + + // "advanced-workflow-action.rating.description-requiredDescription": "Please select a rating below and also add a review", (Auto-Translated) + "advanced-workflow-action.rating.description-requiredDescription": "Selecione uma classificação abaixo e também adicione uma revisão", + + // "advanced-workflow-action.select-reviewer.description-single": "Please select a single reviewer below before submitting", (Auto-Translated) + "advanced-workflow-action.select-reviewer.description-single": "Selecione um único revisor abaixo antes de enviar", + + // "advanced-workflow-action.select-reviewer.description-multiple": "Please select one or more reviewers below before submitting", (Auto-Translated) + "advanced-workflow-action.select-reviewer.description-multiple": "Selecione um ou mais revisores abaixo antes de enviar", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.head": "EPeople", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Add EPeople", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.head": "Adicione EPeople", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Browse All", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.button.see-all": "Navegar por tudo", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Current Members", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Membros atuais", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadata", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadados", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (exact)", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.email": "E-mail (exato)", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Search", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.button": "Procurar", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Name", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.name": "Nome", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identity", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.identity": "Identidade", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.email": "Email", (Auto-Translated) + "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", (Auto-Translated) + "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", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remover / adicionar", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remove member with name "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remova o membro com o nome "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Successfully added member: "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Membro adicionado com sucesso: "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Failed to add member: "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Falha ao adicionar membro: "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Successfully deleted member: "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Membro excluído com sucesso: "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Failed to delete member: "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Falha ao excluir membro: "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Add member with name "{{name}}"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Adicionar membro com o nome "{{name}}"", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "No current active group, submit a name first.", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Nenhum grupo ativo atual, envie um nome primeiro.", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "No members in group yet, search and add.", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-members-yet": "Ainda não há membros do grupo, procure e adicione.", + + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "No EPeople found in that search", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.no-items": "Nenhuma EPeople encontrou nessa pesquisa", + + // "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "No reviewer selected.", (Auto-Translated) + "advanced-workflow-action.select-reviewer.no-reviewer-selected.error": "Nenhum revisor selecionado.", + + // "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": "Quando selecionado , o ZIP enviado sera validado. Você receberá um relatório das alterações detectadas, mas nenhuma alteração será salva.", + + // "admin.batch-import.page.remove": "remove", + "admin.batch-import.page.remove": "remover", + // "auth.errors.invalid-user": "Invalid email address or password.", "auth.errors.invalid-user": "Endereço de email ou senha inválidos.", @@ -862,12 +1007,11 @@ // "auth.messages.token-refresh-failed": "Refreshing your session token failed. Please log in again.", "auth.messages.token-refresh-failed": "Falha ao atualizar seu token de sessão. Por favor faça login novamente.", - // "bitstream.download.page": "Now downloading {{bitstream}}..." , - "bitstream.download.page": "Baixando {{bitstream}} agora ..." , - - // "bitstream.download.page.back": "Back" , - "bitstream.download.page.back": "Voltar" , + // "bitstream.download.page": "Now downloading {{bitstream}}...", + "bitstream.download.page": "Baixando {{bitstream}} agora ...", + // "bitstream.download.page.back": "Back", + "bitstream.download.page.back": "Voltar", // "bitstream.edit.authorizations.link": "Edit bitstream's Policies", "bitstream.edit.authorizations.link": "Editar as políticas do bitstream's", @@ -887,7 +1031,7 @@ // "bitstream.edit.form.description.label": "Description", "bitstream.edit.form.description.label": "Descrição", - // "bitstream.edit.form.embargo.hint": "The first day from which access is allowed. <b>This date cannot be modified on this form.</b> To set an embargo date for a bitstream, go to the <i>Item Status</i> tab, click <i>Autorizações...</i>, create or edit the bitstream's <i>READ</i> policy, and set the <i>Start Date</i> as desired.", + // "bitstream.edit.form.embargo.hint": "The first day from which access is allowed. <b>This date cannot be modified on this form.</b> To set an embargo date for a bitstream, go to the <i>Item Status</i> tab, click <i>Authorizations...</i>, create or edit the bitstream's <i>READ</i> policy, and set the <i>Start Date</i> as desired.", "bitstream.edit.form.embargo.hint": "O primeiro dia a partir do qual o acesso é permitido. <b>Esta data não pode ser modificada neste formulário.</b> Para definir uma data de embargo para este bitstream, vá para a guia <i>Status do Item</i>, clique em <i>Autorizações...</i >, crie ou edite a política <i>READ</i> do bitstream e defina a <i>Data de Início</i> conforme desejado.", // "bitstream.edit.form.embargo.label": "Embargo until specific date", @@ -920,6 +1064,9 @@ // "bitstream.edit.notifications.error.format.title": "An error occurred saving the bitstream's format", "bitstream.edit.notifications.error.format.title": "Um erro ocorreu salvando o formato do bitstream's", + // "bitstream.edit.notifications.error.primaryBitstream.title": "An error occurred saving the primary bitstream", (Auto-Translated) + "bitstream.edit.notifications.error.primaryBitstream.title": "Ocorreu um erro salvando o BitStream primário", + // "bitstream.edit.form.iiifLabel.label": "IIIF Label", "bitstream.edit.form.iiifLabel.label": "Etiqueta IIIF", @@ -944,7 +1091,6 @@ // "bitstream.edit.form.iiifHeight.hint": "The canvas height should usually match the image height.", "bitstream.edit.form.iiifHeight.hint": "A altura da tela geralmente deve corresponder à altura da imagem.", - // "bitstream.edit.notifications.saved.content": "Your changes to this bitstream were saved.", "bitstream.edit.notifications.saved.content": "Suas alterações neste bitstream foram salvas.", @@ -968,6 +1114,7 @@ // "bitstream-request-a-copy.intro.bitstream.one": "Requesting the following file: ", "bitstream-request-a-copy.intro.bitstream.one": "Solicitando o seguinte arquivo: ", + // "bitstream-request-a-copy.intro.bitstream.all": "Requesting all files. ", "bitstream-request-a-copy.intro.bitstream.all": "Solicitando todos os arquivos. ", @@ -1022,6 +1169,12 @@ // "browse.comcol.by.subject": "By Subject", "browse.comcol.by.subject": "Por Assunto", + // "browse.comcol.by.srsc": "By Subject Category", (Auto-Translated) + "browse.comcol.by.srsc": "Por categoria de assunto", + + // "browse.comcol.by.nsi": "By Norwegian Science Index", (Auto-Translated) + "browse.comcol.by.nsi": "Pelo Índice de Ciências Norueguesas", + // "browse.comcol.by.title": "By Title", "browse.comcol.by.title": "Por Título", @@ -1052,6 +1205,12 @@ // "browse.metadata.subject.breadcrumbs": "Browse by Subject", "browse.metadata.subject.breadcrumbs": "Pesquisar por Assunto", + // "browse.metadata.srsc.breadcrumbs": "Browse by Subject Category", (Auto-Translated) + "browse.metadata.srsc.breadcrumbs": "Navegue por categoria de assunto", + + // "browse.metadata.nsi.breadcrumbs": "Browse by Norwegian Science Index", (Auto-Translated) + "browse.metadata.nsi.breadcrumbs": "Navegue pelo Índice de Ciência Norueguês", + // "browse.metadata.title.breadcrumbs": "Browse by Title", "browse.metadata.title.breadcrumbs": "Pesquisar por Título", @@ -1133,15 +1292,33 @@ // "browse.startsWith.type_text": "Filter results by typing the first few letters", "browse.startsWith.type_text": "Filtrar resultados informando as primeiras letras:", + // "browse.startsWith.input": "Filter", (Auto-Translated) + "browse.startsWith.input": "Filtro", + + // "browse.taxonomy.button": "Browse", (Auto-Translated) + "browse.taxonomy.button": "Navegar", + // "browse.title": "Browsing {{ collection }} by {{ field }}{{ startsWith }} {{ value }}", - "browse.title": "Navegando {{ collection }} por {{ field }} {{ value }}", + "browse.title": "Navegando {{ collection }} por {{ field }}{{ startsWith }} {{ value }}", // "browse.title.page": "Browsing {{ collection }} by {{ field }} {{ value }}", "browse.title.page": "Navegando {{ collection }} por {{ field }} {{ value }}", + // "search.browse.item-back": "Back to Results", (Auto-Translated) + "search.browse.item-back": "De volta aos resultados", + // "chips.remove": "Remove chip", "chips.remove": "Remover chip", + // "claimed-approved-search-result-list-element.title": "Approved", (Auto-Translated) + "claimed-approved-search-result-list-element.title": "Approved", + + // "claimed-declined-search-result-list-element.title": "Rejected, sent back to submitter", (Auto-Translated) + "claimed-declined-search-result-list-element.title": "Rejeitado, enviado de volta ao submissor", + + // "claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow", (Auto-Translated) + "claimed-declined-task-search-result-list-element.title": "Recusou, enviado de volta ao fluxo de trabalho do gerente de revisão", + // "collection.create.head": "Create a Collection", "collection.create.head": "Criar uma coleção", @@ -1235,8 +1412,8 @@ // "collection.edit.item-mapper.remove": "Remove selected item mappings", "collection.edit.item-mapper.remove": "Remover mapeamentos selecionados", - // "collection.edit.item-mapper.search-form.placeholder": "Search Item to Map...", - "collection.edit.item-mapper.search-form.placeholder": "Pesquisar Item a Mapear...", + // "collection.edit.item-mapper.search-form.placeholder": "Search items...", + "collection.edit.item-mapper.search-form.placeholder": "Pesquisar Itens...", // "collection.edit.item-mapper.tabs.browse": "Browse mapped items", "collection.edit.item-mapper.tabs.browse": "Navegar por itens mapeados", @@ -1274,9 +1451,15 @@ // "collection.edit.notifications.success": "Successfully edited the Collection", "collection.edit.notifications.success": "Coleção editada com sucesso", - // "collection.edit.return": "Return", + // "collection.edit.return": "Back", "collection.edit.return": "Voltar", + // "collection.edit.tabs.access-control.head": "Access Control", (Auto-Translated) + "collection.edit.tabs.access-control.head": "Controle de acesso", + + // "collection.edit.tabs.access-control.title": "Collection Edit - Access Control", (Auto-Translated) + "collection.edit.tabs.access-control.title": "Edição de coleção - Controle de acesso", + // "collection.edit.tabs.curate.head": "Curate", "collection.edit.tabs.curate.head": "Curadoria", @@ -1400,7 +1583,6 @@ // "collection.edit.template.title": "Edit Template Item", "collection.edit.template.title": "Editar Template de Item", - // "collection.form.abstract": "Short Description", "collection.form.abstract": "Descrição curta", @@ -1460,48 +1642,70 @@ // "collection.source.controls.head": "Harvest Controls", "collection.source.controls.head": "Controles de Colheita(Harvest)", + // "collection.source.controls.test.submit.error": "Something went wrong with initiating the testing of the settings", "collection.source.controls.test.submit.error": "Alguma coisa errada durante a inicialização e teste das configurações", + // "collection.source.controls.test.failed": "The script to test the settings has failed", "collection.source.controls.test.failed": "O script de teste das configurações falhou", + // "collection.source.controls.test.completed": "The script to test the settings has successfully finished", "collection.source.controls.test.completed": "O script de teste das configurações terminou com sucesso", + // "collection.source.controls.test.submit": "Test configuration", "collection.source.controls.test.submit": "Testar a configuração", + // "collection.source.controls.test.running": "Testing configuration...", "collection.source.controls.test.running": "Testando a configuração...", + // "collection.source.controls.import.submit.success": "The import has been successfully initiated", "collection.source.controls.import.submit.success": "A importação foi iniciada com sucesso", + // "collection.source.controls.import.submit.error": "Something went wrong with initiating the import", "collection.source.controls.import.submit.error": "Alguma coisa errada durante a inicialização da importação", + // "collection.source.controls.import.submit": "Import now", "collection.source.controls.import.submit": "Importar agora", + // "collection.source.controls.import.running": "Importing...", "collection.source.controls.import.running": "Importando...", + // "collection.source.controls.import.failed": "An error occurred during the import", "collection.source.controls.import.failed": "Um erro ocorreu durante a importação", + // "collection.source.controls.import.completed": "The import completed", "collection.source.controls.import.completed": "A importação concluiu", + // "collection.source.controls.reset.submit.success": "The reset and reimport has been successfully initiated", "collection.source.controls.reset.submit.success": "A redefinição e reimportação foram iniciadas com sucesso", + // "collection.source.controls.reset.submit.error": "Something went wrong with initiating the reset and reimport", "collection.source.controls.reset.submit.error": "Alguma coisa errada durante a inicialização da redefinição e reimportação", + // "collection.source.controls.reset.failed": "An error occurred during the reset and reimport", "collection.source.controls.reset.failed": "Um erro ocorreu durante a redifinição e reimportação", + // "collection.source.controls.reset.completed": "The reset and reimport completed", "collection.source.controls.reset.completed": "Completou a redefinição e a reimportação", + // "collection.source.controls.reset.submit": "Reset and reimport", "collection.source.controls.reset.submit": "Redefinir e reimportar", + // "collection.source.controls.reset.running": "Resetting and reimporting...", "collection.source.controls.reset.running": "Redefinindo e importando...", + // "collection.source.controls.harvest.status": "Harvest status:", "collection.source.controls.harvest.status": "Status da Colheita (Harvest):", + // "collection.source.controls.harvest.start": "Harvest start time:", "collection.source.controls.harvest.start": "Hora de ínicio da Colheita(Harvest):", + // "collection.source.controls.harvest.last": "Last time harvested:", "collection.source.controls.harvest.last": "Última hora de colhida:", + // "collection.source.controls.harvest.message": "Harvest info:", "collection.source.controls.harvest.message": "Informação sobre Colheita (Harvest):", + // "collection.source.controls.harvest.no-information": "N/A", "collection.source.controls.harvest.no-information": "N/D", @@ -1610,6 +1814,12 @@ // "community.edit.tabs.curate.title": "Community Edit - Curate", "community.edit.tabs.curate.title": "Editar Comunidade - Curador", + // "community.edit.tabs.access-control.head": "Access Control", (Auto-Translated) + "community.edit.tabs.access-control.head": "Controle de acesso", + + // "community.edit.tabs.access-control.title": "Community Edit - Access Control", (Auto-Translated) + "community.edit.tabs.access-control.title": "Edição da comunidade - Controle de acesso", + // "community.edit.tabs.metadata.head": "Edit Metadata", "community.edit.tabs.metadata.head": "Editar Metadado", @@ -1676,7 +1886,6 @@ // "comcol-role.edit.item_read.anonymous-group": "Default read for incoming items is currently set to Anonymous.", "comcol-role.edit.item_read.anonymous-group": "A leitura padrão para itens de entrada está atualmente definida como Anônima.", - // "comcol-role.edit.bitstream_read.name": "Default bitstream read access", "comcol-role.edit.bitstream_read.name": "Acesso de leitura de bitstream padrão", @@ -1686,27 +1895,29 @@ // "comcol-role.edit.bitstream_read.anonymous-group": "Default read for incoming bitstreams is currently set to Anonymous.", "comcol-role.edit.bitstream_read.anonymous-group": "A leitura padrão para bitstreams de entrada está atualmente definida como Anônima.", - // "comcol-role.edit.editor.name": "Editors", "comcol-role.edit.editor.name": "Editores", // "comcol-role.edit.editor.description": "Editors are able to edit the metadata of incoming submissions, and then accept or reject them.", "comcol-role.edit.editor.description": "Editores podem editar metadados de submissões de entrada, e aceitar ou rejeitar elas.", - // "comcol-role.edit.finaleditor.name": "Final editors", "comcol-role.edit.finaleditor.name": "Editores Finais", // "comcol-role.edit.finaleditor.description": "Final editors are able to edit the metadata of incoming submissions, but will not be able to reject them.", "comcol-role.edit.finaleditor.description": "Editores Finais podem editar os metadadods de submissões de entrada, mas não podem rejeitar elas.", - // "comcol-role.edit.reviewer.name": "Reviewers", "comcol-role.edit.reviewer.name": "Revisores", // "comcol-role.edit.reviewer.description": "Reviewers are able to accept or reject incoming submissions. However, they are not able to edit the submission's metadata.", "comcol-role.edit.reviewer.description": "Revisores podem aceitar ou rejeitar submissões de entrada.. Entretanto, eles não podem editar os metadados da submissão.", + // "comcol-role.edit.scorereviewers.name": "Score Reviewers", (Auto-Translated) + "comcol-role.edit.scorereviewers.name": "Revisores de pontuação", + + // "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.", (Auto-Translated) + "comcol-role.edit.scorereviewers.description": "Os revisores podem dar uma pontuação para os envios de entrada, isso definirá se o envio será rejeitado ou não.", // "community.form.abstract": "Short Description", "community.form.abstract": "Descrição curta", @@ -1741,11 +1952,11 @@ // "community.all-lists.head": "Subcommunities and Collections", "community.all-lists.head": "Sub-Comunidade e Coleções", - // "community.sub-collection-list.head": "Collections of this Community", - "community.sub-collection-list.head": "Coleções desta Comunidade", + // "community.sub-collection-list.head": "Collections in this Community", + "community.sub-collection-list.head": "Coleções nesta Comunidade", - // "community.sub-community-list.head": "Communities of this Community", - "community.sub-community-list.head": "Comunidades desta Comunidade", + // "community.sub-community-list.head": "Communities in this Community", + "community.sub-community-list.head": "Comunidades nesta Comunidade", // "cookies.consent.accept-all": "Accept all", "cookies.consent.accept-all": "Aceitar tudo", @@ -1768,6 +1979,12 @@ // "cookies.consent.app.required.title": "(always required)", "cookies.consent.app.required.title": "(sempre requerido)", + // "cookies.consent.app.disable-all.description": "Use this switch to enable or disable all services.", (Auto-Translated) + "cookies.consent.app.disable-all.description": "Use esse comutador para ativar ou desativar todos os serviços.", + + // "cookies.consent.app.disable-all.title": "Enable or disable all services", (Auto-Translated) + "cookies.consent.app.disable-all.title": "Ativar ou desativar todos os serviços", + // "cookies.consent.update": "There were changes since your last visit, please update your consent.", "cookies.consent.update": "Houve alterações desde sua última visita, atualize seu consentimento.", @@ -1777,6 +1994,15 @@ // "cookies.consent.decline": "Decline", "cookies.consent.decline": "Recusar", + // "cookies.consent.ok": "That's ok", (Auto-Translated) + "cookies.consent.ok": "Isso está ok", + + // "cookies.consent.save": "Save", (Auto-Translated) + "cookies.consent.save": "Salvar", + + // "cookies.consent.content-notice.title": "Cookie Consent", (Auto-Translated) + "cookies.consent.content-notice.title": "Consentimento de cookies", + // "cookies.consent.content-notice.description": "We collect and process your personal information for the following purposes: <strong>Authentication, Preferences, Acknowledgement and Statistics</strong>. <br/> To learn more, please read our {privacyPolicy}.", "cookies.consent.content-notice.description": "Coletamos e processamos suas informações pessoais para os seguintes propósitos: <strong>Autenticação, Preferências, Reconhecimento e Estatísticas</strong>. <br/> Para aprender mais, por favor leia nossa {privacyPolicy}.", @@ -1798,6 +2024,12 @@ // "cookies.consent.content-modal.title": "Information that we collect", "cookies.consent.content-modal.title": "Informações que coletamos", + // "cookies.consent.content-modal.services": "services", (Auto-Translated) + "cookies.consent.content-modal.services": "Serviços", + + // "cookies.consent.content-modal.service": "service", (Auto-Translated) + "cookies.consent.content-modal.service": "serviço", + // "cookies.consent.app.title.authentication": "Authentication", "cookies.consent.app.title.authentication": "Authenticação", @@ -1822,16 +2054,28 @@ // "cookies.consent.app.description.google-analytics": "Allows us to track statistical data", "cookies.consent.app.description.google-analytics": "Nos permite rastrear dados estatísticos", + // "cookies.consent.app.title.google-recaptcha": "Google reCaptcha", (Auto-Translated) + "cookies.consent.app.title.google-recaptcha": "Google reCAPTCHA", + + // "cookies.consent.app.description.google-recaptcha": "We use google reCAPTCHA service during registration and password recovery", (Auto-Translated) + "cookies.consent.app.description.google-recaptcha": "Usamos o serviço Google reCAPTCHA durante o registro e recuperação de senha", + // "cookies.consent.purpose.functional": "Functional", "cookies.consent.purpose.functional": "Funcional", // "cookies.consent.purpose.statistical": "Statistical", "cookies.consent.purpose.statistical": "Estatística", - // "curation-task.task.citationpage.label": "Generate Citation Page", + // "cookies.consent.purpose.registration-password-recovery": "Registration and Password recovery", (Auto-Translated) + "cookies.consent.purpose.registration-password-recovery": "Registro e recuperação de senha", + + // "cookies.consent.purpose.sharing": "Sharing", (Auto-Translated) + "cookies.consent.purpose.sharing": "Compartilhamento", + + // "curation-task.task.citationpage.label": "Generate Citation Page", "curation-task.task.citationpage.label": "Gerar página de citação", - // "curation-task.task.checklinks.label": "Check Links in Metadata", + // "curation-task.task.checklinks.label": "Check Links in Metadata", "curation-task.task.checklinks.label": "Verificar links em metadados", // "curation-task.task.noop.label": "NOOP", @@ -1849,6 +2093,9 @@ // "curation-task.task.vscan.label": "Virus Scan", "curation-task.task.vscan.label": "Escanear Virus", + // "curation-task.task.registerdoi.label": "Register DOI", (Auto-Translated) + "curation-task.task.registerdoi.label": "Registrar DOI", + // "curation.form.task-select.label": "Task:", "curation.form.task-select.label": "Tarefa:", @@ -1897,6 +2144,9 @@ // "dso.name.untitled": "Untitled", "dso.name.untitled": "Sem título", + // "dso.name.unnamed": "Unnamed", (Auto-Translated) + "dso.name.unnamed": "Sem nome", + // "dso-selector.create.collection.head": "New collection", "dso-selector.create.collection.head": "Nova coleção", @@ -1906,6 +2156,9 @@ // "dso-selector.create.community.head": "New community", "dso-selector.create.community.head": "Nova comunidade", + // "dso-selector.create.community.or-divider": "or", (Auto-Translated) + "dso-selector.create.community.or-divider": "ou", + // "dso-selector.create.community.sub-level": "Create a new community in", "dso-selector.create.community.sub-level": "Criar uma nova coleção em", @@ -1936,10 +2189,10 @@ // "dso-selector.export-metadata.dspaceobject.head": "Export metadata from", "dso-selector.export-metadata.dspaceobject.head": "Exportar metadados de", - //"dso-selector.export-batch.dspaceobject.head": "Export Batch (ZIP) from", + // "dso-selector.export-batch.dspaceobject.head": "Export Batch (ZIP) from", "dso-selector.export-batch.dspaceobject.head": "Exportar Lote (ZIP) de", - //"dso-selector.import-batch.dspaceobject.head": "Import batch from", + // "dso-selector.import-batch.dspaceobject.head": "Import batch from", "dso-selector.import-batch.dspaceobject.head": "Importar lote de", // "dso-selector.no-results": "No {{ type }} found", @@ -1957,6 +2210,9 @@ // "dso-selector.set-scope.community.button": "Search all of DSpace", "dso-selector.set-scope.community.button": "Pesquisar em todo o DSpace", + // "dso-selector.set-scope.community.or-divider": "or", (Auto-Translated) + "dso-selector.set-scope.community.or-divider": "ou", + // "dso-selector.set-scope.community.input-header": "Search for a community or collection", "dso-selector.set-scope.community.input-header": "Pesquisar uma comunidade ou coleção", @@ -1972,6 +2228,48 @@ // "dso-selector.claim.item.create-from-scratch": "Create a new one", "dso-selector.claim.item.create-from-scratch": "Criar um novo", + // "dso-selector.results-could-not-be-retrieved": "Something went wrong, please refresh again ↻", (Auto-Translated) + "dso-selector.results-could-not-be-retrieved": "Algo deu errado, por favor, recarregue novamente ↻", + + // "supervision-group-selector.header": "Supervision Group Selector", (Auto-Translated) + "supervision-group-selector.header": "Seletor de grupo de supervisão", + + // "supervision-group-selector.select.type-of-order.label": "Select a type of Order", (Auto-Translated) + "supervision-group-selector.select.type-of-order.label": "Selecione um tipo de pedido", + + // "supervision-group-selector.select.type-of-order.option.none": "NONE", (Auto-Translated) + "supervision-group-selector.select.type-of-order.option.none": "NENHUM", + + // "supervision-group-selector.select.type-of-order.option.editor": "EDITOR", (Auto-Translated) + "supervision-group-selector.select.type-of-order.option.editor": "EDITOR", + + // "supervision-group-selector.select.type-of-order.option.observer": "OBSERVER", (Auto-Translated) + "supervision-group-selector.select.type-of-order.option.observer": "OBSERVADOR", + + // "supervision-group-selector.select.group.label": "Select a Group", (Auto-Translated) + "supervision-group-selector.select.group.label": "Selecione um grupo", + + // "supervision-group-selector.button.cancel": "Cancel", (Auto-Translated) + "supervision-group-selector.button.cancel": "Cancelar", + + // "supervision-group-selector.button.save": "Save", (Auto-Translated) + "supervision-group-selector.button.save": "Salvar", + + // "supervision-group-selector.select.type-of-order.error": "Please select a type of order", (Auto-Translated) + "supervision-group-selector.select.type-of-order.error": "Selecione um tipo de pedido", + + // "supervision-group-selector.select.group.error": "Please select a group", (Auto-Translated) + "supervision-group-selector.select.group.error": "Selecione um grupo", + + // "supervision-group-selector.notification.create.success.title": "Successfully created supervision order for group {{ name }}", (Auto-Translated) + "supervision-group-selector.notification.create.success.title": "Ordem de supervisão criada com sucesso para o grupo {{ name }}", + + // "supervision-group-selector.notification.create.failure.title": "Error", (Auto-Translated) + "supervision-group-selector.notification.create.failure.title": "Erro", + + // "supervision-group-selector.notification.create.already-existing": "A supervision order already exists on this item for selected group", (Auto-Translated) + "supervision-group-selector.notification.create.already-existing": "Já existe uma ordem de supervisão neste item para o grupo selecionado", + // "confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}", "confirmation-modal.export-metadata.header": "Exportar metadados para {{ dsoName }}", @@ -1984,16 +2282,16 @@ // "confirmation-modal.export-metadata.confirm": "Export", "confirmation-modal.export-metadata.confirm": "Exportar", - //"confirmation-modal.export-batch.header": "Export batch (ZIP) for {{ dsoName }}", + // "confirmation-modal.export-batch.header": "Export batch (ZIP) for {{ dsoName }}", "confirmation-modal.export-batch.header": "Exportar lote (ZIP) para {{ dsoName }}", - //"confirmation-modal.export-batch.info": "Are you sure you want to export batch (ZIP) for {{ dsoName }}", + // "confirmation-modal.export-batch.info": "Are you sure you want to export batch (ZIP) for {{ dsoName }}", "confirmation-modal.export-batch.info": "Você tem certeza que deseja exportar o lote (ZIP) para {{ dsoName }}", - //"confirmation-modal.export-batch.cancel": "Cancel", + // "confirmation-modal.export-batch.cancel": "Cancel", "confirmation-modal.export-batch.cancel": "Cancelar", - //"confirmation-modal.export-batch.confirm": "Export", + // "confirmation-modal.export-batch.confirm": "Export", "confirmation-modal.export-batch.confirm": "Exportar", // "confirmation-modal.delete-eperson.header": "Delete EPerson \"{{ dsoName }}\"", @@ -2020,6 +2318,18 @@ // "confirmation-modal.delete-profile.confirm": "Delete", "confirmation-modal.delete-profile.confirm": "Apagar", + // "confirmation-modal.delete-subscription.header": "Delete Subscription", (Auto-Translated) + "confirmation-modal.delete-subscription.header": "Excluir assinatura", + + // "confirmation-modal.delete-subscription.info": "Are you sure you want to delete subscription for "{{ dsoName }}"", (Auto-Translated) + "confirmation-modal.delete-subscription.info": "Tem certeza de que deseja excluir a assinatura para "{{ dsoName }}"", + + // "confirmation-modal.delete-subscription.cancel": "Cancel", (Auto-Translated) + "confirmation-modal.delete-subscription.cancel": "Cancelar", + + // "confirmation-modal.delete-subscription.confirm": "Delete", (Auto-Translated) + "confirmation-modal.delete-subscription.confirm": "Excluir", + // "error.bitstream": "Error fetching bitstream", "error.bitstream": "Erro ao carregar bitstream", @@ -2092,6 +2402,27 @@ // "error.validation.groupExists": "This group already exists", "error.validation.groupExists": "Este Grupo já existe", + // "error.validation.metadata.name.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Element & Qualifier fields instead", (Auto-Translated) + "error.validation.metadata.name.invalid-pattern": "Este campo não pode conter pontos, vírgulas ou espaços. Ao invés, por favor, use os campos de Elemento e Qualificador", + + // "error.validation.metadata.name.max-length": "This field may not contain more than 32 characters", (Auto-Translated) + "error.validation.metadata.name.max-length": "Este campo pode não conter mais de 32 caracteres", + + // "error.validation.metadata.namespace.max-length": "This field may not contain more than 256 characters", (Auto-Translated) + "error.validation.metadata.namespace.max-length": "Este campo pode não conter mais de 256 caracteres", + + // "error.validation.metadata.element.invalid-pattern": "This field cannot contain dots, commas or spaces. Please use the Qualifier field instead", (Auto-Translated) + "error.validation.metadata.element.invalid-pattern": "Este campo não pode conter pontos, vírgulas ou espaços. Por favor, use o campo Qualificador em vez disso", + + // "error.validation.metadata.element.max-length": "This field may not contain more than 64 characters", (Auto-Translated) + "error.validation.metadata.element.max-length": "Este campo pode não conter mais de 64 caracteres", + + // "error.validation.metadata.qualifier.invalid-pattern": "This field cannot contain dots, commas or spaces", (Auto-Translated) + "error.validation.metadata.qualifier.invalid-pattern": "Este campo não pode conter pontos, vírgulas ou espaços", + + // "error.validation.metadata.qualifier.max-length": "This field may not contain more than 64 characters", (Auto-Translated) + "error.validation.metadata.qualifier.max-length": "Este campo pode não conter mais de 64 caracteres", + // "feed.description": "Syndication feed", "feed.description": "Feed de distribuição", @@ -2113,10 +2444,10 @@ // "footer.link.privacy-policy": "Privacy policy", "footer.link.privacy-policy": "Política de Privacidade", - // "footer.link.end-user-agreement":"End User Agreement", + // "footer.link.end-user-agreement": "End User Agreement", "footer.link.end-user-agreement": "Termos de Uso", - // "footer.link.feedback":"Send Feedback", + // "footer.link.feedback": "Send Feedback", "footer.link.feedback": "Enviar uma Sugestão", // "forgot-email.form.header": "Forgot Password", @@ -2131,8 +2462,8 @@ // "forgot-email.form.email.error.required": "Please fill in an email address", "forgot-email.form.email.error.required": "Por favor preencha o endereço de email", - // "forgot-email.form.email.error.pattern": "Please fill in a valid email address", - "forgot-email.form.email.error.pattern": "Por favor preencha com um e-mail válido", + // "forgot-email.form.email.error.not-email-form": "Please fill in a valid email address", (Auto-Translated) + "forgot-email.form.email.error.not-email-form": "Por favor preencha com um endereço de email válido", // "forgot-email.form.email.hint": "An email will be sent to this address with a further instructions.", "forgot-email.form.email.hint": "Um e-mail será enviado para este endereço com mais instruções.", @@ -2254,6 +2585,24 @@ // "form.no-value": "No value entered", "form.no-value": "Nenhum valor informado", + // "form.other-information.email": "Email", (Auto-Translated) + "form.other-information.email": "E-mail", + + // "form.other-information.first-name": "First Name", (Auto-Translated) + "form.other-information.first-name": "Primeiro nome", + + // "form.other-information.insolr": "In Solr Index", (Auto-Translated) + "form.other-information.insolr": "No índice Solr", + + // "form.other-information.institution": "Institution", (Auto-Translated) + "form.other-information.institution": "Instituição", + + // "form.other-information.last-name": "Last Name", (Auto-Translated) + "form.other-information.last-name": "Sobrenome", + + // "form.other-information.orcid": "ORCID", (Auto-Translated) + "form.other-information.orcid": "ORCID", + // "form.remove": "Remove", "form.remove": "Apagar", @@ -2272,6 +2621,9 @@ // "form.submit": "Save", "form.submit": "Salvar", + // "form.create": "Create", (Auto-Translated) + "form.create": "Criar", + // "form.repeatable.sort.tip": "Drop the item in the new position", "form.repeatable.sort.tip": "Solte o item na nova posição", @@ -2281,8 +2633,8 @@ // "grant-deny-request-copy.email.back": "Back", "grant-deny-request-copy.email.back": "Voltar", - // "grant-deny-request-copy.email.message": "Message", - "grant-deny-request-copy.email.message": "Mensagem", + // "grant-deny-request-copy.email.message": "Optional additional message", + "grant-deny-request-copy.email.message": "Mensagem adicional opcional", // "grant-deny-request-copy.email.message.empty": "Please enter a message", "grant-deny-request-copy.email.message.empty": "Por favor coloque uma mensagem", @@ -2333,8 +2685,8 @@ // "grant-request-copy.header": "Grant document copy request", "grant-request-copy.header": "Conceder solicitação de cópia do documento", - // "grant-request-copy.intro": "This message will be sent to the applicant of the request. The requested document(s) will be attached.", - "grant-request-copy.intro": "Esta mensagem será enviada ao requerente do pedido. O(s) documento(s) solicitado(s) será(ão) anexado(s).", + // "grant-request-copy.intro": "A message will be sent to the applicant of the request. The requested document(s) will be attached.", + "grant-request-copy.intro": "Uma mensagem será enviada ao requerente do pedido. O(s) documento(s) solicitado(s) será(ão) anexado(s).", // "grant-request-copy.success": "Successfully granted item request", "grant-request-copy.success": "Solicitação de item concedida com sucesso", @@ -2342,13 +2694,13 @@ // "health.breadcrumbs": "Health", "health.breadcrumbs": "Saúde", - // "health-page.heading" : "Health", + // "health-page.heading": "Health", "health-page.heading": "Saúde", - // "health-page.info-tab" : "Info", + // "health-page.info-tab": "Info", "health-page.info-tab": "Informação", - // "health-page.status-tab" : "Status", + // "health-page.status-tab": "Status", "health-page.status-tab": "Status", // "health-page.error.msg": "The health check service is temporarily unavailable", @@ -2441,6 +2793,9 @@ // "info.end-user-agreement.title": "End User Agreement", "info.end-user-agreement.title": "Contrato de Usuário Final", + // "info.end-user-agreement.hosting-country": "the United States", (Auto-Translated) + "info.end-user-agreement.hosting-country": "os Estados Unidos", + // "info.privacy.breadcrumbs": "Privacy Statement", "info.privacy.breadcrumbs": "Política de privacidade", @@ -2474,19 +2829,19 @@ // "info.feedback.email-label": "Your Email", "info.feedback.email-label": "Seu Email", - // "info.feedback.create.success" : "Feedback Sent Successfully!", + // "info.feedback.create.success": "Feedback Sent Successfully!", "info.feedback.create.success": "Sugestão Enviada com Sucesso!", - // "info.feedback.error.email.required" : "A valid email address is required", + // "info.feedback.error.email.required": "A valid email address is required", "info.feedback.error.email.required": "Um endereço de email válido é requerido", - // "info.feedback.error.message.required" : "A comment is required", + // "info.feedback.error.message.required": "A comment is required", "info.feedback.error.message.required": "Um comentário é requerido", - // "info.feedback.page-label" : "Page", + // "info.feedback.page-label": "Page", "info.feedback.page-label": "Página", - // "info.feedback.page_help" : "Tha page related to your feedback", + // "info.feedback.page_help": "Tha page related to your feedback", "info.feedback.page_help": "A página relacionada a sua sugestão", // "item.alerts.private": "This item is non-discoverable", @@ -2501,7 +2856,7 @@ // "item.edit.authorizations.title": "Edit item's Policies", "item.edit.authorizations.title": "Editar Política de item", - // "item.badge.private": "Private", + // "item.badge.private": "Non-discoverable", "item.badge.private": "Privado", // "item.badge.withdrawn": "Withdrawn", @@ -2657,13 +3012,75 @@ // "item.edit.tabs.disabled.tooltip": "You're not authorized to access this tab", "item.edit.tabs.disabled.tooltip": "Você não está autorizado a acessar esta guia", - // "item.edit.tabs.mapper.head": "Collection Mapper", "item.edit.tabs.mapper.head": "Mapeamento de Coleção", // "item.edit.tabs.item-mapper.title": "Item Edit - Collection Mapper", "item.edit.tabs.item-mapper.title": "Editar Item - Mapeamento de Coleção", + // "item.edit.identifiers.doi.status.UNKNOWN": "Unknown", (Auto-Translated) + "item.edit.identifiers.doi.status.UNKNOWN": "Desconhecido", + + // "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Queued for registration", (Auto-Translated) + "item.edit.identifiers.doi.status.TO_BE_REGISTERED": "Fila para registro", + + // "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Queued for reservation", (Auto-Translated) + "item.edit.identifiers.doi.status.TO_BE_RESERVED": "Fila para reserva", + + // "item.edit.identifiers.doi.status.IS_REGISTERED": "Registered", (Auto-Translated) + "item.edit.identifiers.doi.status.IS_REGISTERED": "Registrado", + + // "item.edit.identifiers.doi.status.IS_RESERVED": "Reserved", (Auto-Translated) + "item.edit.identifiers.doi.status.IS_RESERVED": "Reservado", + + // "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Reserved (update queued)", (Auto-Translated) + "item.edit.identifiers.doi.status.UPDATE_RESERVED": "Reservado (atualiza a fila)", + + // "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registered (update queued)", (Auto-Translated) + "item.edit.identifiers.doi.status.UPDATE_REGISTERED": "Registrado (atualiza a fila)", + + // "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Queued for update and registration", (Auto-Translated) + "item.edit.identifiers.doi.status.UPDATE_BEFORE_REGISTRATION": "Fila para atualização e registro", + + // "item.edit.identifiers.doi.status.TO_BE_DELETED": "Queued for deletion", (Auto-Translated) + "item.edit.identifiers.doi.status.TO_BE_DELETED": "Fila para exclusão", + + // "item.edit.identifiers.doi.status.DELETED": "Deleted", (Auto-Translated) + "item.edit.identifiers.doi.status.DELETED": "Excluído", + + // "item.edit.identifiers.doi.status.PENDING": "Pending (not registered)", (Auto-Translated) + "item.edit.identifiers.doi.status.PENDING": "Pendente (não registrado)", + + // "item.edit.identifiers.doi.status.MINTED": "Minted (not registered)", (Auto-Translated) + "item.edit.identifiers.doi.status.MINTED": "Cunhado (não registrado)", + + // "item.edit.tabs.status.buttons.register-doi.label": "Register a new or pending DOI", (Auto-Translated) + "item.edit.tabs.status.buttons.register-doi.label": "Registre um DOI novo ou pendente", + + // "item.edit.tabs.status.buttons.register-doi.button": "Register DOI...", (Auto-Translated) + "item.edit.tabs.status.buttons.register-doi.button": "Registre DOI ...", + + // "item.edit.register-doi.header": "Register a new or pending DOI", (Auto-Translated) + "item.edit.register-doi.header": "Registre um DOI novo ou pendente", + + // "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", (Auto-Translated) + "item.edit.register-doi.description": "Revise todos os identificadores pendentes e metadados do item abaixo e clique em Confirmar para prosseguir com o registro do DOI ou cancelar para desistir", + + // "item.edit.register-doi.confirm": "Confirm", (Auto-Translated) + "item.edit.register-doi.confirm": "Confirmar", + + // "item.edit.register-doi.cancel": "Cancel", (Auto-Translated) + "item.edit.register-doi.cancel": "Cancelar", + + // "item.edit.register-doi.success": "DOI queued for registration successfully.", (Auto-Translated) + "item.edit.register-doi.success": "DOI enfileirado para registro com sucesso.", + + // "item.edit.register-doi.error": "Error registering DOI", (Auto-Translated) + "item.edit.register-doi.error": "Erro ao registrar DOI", + + // "item.edit.register-doi.to-update": "The following DOI has already been minted and will be queued for registration online", (Auto-Translated) + "item.edit.register-doi.to-update": "O seguinte DOI já foi cunhado e será enfileirado para registro online", + // "item.edit.item-mapper.buttons.add": "Map item to selected collections", "item.edit.item-mapper.buttons.add": "Mapear item na(s) coleção(ões) seleciona(s)", @@ -2724,6 +3141,12 @@ // "item.edit.metadata.discard-button": "Discard", "item.edit.metadata.discard-button": "Descartar", + // "item.edit.metadata.edit.buttons.confirm": "Confirm", (Auto-Translated) + "item.edit.metadata.edit.buttons.confirm": "Confirmar", + + // "item.edit.metadata.edit.buttons.drag": "Drag to reorder", (Auto-Translated) + "item.edit.metadata.edit.buttons.drag": "Arraste para reordenar", + // "item.edit.metadata.edit.buttons.edit": "Edit", "item.edit.metadata.edit.buttons.edit": "Editar", @@ -2736,6 +3159,9 @@ // "item.edit.metadata.edit.buttons.unedit": "Stop editing", "item.edit.metadata.edit.buttons.unedit": "Parar edição", + // "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", (Auto-Translated) + "item.edit.metadata.edit.buttons.virtual": "Este é um valor de metadados virtuais, ou seja, um valor herdado de uma entidade relacionada. Não pode ser modificado diretamente. Adicione ou remova o relacionamento correspondente na guia \"Relacionamentos\"", + // "item.edit.metadata.empty": "The item currently doesn't contain any metadata. Click Add to start adding a metadata value.", "item.edit.metadata.empty": "O item atualmente não contém metadados. Clique em Adicionar para começar a adicionar um valor de metadados.", @@ -2751,6 +3177,9 @@ // "item.edit.metadata.headers.value": "Value", "item.edit.metadata.headers.value": "Valor", + // "item.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", (Auto-Translated) + "item.edit.metadata.metadatafield.error": "Ocorreu um erro ao validar o campo de metadados", + // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", "item.edit.metadata.metadatafield.invalid": "Por favor escolha um campo de metadados válido", @@ -2784,6 +3213,9 @@ // "item.edit.metadata.reinstate-button": "Undo", "item.edit.metadata.reinstate-button": "Desfazer", + // "item.edit.metadata.reset-order-button": "Undo reorder", (Auto-Translated) + "item.edit.metadata.reset-order-button": "Desfazer reordenar", + // "item.edit.metadata.save-button": "Save", "item.edit.metadata.save-button": "Salvar", @@ -2838,37 +3270,37 @@ // "item.edit.private.cancel": "Cancel", "item.edit.private.cancel": "Cancelar", - // "item.edit.private.confirm": "Make it Private", + // "item.edit.private.confirm": "Make it non-discoverable", "item.edit.private.confirm": "Tornar Privado", - // "item.edit.private.description": "Are you sure this item should be made private in the archive?", + // "item.edit.private.description": "Are you sure this item should be made non-discoverable in the archive?", "item.edit.private.description": "Tem certeza de que este item deve ser tornado privado no arquivo?", - // "item.edit.private.error": "An error occurred while making the item private", + // "item.edit.private.error": "An error occurred while making the item non-discoverable", "item.edit.private.error": "Ocorreu um erro ao tornar o item privado", - // "item.edit.private.header": "Make item private: {{ id }}", + // "item.edit.private.header": "Make item non-discoverable: {{ id }}", "item.edit.private.header": "Tornar o item privado: {{ id }}", - // "item.edit.private.success": "The item is now private", + // "item.edit.private.success": "The item is now non-discoverable", "item.edit.private.success": "O item agora é privado", // "item.edit.public.cancel": "Cancel", "item.edit.public.cancel": "Cancelar", - // "item.edit.public.confirm": "Make it public", + // "item.edit.public.confirm": "Make it discoverable", "item.edit.public.confirm": "Tornar público", - // "item.edit.public.description": "Are you sure this item should be made public in the archive?", + // "item.edit.public.description": "Are you sure this item should be made discoverable in the archive?", "item.edit.public.description": "Você tem certeza que deseja tornar este item público no arquivo?", - // "item.edit.public.error": "An error occurred while making the item public", + // "item.edit.public.error": "An error occurred while making the item discoverable", "item.edit.public.error": "Ocorreu um erro ao tornar o item público", - // "item.edit.public.header": "Make item public: {{ id }}", + // "item.edit.public.header": "Make item discoverable: {{ id }}", "item.edit.public.header": "Tornar o item público: {{ id }}", - // "item.edit.public.success": "The item is now public", + // "item.edit.public.success": "The item is now discoverable", "item.edit.public.success": "O item agora é público", // "item.edit.reinstate.cancel": "Cancel", @@ -2949,6 +3381,15 @@ // "item.edit.tabs.curate.title": "Item Edit - Curate", "item.edit.tabs.curate.title": "Editar Item - Curadoria", + // "item.edit.curate.title": "Curate Item: {{item}}", (Auto-Translated) + "item.edit.curate.title": "Fazer curadoria do Item: {{item}}", + + // "item.edit.tabs.access-control.head": "Access Control", (Auto-Translated) + "item.edit.tabs.access-control.head": "Controle de acesso", + + // "item.edit.tabs.access-control.title": "Item Edit - Access Control", (Auto-Translated) + "item.edit.tabs.access-control.title": "Edição de item - Controle de acesso", + // "item.edit.tabs.metadata.head": "Metadata", "item.edit.tabs.metadata.head": "Metadados", @@ -3102,6 +3543,30 @@ // "item.truncatable-part.show-less": "Collapse", "item.truncatable-part.show-less": "Fechar", + // "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", (Auto-Translated) + "workflow-item.search.result.delete-supervision.modal.header": "Excluir ordem de supervisão", + + // "workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order", (Auto-Translated) + "workflow-item.search.result.delete-supervision.modal.info": "Tem certeza que deseja excluir o pedido de supervisão", + + // "workflow-item.search.result.delete-supervision.modal.cancel": "Cancel", (Auto-Translated) + "workflow-item.search.result.delete-supervision.modal.cancel": "Cancelar", + + // "workflow-item.search.result.delete-supervision.modal.confirm": "Delete", (Auto-Translated) + "workflow-item.search.result.delete-supervision.modal.confirm": "Excluir", + + // "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order "{{name}}"", (Auto-Translated) + "workflow-item.search.result.notification.deleted.success": "Ordem de supervisão excluída com sucesso "{{name}}"", + + // "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order "{{name}}"", (Auto-Translated) + "workflow-item.search.result.notification.deleted.failure": "Falha ao excluir a ordem de supervisão "{{name}}"", + + // "workflow-item.search.result.list.element.supervised-by": "Supervised by:", (Auto-Translated) + "workflow-item.search.result.list.element.supervised-by": "Supervisionado por:", + + // "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remove supervision group", (Auto-Translated) + "workflow-item.search.result.list.element.supervised.remove-tooltip": "Remover o grupo de supervisão", + // "item.page.abstract": "Abstract", "item.page.abstract": "Resumo", @@ -3192,10 +3657,10 @@ // "item.page.bitstreams.collapse": "Collapse", "item.page.bitstreams.collapse": "Fechar", - // "item.page.filesection.original.bundle" : "Original bundle", + // "item.page.filesection.original.bundle": "Original bundle", "item.page.filesection.original.bundle": "Pacote Original", - // "item.page.filesection.license.bundle" : "License bundle", + // "item.page.filesection.license.bundle": "License bundle", "item.page.filesection.license.bundle": "Licença do Pacote", // "item.page.return": "Back", @@ -3240,27 +3705,30 @@ // "item.preview.dc.type": "Type:", "item.preview.dc.type": "Tipo:", - // "item.preview.oaire.citation.issue" : "Issue", + // "item.preview.oaire.citation.issue": "Issue", "item.preview.oaire.citation.issue": "Questão", - // "item.preview.oaire.citation.volume" : "Volume", + // "item.preview.oaire.citation.volume": "Volume", "item.preview.oaire.citation.volume": "Volume", - // "item.preview.dc.relation.issn" : "ISSN", + // "item.preview.dc.relation.issn": "ISSN", "item.preview.dc.relation.issn": "ISSN", - // "item.preview.dc.identifier.isbn" : "ISBN", + // "item.preview.dc.identifier.isbn": "ISBN", "item.preview.dc.identifier.isbn": "ISBN", // "item.preview.dc.identifier": "Identifier:", "item.preview.dc.identifier": "Identificador:", - // "item.preview.dc.relation.ispartof" : "Journal or Serie", - "item.preview.dc.relation.ispartof": "Revista ou Série", + // "item.preview.dc.relation.ispartof": "Journal or Series", + "item.preview.dc.relation.ispartof": "Revista ou Séries", - // "item.preview.dc.identifier.doi" : "DOI", + // "item.preview.dc.identifier.doi": "DOI", "item.preview.dc.identifier.doi": "DOI", + // "item.preview.dc.publisher": "Publisher:", (Auto-Translated) + "item.preview.dc.publisher": "Editora:", + // "item.preview.person.familyName": "Surname:", "item.preview.person.familyName": "Sobrenome:", @@ -3399,13 +3867,13 @@ // "item.version.create.modal.submitted.text": "The new version is being created. This may take some time if the item has a lot of relationships.", "item.version.create.modal.submitted.text": "A nova versão está sendo criada. Isso pode levar algum tempo se o item tiver muitos relacionamentos.", - // "item.version.create.notification.success" : "New version has been created with version number {{version}}", + // "item.version.create.notification.success": "New version has been created with version number {{version}}", "item.version.create.notification.success": "Uma nova versão foi criada com o número de versão {{version}}", - // "item.version.create.notification.failure" : "New version has not been created", + // "item.version.create.notification.failure": "New version has not been created", "item.version.create.notification.failure": "A nova versão não foi criada", - // "item.version.create.notification.inProgress" : "A new version cannot be created because there is an inprogress submission in the version history", + // "item.version.create.notification.inProgress": "A new version cannot be created because there is an inprogress submission in the version history", "item.version.create.notification.inProgress": "Não é possível criar uma nova versão porque há uma submissão em andamento no histórico de versões", // "item.version.delete.modal.header": "Delete version", @@ -3426,18 +3894,99 @@ // "item.version.delete.modal.button.cancel.tooltip": "Do not delete this version", "item.version.delete.modal.button.cancel.tooltip": "Não apague esta versão", - // "item.version.delete.notification.success" : "Version number {{version}} has been deleted", + // "item.version.delete.notification.success": "Version number {{version}} has been deleted", "item.version.delete.notification.success": "Versão número {{version}} foi apagada", - // "item.version.delete.notification.failure" : "Version number {{version}} has not been deleted", + // "item.version.delete.notification.failure": "Version number {{version}} has not been deleted", "item.version.delete.notification.failure": "Versão número {{version}} não foi apagada", - // "item.version.edit.notification.success" : "The summary of version number {{version}} has been changed", + // "item.version.edit.notification.success": "The summary of version number {{version}} has been changed", "item.version.edit.notification.success": "O resumo da versão número {{version}} foi alterado", - // "item.version.edit.notification.failure" : "The summary of version number {{version}} has not been changed", + // "item.version.edit.notification.failure": "The summary of version number {{version}} has not been changed", "item.version.edit.notification.failure": "O resumo da versão número {{version}} não foi alterado", + // "itemtemplate.edit.metadata.add-button": "Add", (Auto-Translated) + "itemtemplate.edit.metadata.add-button": "Adicionar", + + // "itemtemplate.edit.metadata.discard-button": "Discard", (Auto-Translated) + "itemtemplate.edit.metadata.discard-button": "Descartar", + + // "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirm", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirmar", + + // "itemtemplate.edit.metadata.edit.buttons.drag": "Drag to reorder", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.drag": "Arraste para reordenar", + + // "itemtemplate.edit.metadata.edit.buttons.edit": "Edit", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.edit": "Editar", + + // "itemtemplate.edit.metadata.edit.buttons.remove": "Remove", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.remove": "Remover", + + // "itemtemplate.edit.metadata.edit.buttons.undo": "Undo changes", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.undo": "Desfazer mudanças", + + // "itemtemplate.edit.metadata.edit.buttons.unedit": "Stop editing", (Auto-Translated) + "itemtemplate.edit.metadata.edit.buttons.unedit": "Parar de editar", + + // "itemtemplate.edit.metadata.empty": "The item template currently doesn't contain any metadata. Click Add to start adding a metadata value.", (Auto-Translated) + "itemtemplate.edit.metadata.empty": "O modelo de item atualmente não contém metadados. Clique em Adicionar para começar a adicionar um valor de metadados.", + + // "itemtemplate.edit.metadata.headers.edit": "Edit", (Auto-Translated) + "itemtemplate.edit.metadata.headers.edit": "Editar", + + // "itemtemplate.edit.metadata.headers.field": "Field", (Auto-Translated) + "itemtemplate.edit.metadata.headers.field": "Campo", + + // "itemtemplate.edit.metadata.headers.language": "Lang", (Auto-Translated) + "itemtemplate.edit.metadata.headers.language": "Idioma", + + // "itemtemplate.edit.metadata.headers.value": "Value", (Auto-Translated) + "itemtemplate.edit.metadata.headers.value": "Valor", + + // "itemtemplate.edit.metadata.metadatafield.error": "An error occurred validating the metadata field", (Auto-Translated) + "itemtemplate.edit.metadata.metadatafield.error": "Ocorreu um erro validando o campo de metadados", + + // "itemtemplate.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", (Auto-Translated) + "itemtemplate.edit.metadata.metadatafield.invalid": "Escolha um campo de metadados válido", + + // "itemtemplate.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.discarded.content": "Suas mudanças foram descartadas. Para restabelecer suas alterações, clique no botão 'Desfazer'", + + // "itemtemplate.edit.metadata.notifications.discarded.title": "Changes discarded", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.discarded.title": "Mudanças descartadas", + + // "itemtemplate.edit.metadata.notifications.error.title": "An error occurred", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.error.title": "Um erro ocorreu", + + // "itemtemplate.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.invalid.content": "Suas mudanças não foram salvas. Certifique-se de que todos os campos sejam válidos antes de salvar.", + + // "itemtemplate.edit.metadata.notifications.invalid.title": "Metadata invalid", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.invalid.title": "Metadados inválidos", + + // "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", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.outdated.content": "O modelo de item em que você está trabalhando atualmente foi alterado por outro usuário. Suas alterações atuais serão descartadas para evitar conflitos", + + // "itemtemplate.edit.metadata.notifications.outdated.title": "Changes outdated", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.outdated.title": "Mudanças desatualizadas", + + // "itemtemplate.edit.metadata.notifications.saved.content": "Your changes to this item template's metadata were saved.", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.saved.content": "Suas alterações nos metadados do modelo deste item foram salvas.", + + // "itemtemplate.edit.metadata.notifications.saved.title": "Metadata saved", (Auto-Translated) + "itemtemplate.edit.metadata.notifications.saved.title": "Metadados salvos", + + // "itemtemplate.edit.metadata.reinstate-button": "Undo", (Auto-Translated) + "itemtemplate.edit.metadata.reinstate-button": "Desfazer", + + // "itemtemplate.edit.metadata.reset-order-button": "Undo reorder", (Auto-Translated) + "itemtemplate.edit.metadata.reset-order-button": "Desfazer reordenar", + + // "itemtemplate.edit.metadata.save-button": "Save", (Auto-Translated) + "itemtemplate.edit.metadata.save-button": "Salvar", + // "journal.listelement.badge": "Journal", "journal.listelement.badge": "Revista", @@ -3523,8 +4072,7 @@ "iiifsearchable.page.doi": "Link Permanente: ", // "iiifsearchable.page.issue": "Issue: ", - // TODO New key - Add a translation - "iiifsearchable.page.issue": "Issue: ", + "iiifsearchable.page.issue": "Edição: ", // "iiifsearchable.page.description": "Description: ", "iiifsearchable.page.description": "Descrição: ", @@ -3542,8 +4090,7 @@ "iiif.page.doi": "Link Permanente: ", // "iiif.page.issue": "Issue: ", - // TODO New key - Add a translation - "iiif.page.issue": "Issue: ", + "iiif.page.issue": "Edição: ", // "iiif.page.description": "Description: ", "iiif.page.description": "Descrição: ", @@ -3614,9 +4161,6 @@ // "login.form.new-user": "New user? Click here to register.", "login.form.new-user": "Novo usuário? Clique aqui para cadastrar.", - // "login.form.or-divider": "or", - "login.form.or-divider": "ou", - // "login.form.oidc": "Log in with OIDC", "login.form.oidc": "Entrar com o OIDC", @@ -3662,6 +4206,9 @@ // "menu.section.access_control_authorizations": "Authorizations", "menu.section.access_control_authorizations": "Autorizações", + // "menu.section.access_control_bulk": "Bulk Access Management", (Auto-Translated) + "menu.section.access_control_bulk": "Gerenciamento de acesso em massa", + // "menu.section.access_control_groups": "Groups", "menu.section.access_control_groups": "Grupos", @@ -3695,6 +4242,12 @@ // "menu.section.browse_global_by_subject": "By Subject", "menu.section.browse_global_by_subject": "Por Assunto", + // "menu.section.browse_global_by_srsc": "By Subject Category", (Auto-Translated) + "menu.section.browse_global_by_srsc": "Por categoria de assunto", + + // "menu.section.browse_global_by_nsi": "By Norwegian Science Index", (Auto-Translated) + "menu.section.browse_global_by_nsi": "Pelo Índice de Ciências Norueguesas", + // "menu.section.browse_global_by_title": "By Title", "menu.section.browse_global_by_title": "Por Título", @@ -3734,6 +4287,9 @@ // "menu.section.export_metadata": "Metadata", "menu.section.export_metadata": "Metadados", + // "menu.section.export_batch": "Batch Export (ZIP)", + "menu.section.export_batch": "Exportação em Lote (ZIP)", + // "menu.section.icon.access_control": "Access Control menu section", "menu.section.icon.access_control": "Seção do menu Controle de Acesso", @@ -3788,9 +4344,6 @@ // "menu.section.import_batch": "Batch Import (ZIP)", "menu.section.import_batch": "Importação em Lote (ZIP)", - // "menu.section.export_batch": "Batch Export (ZIP)", - "menu.section.export_batch": "Exportação em Lote (ZIP)", - // "menu.section.import_metadata": "Metadata", "menu.section.import_metadata": "Metadados", @@ -3874,8 +4427,10 @@ // "metadata-export-search.tooltip": "Export search results as CSV", "metadata-export-search.tooltip": "Exportar resultados de pesquisa como CSV", + // "metadata-export-search.submit.success": "The export was started successfully", "metadata-export-search.submit.success": "A exportação foi iniciada com sucesso", + // "metadata-export-search.submit.error": "Starting the export has failed", "metadata-export-search.submit.error": "Falha ao iniciar a exportação", @@ -3885,9 +4440,6 @@ // "mydspace.description": "", "mydspace.description": "", - // "mydspace.general.text-here": "here", - "mydspace.general.text-here": "aqui", - // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", "mydspace.messages.controller-help": "Selecione esta opção para enviar uma mensagem para o submetedor do item.", @@ -3966,12 +4518,15 @@ // "mydspace.search-form.placeholder": "Search in mydspace...", "mydspace.search-form.placeholder": "Procurar no meudspace...", - // "mydspace.show.workflow": "All tasks", - "mydspace.show.workflow": "Todas as tarefas", + // "mydspace.show.workflow": "Workflow tasks", + "mydspace.show.workflow": "Tarefas de fluxo de trabalho", // "mydspace.show.workspace": "Your Submissions", "mydspace.show.workspace": "Minhas Submissões", + // "mydspace.show.supervisedWorkspace": "Supervised items", (Auto-Translated) + "mydspace.show.supervisedWorkspace": "Itens supervisionados", + // "mydspace.status.mydspaceArchived": "Archived", "mydspace.status.mydspaceArchived": "Arquivado", @@ -4014,14 +4569,20 @@ // "nav.community-browse.header": "By Community", "nav.community-browse.header": "Por Comunidade", + // "nav.context-help-toggle": "Toggle context help", (Auto-Translated) + "nav.context-help-toggle": "Alternar a ajuda do contexto", + // "nav.language": "Language switch", "nav.language": "Selecionar um idioma", // "nav.login": "Log In", "nav.login": "Entrar", - // "nav.logout": "User profile menu and Log Out", - "nav.logout": "Menu do Usuário e Sair", + // "nav.user-profile-menu-and-logout": "User profile menu and Log Out", (Auto-Translated) + "nav.user-profile-menu-and-logout": "Menu do perfil de usuário e Sair", + + // "nav.logout": "Log Out", + "nav.logout": "Sair", // "nav.main.description": "Main navigation bar", "nav.main.description": "Barra de navegação principal", @@ -4035,25 +4596,33 @@ // "nav.search": "Search", "nav.search": "Buscar", + // "nav.search.button": "Submit search", (Auto-Translated) + "nav.search.button": "Enviar pesquisa", + // "nav.statistics.header": "Statistics", "nav.statistics.header": "Estatísticas", // "nav.stop-impersonating": "Stop impersonating EPerson", "nav.stop-impersonating": "Deixar de assumir o papel do EPerson", - // "nav.toggle" : "Toggle navigation", + // "nav.subscriptions": "Subscriptions", (Auto-Translated) + "nav.subscriptions": "Assinaturas", + + // "nav.toggle": "Toggle navigation", "nav.toggle": "Alternar navegação", - // "nav.user.description" : "User profile bar", + // "nav.user.description": "User profile bar", "nav.user.description": "Barra de perfil do usuário", // "none.listelement.badge": "Item", "none.listelement.badge": "Item", - // "orgunit.listelement.badge": "Organizational Unit", "orgunit.listelement.badge": "Unidade Organizacional", + // "orgunit.listelement.no-title": "Untitled", (Auto-Translated) + "orgunit.listelement.no-title": "Sem título", + // "orgunit.page.city": "City", "orgunit.page.city": "Cidade", @@ -4186,6 +4755,9 @@ // "process.new.notification.error.content": "An error occurred while creating this process", "process.new.notification.error.content": "Um erro ocorreu enquanto criava o processo", + // "process.new.notification.error.max-upload.content": "The file exceeds the maximum upload size", (Auto-Translated) + "process.new.notification.error.max-upload.content": "O arquivo excede o tamanho máximo de upload", + // "process.new.header": "Create a new process", "process.new.header": "Criar novo processo", @@ -4195,16 +4767,16 @@ // "process.new.breadcrumbs": "Create a new process", "process.new.breadcrumbs": "Criar novo processo", - // "process.detail.arguments" : "Arguments", + // "process.detail.arguments": "Arguments", "process.detail.arguments": "Argumentos", - // "process.detail.arguments.empty" : "This process doesn't contain any arguments", + // "process.detail.arguments.empty": "This process doesn't contain any arguments", "process.detail.arguments.empty": "Este processo não contêm nenhum argumento", - // "process.detail.back" : "Back", + // "process.detail.back": "Back", "process.detail.back": "Voltar", - // "process.detail.output" : "Process Output", + // "process.detail.output": "Process Output", "process.detail.output": "Saída do Processo", // "process.detail.logs.button": "Retrieve process output", @@ -4216,28 +4788,28 @@ // "process.detail.logs.none": "This process has no output", "process.detail.logs.none": "Este processo não tem saída", - // "process.detail.output-files" : "Output Files", + // "process.detail.output-files": "Output Files", "process.detail.output-files": "Arquivos de saída", - // "process.detail.output-files.empty" : "This process doesn't contain any output files", + // "process.detail.output-files.empty": "This process doesn't contain any output files", "process.detail.output-files.empty": "Este processo não contém nenhum arquivo de saída", - // "process.detail.script" : "Script", + // "process.detail.script": "Script", "process.detail.script": "Script", - // "process.detail.title" : "Process: {{ id }} - {{ name }}", + // "process.detail.title": "Process: {{ id }} - {{ name }}", "process.detail.title": "Processo: {{ id }} - {{ name }}", - // "process.detail.start-time" : "Start time", + // "process.detail.start-time": "Start time", "process.detail.start-time": "Hora de Início", - // "process.detail.end-time" : "Finish time", + // "process.detail.end-time": "Finish time", "process.detail.end-time": "Hora de Fim", - // "process.detail.status" : "Status", + // "process.detail.status": "Status", "process.detail.status": "Status", - // "process.detail.create" : "Create similar process", + // "process.detail.create": "Create similar process", "process.detail.create": "Criar processo similar", // "process.detail.actions": "Actions", @@ -4264,22 +4836,22 @@ // "process.detail.delete.error": "Something went wrong when deleting the process", "process.detail.delete.error": "Algo deu errado ao excluir o processo", - // "process.overview.table.finish" : "Finish time (UTC)", + // "process.overview.table.finish": "Finish time (UTC)", "process.overview.table.finish": "Hora de Fim (UTC)", - // "process.overview.table.id" : "Process ID", + // "process.overview.table.id": "Process ID", "process.overview.table.id": "ID do Processo", - // "process.overview.table.name" : "Name", + // "process.overview.table.name": "Name", "process.overview.table.name": "Nome", - // "process.overview.table.start" : "Start time (UTC)", + // "process.overview.table.start": "Start time (UTC)", "process.overview.table.start": "Hora de Início (UTC)", - // "process.overview.table.status" : "Status", + // "process.overview.table.status": "Status", "process.overview.table.status": "Status", - // "process.overview.table.user" : "User", + // "process.overview.table.user": "User", "process.overview.table.user": "Usuário", // "process.overview.title": "Processes Overview", @@ -4384,6 +4956,9 @@ // "profile.security.form.label.passwordrepeat": "Retype to confirm", "profile.security.form.label.passwordrepeat": "Redigite para confirmar", + // "profile.security.form.label.current-password": "Current password", (Auto-Translated) + "profile.security.form.label.current-password": "Senha atual", + // "profile.security.form.notifications.success.content": "Your changes to the password were saved.", "profile.security.form.notifications.success.content": "Suas alterações na senha foram salvas.", @@ -4393,6 +4968,9 @@ // "profile.security.form.notifications.error.title": "Error changing passwords", "profile.security.form.notifications.error.title": "Erro trocando a senha", + // "profile.security.form.notifications.error.change-failed": "An error occurred while trying to change the password. Please check if the current password is correct.", (Auto-Translated) + "profile.security.form.notifications.error.change-failed": "Ocorreu um erro ao tentar alterar a senha. Verifique se a senha atual está correta.", + // "profile.security.form.notifications.error.not-same": "The provided passwords are not the same.", "profile.security.form.notifications.error.not-same": "As senhas fornecidas não são as mesmas.", @@ -4558,8 +5136,11 @@ // "register-page.registration.email.error.required": "Please fill in an email address", "register-page.registration.email.error.required": "Por favor preencha o endereço de email", - // "register-page.registration.email.error.pattern": "Please fill in a valid email address", - "register-page.registration.email.error.pattern": "Por favor preencha com um endereço válido de email", + // "register-page.registration.email.error.not-email-form": "Please fill in a valid email address.", (Auto-Translated) + "register-page.registration.email.error.not-email-form": "Por favor preencha com um endereço de email válido.", + + // "register-page.registration.email.error.not-valid-domain": "Use email with allowed domains: {{ domains }}", (Auto-Translated) + "register-page.registration.email.error.not-valid-domain": "Use email com domínios permitidos: {{ domains }}", // "register-page.registration.email.hint": "This address will be verified and used as your login name.", "register-page.registration.email.hint": "Este endereço será verificado e usado como seu nome de login.", @@ -4579,6 +5160,30 @@ // "register-page.registration.error.content": "An error occured when registering the following email address: {{ email }}", "register-page.registration.error.content": "Um erro ocorreu enquanto registrava o seguinte endereço de email: {{ email }}", + // "register-page.registration.error.recaptcha": "Error when trying to authenticate with recaptcha", (Auto-Translated) + "register-page.registration.error.recaptcha": "Erro ao tentar autenticar com o reCAPTCHA", + + // "register-page.registration.google-recaptcha.must-accept-cookies": "In order to register you must accept the <b>Registration and Password recovery</b> (Google reCaptcha) cookies.", (Auto-Translated) + "register-page.registration.google-recaptcha.must-accept-cookies": "Para se registrar, você deve aceitar os cookies de <b> Registro e Recuperação de Senha </b> (Google reCAPTCHA).", + + // "register-page.registration.error.maildomain": "This email address is not on the list of domains who can register. Allowed domains are {{ domains }}", (Auto-Translated) + "register-page.registration.error.maildomain": "Este endereço de e-mail não está na lista de domínios que podem se registrar. Os domínios permitidos são {{ domains }}", + + // "register-page.registration.google-recaptcha.open-cookie-settings": "Open cookie settings", (Auto-Translated) + "register-page.registration.google-recaptcha.open-cookie-settings": "Abra as configurações de cookies", + + // "register-page.registration.google-recaptcha.notification.title": "Google reCaptcha", (Auto-Translated) + "register-page.registration.google-recaptcha.notification.title": "Google reCAPTCHA", + + // "register-page.registration.google-recaptcha.notification.message.error": "An error occurred during reCaptcha verification", (Auto-Translated) + "register-page.registration.google-recaptcha.notification.message.error": "Ocorreu um erro durante a verificação de reCAPTCHA", + + // "register-page.registration.google-recaptcha.notification.message.expired": "Verification expired. Please verify again.", (Auto-Translated) + "register-page.registration.google-recaptcha.notification.message.expired": "Verificação expirada. Por favor, verifique novamente.", + + // "register-page.registration.info.maildomain": "Accounts can be registered for mail addresses of the domains", (Auto-Translated) + "register-page.registration.info.maildomain": "Contas podem ser registradas para endereços de correio dos domínios", + // "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": "Nenhuma correspondência adequada foi encontrada para o tipo de relacionamento {{ type }} entre os dois itens", @@ -4645,11 +5250,11 @@ // "repository.image.logo": "Repository logo", "repository.image.logo": "Logo do Repositório", - // "repository.title.prefix": "DSpace Angular :: ", - "repository.title.prefix": "DSpace Angular :: ", + // "repository.title": "DSpace Repository", (Auto-Translated) + "repository.title": "Repositório DSpace", - // "repository.title.prefixDSpace": "DSpace Angular ::", - "repository.title.prefixDSpace": "DSpace Angular ::", + // "repository.title.prefix": "DSpace Repository :: ", + "repository.title.prefix": "Repositório DSpace :: ", // "resource-policies.add.button": "Add", "resource-policies.add.button": "Adicionar", @@ -4879,6 +5484,9 @@ // "search.filters.applied.f.birthDate.min": "Start birth date", "search.filters.applied.f.birthDate.min": "Início data de nascimento", + // "search.filters.applied.f.supervisedBy": "Supervised by", (Auto-Translated) + "search.filters.applied.f.supervisedBy": "Supervisionado por", + // "search.filters.applied.f.withdrawn": "Withdrawn", "search.filters.applied.f.withdrawn": "Retirado", @@ -4963,7 +5571,7 @@ // "search.filters.filter.dateSubmitted.label": "Search date submitted", "search.filters.filter.dateSubmitted.label": "Procurar data de submissão", - // "search.filters.filter.discoverable.head": "Private", + // "search.filters.filter.discoverable.head": "Non-discoverable", "search.filters.filter.discoverable.head": "Privado", // "search.filters.filter.withdrawn.head": "Withdrawn", @@ -5089,6 +5697,18 @@ // "search.filters.filter.submitter.label": "Search submitter", "search.filters.filter.submitter.label": "Procurar submetedor", + // "search.filters.filter.show-tree": "Browse {{ name }} tree", (Auto-Translated) + "search.filters.filter.show-tree": "Navegar na árvore {{ name }}", + + // "search.filters.filter.supervisedBy.head": "Supervised By", (Auto-Translated) + "search.filters.filter.supervisedBy.head": "Supervisionado por", + + // "search.filters.filter.supervisedBy.placeholder": "Supervised By", (Auto-Translated) + "search.filters.filter.supervisedBy.placeholder": "Supervisionado por", + + // "search.filters.filter.supervisedBy.label": "Search Supervised By", (Auto-Translated) + "search.filters.filter.supervisedBy.label": "Pesquisa supervisionada por", + // "search.filters.entityType.JournalIssue": "Journal Issue", "search.filters.entityType.JournalIssue": "Número de Revista", @@ -5110,6 +5730,21 @@ // "search.filters.discoverable.false": "Yes", "search.filters.discoverable.false": "Sim", + // "search.filters.namedresourcetype.Archived": "Archived", (Auto-Translated) + "search.filters.namedresourcetype.Archived": "Arquivado", + + // "search.filters.namedresourcetype.Validation": "Validation", (Auto-Translated) + "search.filters.namedresourcetype.Validation": "Validação", + + // "search.filters.namedresourcetype.Waiting for Controller": "Waiting for Controller", (Auto-Translated) + "search.filters.namedresourcetype.Waiting for Controller": "Esperando por controlador", + + // "search.filters.namedresourcetype.Workflow": "Workflow", (Auto-Translated) + "search.filters.namedresourcetype.Workflow": "Fluxo de trabalho", + + // "search.filters.namedresourcetype.Workspace": "Workspace", (Auto-Translated) + "search.filters.namedresourcetype.Workspace": "Área de trabalho", + // "search.filters.withdrawn.true": "Yes", "search.filters.withdrawn.true": "Sim", @@ -5257,6 +5892,9 @@ // "statistics.table.header.views": "Views", "statistics.table.header.views": "Visualizações", + // "statistics.table.no-name": "(object name could not be loaded)", (Auto-Translated) + "statistics.table.no-name": "(o nome do objeto não pôde ser carregado)", + // "submission.edit.breadcrumbs": "Edit Submission", "submission.edit.breadcrumbs": "Editar Submissão", @@ -5266,8 +5904,8 @@ // "submission.general.cancel": "Cancel", "submission.general.cancel": "Cancelar", - // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", - "submission.general.cannot_submit": "Você mão tem privilégios para fazer uma nova submissão.", + // "submission.general.cannot_submit": "You don't have permission to make a new submission.", + "submission.general.cannot_submit": "Você não tem privilégios para fazer uma nova submissão.", // "submission.general.deposit": "Deposit", "submission.general.deposit": "Depositar", @@ -5309,8 +5947,7 @@ "submission.import-external.title.Journal": "Importar uma revista de uma fonte externa", // "submission.import-external.title.JournalIssue": "Import a journal issue from an external source", - // TODO New key - Add a translation - "submission.import-external.title.JournalIssue": "Import a journal issue from an external source", + "submission.import-external.title.JournalIssue": "Importar uma edição de revista de uma fonte externa", // "submission.import-external.title.JournalVolume": "Import a journal volume from an external source", "submission.import-external.title.JournalVolume": "Importar um volume de revista de uma fonte externa", @@ -5360,6 +5997,9 @@ // "submission.import-external.source.crossref": "CrossRef", "submission.import-external.source.crossref": "CrossRef", + // "submission.import-external.source.datacite": "DataCite", (Auto-Translated) + "submission.import-external.source.datacite": "DataCite", + // "submission.import-external.source.scielo": "SciELO", "submission.import-external.source.scielo": "SciELO", @@ -5451,8 +6091,7 @@ "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal": "Importar revista remota", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Import remote journal issue", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Import remote journal issue", + "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Issue": "Importar uma edição de jornal remota", // "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Import remote journal volume", "submission.sections.describe.relationship-lookup.external-source.import-button-title.Journal Volume": "Importar volume de revista remoto", @@ -5557,16 +6196,13 @@ "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.added.new-entity": "Revista Externa importada e adicionada com sucesso à seleção", // "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Import Remote Journal Issue", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Import Remote Journal Issue", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.title": "Importar uma edição de jornal remota", // "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Successfully added local journal issue to the selection", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Successfully added local journal issue to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.local-entity": "Edição de jornal local adicionada com sucesso à seleção", // "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Successfully imported and added external journal issue to the selection", - // TODO New key - Add a translation - "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Successfully imported and added external journal issue to the selection", + "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Issue.added.new-entity": "Edição de jornal externo importada e adicionada com sucesso à seleção", // "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Import Remote Journal Volume", "submission.sections.describe.relationship-lookup.external-source.import-modal.Journal Volume.title": "Importar Volume de Revista Remoto", @@ -5612,6 +6248,7 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Local Journals ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalOfPublication": "Revistas Locais ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Local Projects ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.Project": "Projetos Locais ({{ count }})", @@ -5635,11 +6272,13 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Local Journal Issues ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalIssueOfPublication": "Números de Revista Local ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Local Journal Issues ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalIssue": "Números de Revista Local ({{ count }})", // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Local Journal Volumes ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isJournalVolumeOfPublication": "Volumes de Revista Local ({{ count }})", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Local Journal Volumes ({{ count }})", "submission.sections.describe.relationship-lookup.search-tab.tab-title.JournalVolume": "Volumes de Revista Local ({{ count }})", @@ -5679,6 +6318,9 @@ // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Funder of the Project", "submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Financiador do Projeto", + // "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author", (Auto-Translated) + "submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publicação do Autor", + // "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Funding OpenAIRE API", "submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Financiamento da API OpenAIRE", @@ -5699,11 +6341,13 @@ // "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Journal Issues", "submission.sections.describe.relationship-lookup.title.isJournalIssueOfPublication": "Números de Revista", + // "submission.sections.describe.relationship-lookup.title.JournalIssue": "Journal Issues", "submission.sections.describe.relationship-lookup.title.JournalIssue": "Números de Revista", // "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Journal Volumes", "submission.sections.describe.relationship-lookup.title.isJournalVolumeOfPublication": "Volumes de Revista", + // "submission.sections.describe.relationship-lookup.title.JournalVolume": "Journal Volumes", "submission.sections.describe.relationship-lookup.title.JournalVolume": "Volumes de Revista", @@ -5715,6 +6359,7 @@ // "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Funding Agency", "submission.sections.describe.relationship-lookup.title.isFundingAgencyOfPublication": "Agências de Financiamento", + // "submission.sections.describe.relationship-lookup.title.Project": "Projects", "submission.sections.describe.relationship-lookup.title.Project": "Projetos", @@ -5742,6 +6387,9 @@ // "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Parent Organizational Unit", "submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Unidade organizacional principal", + // "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication", (Auto-Translated) + "submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publicação", + // "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown", "submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Alternar menu suspenso", @@ -5759,6 +6407,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Selected Journal Volume", "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalVolumeOfPublication": "Volume de Revista selecionados", + // "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Selected Projects", "submission.sections.describe.relationship-lookup.selection-tab.title.Project": "Projetos Selecionados", @@ -5782,6 +6431,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Selected Issue", "submission.sections.describe.relationship-lookup.selection-tab.title.isJournalIssueOfPublication": "Problema selecionado", + // "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Selected Journal Volume", "submission.sections.describe.relationship-lookup.selection-tab.title.JournalVolume": "Volume de Revista selecionado", @@ -5790,6 +6440,7 @@ // "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Selected Funding", "submission.sections.describe.relationship-lookup.selection-tab.title.isFundingOfPublication": "Financiamento selecionado", + // "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Selected Issue", "submission.sections.describe.relationship-lookup.selection-tab.title.JournalIssue": "Problema selecionado", @@ -5910,6 +6561,24 @@ // "submission.sections.general.sections_not_valid": "There are incomplete sections.", "submission.sections.general.sections_not_valid": "Há seções incompletas.", + // "submission.sections.identifiers.info": "The following identifiers will be created for your item:", (Auto-Translated) + "submission.sections.identifiers.info": "Os seguintes identificadores serão criados para o seu item:", + + // "submission.sections.identifiers.no_handle": "No handles have been minted for this item.", (Auto-Translated) + "submission.sections.identifiers.no_handle": "Nenhuma alça foi cunhada para este item.", + + // "submission.sections.identifiers.no_doi": "No DOIs have been minted for this item.", (Auto-Translated) + "submission.sections.identifiers.no_doi": "Nenhum DOIs foi cunhado para este item.", + + // "submission.sections.identifiers.handle_label": "Handle: ", (Auto-Translated) + "submission.sections.identifiers.handle_label": "Lidar:", + + // "submission.sections.identifiers.doi_label": "DOI: ", (Auto-Translated) + "submission.sections.identifiers.doi_label": "DOI:", + + // "submission.sections.identifiers.otherIdentifiers_label": "Other identifiers: ", (Auto-Translated) + "submission.sections.identifiers.otherIdentifiers_label": "Outros identificadores:", + // "submission.sections.submit.progressbar.accessCondition": "Item access conditions", "submission.sections.submit.progressbar.accessCondition": "Condições de acesso ao Item", @@ -5931,6 +6600,9 @@ // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", "submission.sections.submit.progressbar.detect-duplicate": "Duplicados em potencial", + // "submission.sections.submit.progressbar.identifiers": "Identifiers", (Auto-Translated) + "submission.sections.submit.progressbar.identifiers": "Identificadores", + // "submission.sections.submit.progressbar.license": "Deposit license", "submission.sections.submit.progressbar.license": "Depositar licença", @@ -6076,8 +6748,7 @@ "submission.sections.accesses.form.discoverable-description": "Quando marcado, este item poderá ser descoberto na pesquisa/navegação. Quando desmarcado, o item estará disponível apenas por meio de um link direto e nunca aparecerá na pesquisa/navegação.", // "submission.sections.accesses.form.discoverable-label": "Discoverable", - // TODO New key - Add a translation - "submission.sections.accesses.form.discoverable-label": "Discoverable", + "submission.sections.accesses.form.discoverable-label": "Público", // "submission.sections.accesses.form.access-condition-label": "Access condition type", "submission.sections.accesses.form.access-condition-label": "Tipo de condição de acesso", @@ -6118,16 +6789,15 @@ // "submission.sections.accesses.form.until-placeholder": "Until", "submission.sections.accesses.form.until-placeholder": "Até", - // "submission.sections.license.granted-label": "Confirmo a licença acima", - "submission.sections.license.granted-label": "I confirm the license above", + // "submission.sections.license.granted-label": "I confirm the license above", + "submission.sections.license.granted-label": "Confirmo a licença acima", // "submission.sections.license.required": "You must accept the license", "submission.sections.license.required": "Você deve aceitar a licença", - // "submission.sections.license.notgranted": "You must accept the license", + // "submission.sections.license.notgranted": "You must accept the license", "submission.sections.license.notgranted": "Você deve aceitar a licença", - // "submission.sections.sherpa.publication.information": "Publication information", "submission.sections.sherpa.publication.information": "Informações de publicação", @@ -6215,8 +6885,8 @@ // "submission.workflow.generic.delete": "Delete", "submission.workflow.generic.delete": "Apagar", - // "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 você gostaria de descartar este item, selecione \"Apagar\". Você será questionado para confirmar.", + // "submission.workflow.generic.delete-help": "Select this option to discard this item. You will then be asked to confirm it.", + "submission.workflow.generic.delete-help": "Selecione esta opção para descartar este item. Em seguida, será solicitada confirmção.", // "submission.workflow.generic.edit": "Edit", "submission.workflow.generic.edit": "Editar", @@ -6230,6 +6900,18 @@ // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", "submission.workflow.generic.view-help": "Selecione esta opção para ver o metadados do item.", + // "submission.workflow.generic.submit_select_reviewer": "Select Reviewer", (Auto-Translated) + "submission.workflow.generic.submit_select_reviewer": "Selecione Revisor", + + // "submission.workflow.generic.submit_select_reviewer-help": "", (Auto-Translated) + "submission.workflow.generic.submit_select_reviewer-help": "", + + // "submission.workflow.generic.submit_score": "Rate", (Auto-Translated) + "submission.workflow.generic.submit_score": "Avaliar", + + // "submission.workflow.generic.submit_score-help": "", (Auto-Translated) + "submission.workflow.generic.submit_score-help": "", + // "submission.workflow.tasks.claimed.approve": "Approve", "submission.workflow.tasks.claimed.approve": "Aprovar", @@ -6242,6 +6924,12 @@ // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", "submission.workflow.tasks.claimed.edit_help": "Selecione esta opção para modificar os metadados do item.", + // "submission.workflow.tasks.claimed.decline": "Decline", (Auto-Translated) + "submission.workflow.tasks.claimed.decline": "Recusar", + + // "submission.workflow.tasks.claimed.decline_help": "", (Auto-Translated) + "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.", "submission.workflow.tasks.claimed.reject.reason.info": "Por favor informe o motivo pela rejeição da submissão na caixa abaixo, indicando se o submetedor pode corrigir um problema e reenviar.", @@ -6296,6 +6984,114 @@ // "submission.workspace.generic.view-help": "Select this option to view the item's metadata.", "submission.workspace.generic.view-help": "Selecione esta opção para visualizar os metadados do item.", + // "submitter.empty": "N/A", (Auto-Translated) + "submitter.empty": "N/D", + + // "subscriptions.title": "Subscriptions", (Auto-Translated) + "subscriptions.title": "Assinaturas", + + // "subscriptions.item": "Subscriptions for items", (Auto-Translated) + "subscriptions.item": "Assinaturas para itens", + + // "subscriptions.collection": "Subscriptions for collections", (Auto-Translated) + "subscriptions.collection": "Assinaturas para coleções", + + // "subscriptions.community": "Subscriptions for communities", (Auto-Translated) + "subscriptions.community": "Assinaturas para comunidades", + + // "subscriptions.subscription_type": "Subscription type", (Auto-Translated) + "subscriptions.subscription_type": "Tipo de assinatura", + + // "subscriptions.frequency": "Subscription frequency", (Auto-Translated) + "subscriptions.frequency": "Frequência de assinatura", + + // "subscriptions.frequency.D": "Daily", (Auto-Translated) + "subscriptions.frequency.D": "Diáriamente", + + // "subscriptions.frequency.M": "Monthly", (Auto-Translated) + "subscriptions.frequency.M": "Mensalmente", + + // "subscriptions.frequency.W": "Weekly", (Auto-Translated) + "subscriptions.frequency.W": "Semanalmente", + + // "subscriptions.tooltip": "Subscribe", (Auto-Translated) + "subscriptions.tooltip": "Se inscrever", + + // "subscriptions.modal.title": "Subscriptions", (Auto-Translated) + "subscriptions.modal.title": "Assinaturas", + + // "subscriptions.modal.type-frequency": "Type and frequency", (Auto-Translated) + "subscriptions.modal.type-frequency": "Tipo e frequência", + + // "subscriptions.modal.close": "Close", (Auto-Translated) + "subscriptions.modal.close": "Fechar", + + // "subscriptions.modal.delete-info": "To remove this subscription, please visit the "Subscriptions" page under your user profile", (Auto-Translated) + "subscriptions.modal.delete-info": "Para remover esta assinatura, visite a página \"Assinaturas\" no seu perfil de usuário", + + // "subscriptions.modal.new-subscription-form.type.content": "Content", (Auto-Translated) + "subscriptions.modal.new-subscription-form.type.content": "Conteúdo", + + // "subscriptions.modal.new-subscription-form.frequency.D": "Daily", (Auto-Translated) + "subscriptions.modal.new-subscription-form.frequency.D": "Diáriamente", + + // "subscriptions.modal.new-subscription-form.frequency.W": "Weekly", (Auto-Translated) + "subscriptions.modal.new-subscription-form.frequency.W": "Semanalmente", + + // "subscriptions.modal.new-subscription-form.frequency.M": "Monthly", (Auto-Translated) + "subscriptions.modal.new-subscription-form.frequency.M": "Mensalmente", + + // "subscriptions.modal.new-subscription-form.submit": "Submit", (Auto-Translated) + "subscriptions.modal.new-subscription-form.submit": "Enviar", + + // "subscriptions.modal.new-subscription-form.processing": "Processing...", (Auto-Translated) + "subscriptions.modal.new-subscription-form.processing": "Em processamento...", + + // "subscriptions.modal.create.success": "Subscribed to {{ type }} successfully.", (Auto-Translated) + "subscriptions.modal.create.success": "Inscrito em {{type}} com sucesso.", + + // "subscriptions.modal.delete.success": "Subscription deleted successfully", (Auto-Translated) + "subscriptions.modal.delete.success": "Assinatura excluída com sucesso", + + // "subscriptions.modal.update.success": "Subscription to {{ type }} updated successfully", (Auto-Translated) + "subscriptions.modal.update.success": "Assinatura para {{type}} atualizado com sucesso", + + // "subscriptions.modal.create.error": "An error occurs during the subscription creation", (Auto-Translated) + "subscriptions.modal.create.error": "Um erro ocorre durante a criação de assinatura", + + // "subscriptions.modal.delete.error": "An error occurs during the subscription delete", (Auto-Translated) + "subscriptions.modal.delete.error": "Um erro ocorre durante a exclusão de assinatura", + + // "subscriptions.modal.update.error": "An error occurs during the subscription update", (Auto-Translated) + "subscriptions.modal.update.error": "Um erro ocorre durante a atualização da assinatura", + + // "subscriptions.table.dso": "Subject", (Auto-Translated) + "subscriptions.table.dso": "Assunto", + + // "subscriptions.table.subscription_type": "Subscription Type", (Auto-Translated) + "subscriptions.table.subscription_type": "Tipo de assinatura", + + // "subscriptions.table.subscription_frequency": "Subscription Frequency", (Auto-Translated) + "subscriptions.table.subscription_frequency": "Frequência de assinatura", + + // "subscriptions.table.action": "Action", (Auto-Translated) + "subscriptions.table.action": "Ação", + + // "subscriptions.table.edit": "Edit", (Auto-Translated) + "subscriptions.table.edit": "Editar", + + // "subscriptions.table.delete": "Delete", (Auto-Translated) + "subscriptions.table.delete": "Excluir", + + // "subscriptions.table.not-available": "Not available", (Auto-Translated) + "subscriptions.table.not-available": "Não disponível", + + // "subscriptions.table.not-available-message": "The subscribed item has been deleted, or you don't currently have the permission to view it", (Auto-Translated) + "subscriptions.table.not-available-message": "O item inscrito foi excluído, ou você não tem permissão para vê-lo", + + // "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.", (Auto-Translated) + "subscriptions.table.empty.message": "Você não tem nenhuma assinatura no momento. Para se inscrever em atualizações por e-mail para uma comunidade ou coleção, use o botão de assinatura na página do objeto.", + // "thumbnail.default.alt": "Thumbnail Image", "thumbnail.default.alt": "Imagem de Miniatura", @@ -6344,6 +7140,9 @@ // "vocabulary-treeview.tree.description.srsc": "Research Subject Categories", "vocabulary-treeview.tree.description.srsc": "Categorias de Assuntos de Pesquisa", + // "vocabulary-treeview.info": "Select a subject to add as search filter", (Auto-Translated) + "vocabulary-treeview.info": "Selecione um assunto para adicionar como filtro de pesquisa", + // "uploader.browse": "browse", "uploader.browse": "Navegar", @@ -6356,8 +7155,8 @@ // "uploader.or": ", or ", "uploader.or": ", ou ", - // "uploader.processing": "Processing", - "uploader.processing": "Processando", + // "uploader.processing": "Processing uploaded file(s)... (it's now safe to close this page)", + "uploader.processing": "Processando arquivo(s) enviado(s)... (agora é seguro fechar esta página)", // "uploader.queue-length": "Queue length", "uploader.queue-length": "Tamanho da fila", @@ -6371,6 +7170,9 @@ // "virtual-metadata.delete-relationship.modal-head": "Select the items for which you want to save the virtual metadata as real metadata", "virtual-metadata.delete-relationship.modal-head": "Selecione os itens para os quais você deseja salvar os metadados virtuais como metadados reais", + // "supervisedWorkspace.search.results.head": "Supervised Items", (Auto-Translated) + "supervisedWorkspace.search.results.head": "Itens supervisionados", + // "workspace.search.results.head": "Your submissions", "workspace.search.results.head": "Suas submissões", @@ -6380,6 +7182,9 @@ // "workflow.search.results.head": "Workflow tasks", "workflow.search.results.head": "Tarefas do Workflow", + // "supervision.search.results.head": "Workflow and Workspace tasks", (Auto-Translated) + "supervision.search.results.head": "Tarefas de fluxo de trabalho e espaço de trabalho", + // "workflow-item.edit.breadcrumbs": "Edit workflowitem", "workflow-item.edit.breadcrumbs": "Editar item do workflow", @@ -6443,6 +7248,81 @@ // "workspace-item.view.title": "Workspace View", "workspace-item.view.title": "Visualização da Área de Trabalho (Workspace)", + // "workspace-item.delete.breadcrumbs": "Workspace Delete", (Auto-Translated) + "workspace-item.delete.breadcrumbs": "Excluir espaço de trabalho", + + // "workspace-item.delete.header": "Delete workspace item", (Auto-Translated) + "workspace-item.delete.header": "Excluir item do espaço de trabalho", + + // "workspace-item.delete.button.confirm": "Delete", (Auto-Translated) + "workspace-item.delete.button.confirm": "Excluir", + + // "workspace-item.delete.button.cancel": "Cancel", (Auto-Translated) + "workspace-item.delete.button.cancel": "Cancelar", + + // "workspace-item.delete.notification.success.title": "Deleted", (Auto-Translated) + "workspace-item.delete.notification.success.title": "Excluído", + + // "workspace-item.delete.title": "This workspace item was successfully deleted", (Auto-Translated) + "workspace-item.delete.title": "Este item do espaço de trabalho foi excluído com sucesso", + + // "workspace-item.delete.notification.error.title": "Something went wrong", (Auto-Translated) + "workspace-item.delete.notification.error.title": "Algo deu errado", + + // "workspace-item.delete.notification.error.content": "The workspace item could not be deleted", (Auto-Translated) + "workspace-item.delete.notification.error.content": "O item do espaço de trabalho não pôde ser excluído", + + // "workflow-item.advanced.title": "Advanced workflow", (Auto-Translated) + "workflow-item.advanced.title": "Fluxo de trabalho avançado", + + // "workflow-item.selectrevieweraction.notification.success.title": "Selected reviewer", (Auto-Translated) + "workflow-item.selectrevieweraction.notification.success.title": "Revisor selecionado", + + // "workflow-item.selectrevieweraction.notification.success.content": "The reviewer for this workflow item has been successfully selected", (Auto-Translated) + "workflow-item.selectrevieweraction.notification.success.content": "O revisor deste item de fluxo de trabalho foi selecionado com sucesso", + + // "workflow-item.selectrevieweraction.notification.error.title": "Something went wrong", (Auto-Translated) + "workflow-item.selectrevieweraction.notification.error.title": "Algo deu errado", + + // "workflow-item.selectrevieweraction.notification.error.content": "Couldn't select the reviewer for this workflow item", (Auto-Translated) + "workflow-item.selectrevieweraction.notification.error.content": "Não foi possível selecionar o revisor para este item de fluxo de trabalho", + + // "workflow-item.selectrevieweraction.title": "Select Reviewer", (Auto-Translated) + "workflow-item.selectrevieweraction.title": "Selecione Revisor", + + // "workflow-item.selectrevieweraction.header": "Select Reviewer", (Auto-Translated) + "workflow-item.selectrevieweraction.header": "Selecione Revisor", + + // "workflow-item.selectrevieweraction.button.cancel": "Cancel", (Auto-Translated) + "workflow-item.selectrevieweraction.button.cancel": "Cancelar", + + // "workflow-item.selectrevieweraction.button.confirm": "Confirm", (Auto-Translated) + "workflow-item.selectrevieweraction.button.confirm": "Confirmar", + + // "workflow-item.scorereviewaction.notification.success.title": "Rating review", (Auto-Translated) + "workflow-item.scorereviewaction.notification.success.title": "Revisão de classificação", + + // "workflow-item.scorereviewaction.notification.success.content": "The rating for this item workflow item has been successfully submitted", (Auto-Translated) + "workflow-item.scorereviewaction.notification.success.content": "A classificação para este item de fluxo de trabalho do item foi enviada com sucesso", + + // "workflow-item.scorereviewaction.notification.error.title": "Something went wrong", (Auto-Translated) + "workflow-item.scorereviewaction.notification.error.title": "Algo deu errado", + + // "workflow-item.scorereviewaction.notification.error.content": "Couldn't rate this item", (Auto-Translated) + "workflow-item.scorereviewaction.notification.error.content": "Não foi possível avaliar este item", + + // "workflow-item.scorereviewaction.title": "Rate this item", (Auto-Translated) + "workflow-item.scorereviewaction.title": "Avaliar este item", + + // "workflow-item.scorereviewaction.header": "Rate this item", (Auto-Translated) + "workflow-item.scorereviewaction.header": "Avaliar este item", + + // "workflow-item.scorereviewaction.button.cancel": "Cancel", (Auto-Translated) + "workflow-item.scorereviewaction.button.cancel": "Cancelar", + + // "workflow-item.scorereviewaction.button.confirm": "Confirm", (Auto-Translated) + "workflow-item.scorereviewaction.button.confirm": "Confirmar", + // "idle-modal.header": "Session will expire soon", "idle-modal.header": "Sessão vai expirar em breve", @@ -6455,7 +7335,7 @@ // "idle-modal.extend-session": "Extend session", "idle-modal.extend-session": "Estender sessão", - // "researcher.profile.action.processing" : "Processing...", + // "researcher.profile.action.processing": "Processing...", "researcher.profile.action.processing": "Processando...", // "researcher.profile.associated": "Researcher profile associated", @@ -6488,10 +7368,10 @@ // "researcher.profile.view": "View", "researcher.profile.view": "Ver", - // "researcher.profile.private.visibility" : "PRIVATE", + // "researcher.profile.private.visibility": "PRIVATE", "researcher.profile.private.visibility": "PRIVADO", - // "researcher.profile.public.visibility" : "PUBLIC", + // "researcher.profile.public.visibility": "PUBLIC", "researcher.profile.public.visibility": "PÚBLICO", // "researcher.profile.status": "Status:", @@ -6500,16 +7380,16 @@ // "researcherprofile.claim.not-authorized": "You are not authorized to claim this item. For more details contact the administrator(s).", "researcherprofile.claim.not-authorized": "Você não está autorizado a reivindicar este item. Para mais detalhes, entre em contato com o(s) administrador(es)", - // "researcherprofile.error.claim.body" : "An error occurred while claiming the profile, please try again later", + // "researcherprofile.error.claim.body": "An error occurred while claiming the profile, please try again later", "researcherprofile.error.claim.body": "Ocorreu um erro ao reivindicar o perfil, tente novamente mais tarde", - // "researcherprofile.error.claim.title" : "Error", + // "researcherprofile.error.claim.title": "Error", "researcherprofile.error.claim.title": "Erro", - // "researcherprofile.success.claim.body" : "Profile claimed with success", + // "researcherprofile.success.claim.body": "Profile claimed with success", "researcherprofile.success.claim.body": "Perfil reivindicado com sucesso", - // "researcherprofile.success.claim.title" : "Success", + // "researcherprofile.success.claim.title": "Success", "researcherprofile.success.claim.title": "Successo", // "person.page.orcid.create": "Create an ORCID ID", @@ -6518,7 +7398,7 @@ // "person.page.orcid.granted-authorizations": "Granted authorizations", "person.page.orcid.granted-authorizations": "Autorizações concedidas", - // "person.page.orcid.grant-authorizations" : "Grant authorizations", + // "person.page.orcid.grant-authorizations": "Grant authorizations", "person.page.orcid.grant-authorizations": "Conceder autorizações", // "person.page.orcid.link": "Connect to ORCID ID", @@ -6566,43 +7446,43 @@ // "person.page.orcid.save.preference.changes": "Update settings", "person.page.orcid.save.preference.changes": "Atualizar configurações", - // "person.page.orcid.sync-profile.affiliation" : "Affiliation", + // "person.page.orcid.sync-profile.affiliation": "Affiliation", "person.page.orcid.sync-profile.affiliation": "Afiliação", - // "person.page.orcid.sync-profile.biographical" : "Biographical data", + // "person.page.orcid.sync-profile.biographical": "Biographical data", "person.page.orcid.sync-profile.biographical": "Dados biográficos", - // "person.page.orcid.sync-profile.education" : "Education", + // "person.page.orcid.sync-profile.education": "Education", "person.page.orcid.sync-profile.education": "Educação", - // "person.page.orcid.sync-profile.identifiers" : "Identifiers", + // "person.page.orcid.sync-profile.identifiers": "Identifiers", "person.page.orcid.sync-profile.identifiers": "Identificadores", - // "person.page.orcid.sync-fundings.all" : "All fundings", + // "person.page.orcid.sync-fundings.all": "All fundings", "person.page.orcid.sync-fundings.all": "Todos financiamentos", - // "person.page.orcid.sync-fundings.mine" : "My fundings", + // "person.page.orcid.sync-fundings.mine": "My fundings", "person.page.orcid.sync-fundings.mine": "Meus financiamentos", - // "person.page.orcid.sync-fundings.my_selected" : "Selected fundings", + // "person.page.orcid.sync-fundings.my_selected": "Selected fundings", "person.page.orcid.sync-fundings.my_selected": "Financiamentos selecionados", - // "person.page.orcid.sync-fundings.disabled" : "Disabled", + // "person.page.orcid.sync-fundings.disabled": "Disabled", "person.page.orcid.sync-fundings.disabled": "Desabilitado", - // "person.page.orcid.sync-publications.all" : "All publications", + // "person.page.orcid.sync-publications.all": "All publications", "person.page.orcid.sync-publications.all": "Todas publicações", - // "person.page.orcid.sync-publications.mine" : "My publications", + // "person.page.orcid.sync-publications.mine": "My publications", "person.page.orcid.sync-publications.mine": "Minhas publicações", - // "person.page.orcid.sync-publications.my_selected" : "Selected publications", + // "person.page.orcid.sync-publications.my_selected": "Selected publications", "person.page.orcid.sync-publications.my_selected": "Publicações selecionadas", - // "person.page.orcid.sync-publications.disabled" : "Disabled", + // "person.page.orcid.sync-publications.disabled": "Disabled", "person.page.orcid.sync-publications.disabled": "Desabilitado", - // "person.page.orcid.sync-queue.discard" : "Discard the change and do not synchronize with the ORCID registry", + // "person.page.orcid.sync-queue.discard": "Discard the change and do not synchronize with the ORCID registry", "person.page.orcid.sync-queue.discard": "Descarte a alteração e não sincronize com o registro ORCID", // "person.page.orcid.sync-queue.discard.error": "The discarding of the ORCID queue record failed", @@ -6614,13 +7494,13 @@ // "person.page.orcid.sync-queue.empty-message": "The ORCID queue registry is empty", "person.page.orcid.sync-queue.empty-message": "O registro da fila ORCID está vazio", - // "person.page.orcid.sync-queue.table.header.type" : "Type", + // "person.page.orcid.sync-queue.table.header.type": "Type", "person.page.orcid.sync-queue.table.header.type": "Tipo", - // "person.page.orcid.sync-queue.table.header.description" : "Description", + // "person.page.orcid.sync-queue.table.header.description": "Description", "person.page.orcid.sync-queue.table.header.description": "Descrição", - // "person.page.orcid.sync-queue.table.header.action" : "Action", + // "person.page.orcid.sync-queue.table.header.action": "Action", "person.page.orcid.sync-queue.table.header.action": "Ação", // "person.page.orcid.sync-queue.description.affiliation": "Affiliations", @@ -6686,7 +7566,7 @@ // "person.page.orcid.sync-queue.tooltip.researcher_urls": "Researcher url", "person.page.orcid.sync-queue.tooltip.researcher_urls": "URL do pesquisador", - // "person.page.orcid.sync-queue.send" : "Synchronize with ORCID registry", + // "person.page.orcid.sync-queue.send": "Synchronize with ORCID registry", "person.page.orcid.sync-queue.send": "Sincronize com o registro ORCID", // "person.page.orcid.sync-queue.send.unauthorized-error.title": "The submission to ORCID failed for missing authorizations.", @@ -6740,7 +7620,7 @@ // "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "The organization's name is required", "person.page.orcid.sync-queue.send.validation-error.organization.name-required": "O nome da organização é obrigatório", - // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid" : "The publication date must be one year after 1900", + // "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "The publication date must be one year after 1900", "person.page.orcid.sync-queue.send.validation-error.publication.date-invalid": "A data de publicação deve ser um ano após 1900", // "person.page.orcid.sync-queue.send.validation-error.organization.address-required": "The organization to be sent requires an address", @@ -6818,10 +7698,156 @@ // "person.orcid.registry.queue": "ORCID Registry Queue", "person.orcid.registry.queue": "ORCID Registro na Fila", - // "person.orcid.registry.auth": "ORCID Autorizações", - "person.orcid.registry.auth": "ORCID Autorizações", + // "person.orcid.registry.auth": "ORCID Authorizations", + "person.orcid.registry.auth": "Autorizações ORCID", // "home.recent-submissions.head": "Recent Submissions", "home.recent-submissions.head": "Submissões Recentes", + // "listable-notification-object.default-message": "This object couldn't be retrieved", (Auto-Translated) + "listable-notification-object.default-message": "Este objeto não pôde ser recuperado", + + // "system-wide-alert-banner.retrieval.error": "Something went wrong retrieving the system-wide alert banner", (Auto-Translated) + "system-wide-alert-banner.retrieval.error": "Algo deu errado recuperar o banner de alerta em todo o sistema", + + // "system-wide-alert-banner.countdown.prefix": "In", (Auto-Translated) + "system-wide-alert-banner.countdown.prefix": "Em", + + // "system-wide-alert-banner.countdown.days": "{{days}} day(s),", (Auto-Translated) + "system-wide-alert-banner.countdown.days": "{{days}} dia (s),", + + // "system-wide-alert-banner.countdown.hours": "{{hours}} hour(s) and", (Auto-Translated) + "system-wide-alert-banner.countdown.hours": "{{hours}} hora (s) e", + + // "system-wide-alert-banner.countdown.minutes": "{{minutes}} minute(s):", (Auto-Translated) + "system-wide-alert-banner.countdown.minutes": "{{minutes}} minuto (s):", + + // "menu.section.system-wide-alert": "System-wide Alert", (Auto-Translated) + "menu.section.system-wide-alert": "Alerta em todo o sistema", + + // "system-wide-alert.form.header": "System-wide Alert", (Auto-Translated) + "system-wide-alert.form.header": "Alerta em todo o sistema", + + // "system-wide-alert-form.retrieval.error": "Something went wrong retrieving the system-wide alert", (Auto-Translated) + "system-wide-alert-form.retrieval.error": "Algo deu errado recuperando o alerta em todo o sistema", + + // "system-wide-alert.form.cancel": "Cancel", (Auto-Translated) + "system-wide-alert.form.cancel": "Cancelar", + + // "system-wide-alert.form.save": "Save", (Auto-Translated) + "system-wide-alert.form.save": "Salvar", + + // "system-wide-alert.form.label.active": "ACTIVE", (Auto-Translated) + "system-wide-alert.form.label.active": "ATIVO", + + // "system-wide-alert.form.label.inactive": "INACTIVE", (Auto-Translated) + "system-wide-alert.form.label.inactive": "INATIVO", + + // "system-wide-alert.form.error.message": "The system wide alert must have a message", (Auto-Translated) + "system-wide-alert.form.error.message": "O alerta amplo do sistema deve ter uma mensagem", + + // "system-wide-alert.form.label.message": "Alert message", (Auto-Translated) + "system-wide-alert.form.label.message": "Mensagem de alerta", + + // "system-wide-alert.form.label.countdownTo.enable": "Enable a countdown timer", (Auto-Translated) + "system-wide-alert.form.label.countdownTo.enable": "Ativar um cronômetro de contagem regressiva", + + // "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.", (Auto-Translated) + "system-wide-alert.form.label.countdownTo.hint": "Dica: defina um cronômetro de contagem regressiva. Quando ativado, uma data pode ser definida no futuro e o banner de alerta em todo o sistema executará uma contagem regressiva para a data definida. Quando esse timer terminar, ele desaparecerá do alerta. O servidor NÃO será interrompido automaticamente.", + + // "system-wide-alert.form.label.preview": "System-wide alert preview", (Auto-Translated) + "system-wide-alert.form.label.preview": "Visualização de alerta em todo o sistema", + + // "system-wide-alert.form.update.success": "The system-wide alert was successfully updated", (Auto-Translated) + "system-wide-alert.form.update.success": "O alerta em todo o sistema foi atualizado com sucesso", + + // "system-wide-alert.form.update.error": "Something went wrong when updating the system-wide alert", (Auto-Translated) + "system-wide-alert.form.update.error": "Algo deu errado ao atualizar o alerta em todo o sistema", + + // "system-wide-alert.form.create.success": "The system-wide alert was successfully created", (Auto-Translated) + "system-wide-alert.form.create.success": "O alerta em todo o sistema foi criado com sucesso", + + // "system-wide-alert.form.create.error": "Something went wrong when creating the system-wide alert", (Auto-Translated) + "system-wide-alert.form.create.error": "Algo deu errado ao criar o alerta em todo o sistema", + + // "admin.system-wide-alert.breadcrumbs": "System-wide Alerts", (Auto-Translated) + "admin.system-wide-alert.breadcrumbs": "Alertas em todo o sistema", + + // "admin.system-wide-alert.title": "System-wide Alerts", (Auto-Translated) + "admin.system-wide-alert.title": "Alertas em todo o sistema", + + // "item-access-control-title": "This form allows you to perform changes to the access conditions of the item's metadata or its bitstreams.", (Auto-Translated) + "item-access-control-title": "Este formulário permite que você execute alterações nas condições de acesso dos metadados do item ou seus bitstreams.", + + // "collection-access-control-title": "This form allows you to perform changes to the access conditions of all the items owned by this collection. Changes may be performed to either all Item metadata or all content (bitstreams).", (Auto-Translated) + "collection-access-control-title": "Este formulário permite executar alterações nas condições de acesso de todos os itens de propriedade desta coleção. As alterações podem ser realizadas em todos os metadados do item ou em todo o conteúdo (BitStreams).", + + // "community-access-control-title": "This form allows you to perform changes to the access conditions of all the items owned by any collection under this community. Changes may be performed to either all Item metadata or all content (bitstreams).", (Auto-Translated) + "community-access-control-title": "Este formulário permite executar alterações nas condições de acesso de todos os itens pertencentes a qualquer coleção nesta comunidade. As alterações podem ser realizadas em todos os metadados do item ou em todo o conteúdo (BitStreams).", + + // "access-control-item-header-toggle": "Item's Metadata", (Auto-Translated) + "access-control-item-header-toggle": "Metadados do item", + + // "access-control-bitstream-header-toggle": "Bitstreams", (Auto-Translated) + "access-control-bitstream-header-toggle": "BitStreams", + + // "access-control-mode": "Mode", (Auto-Translated) + "access-control-mode": "Modo", + + // "access-control-access-conditions": "Access conditions", (Auto-Translated) + "access-control-access-conditions": "Condições de acesso", + + // "access-control-no-access-conditions-warning-message": "Currently, no access conditions are specified below. If executed, this will replace the current access conditions with the default access conditions inherited from the owning collection.", (Auto-Translated) + "access-control-no-access-conditions-warning-message": "Atualmente, nenhuma condição de acesso é especificada abaixo. Se executado, isso substituirá as condições de acesso atuais pelas condições de acesso padrão herdadas da coleção proprietária.", + + // "access-control-replace-all": "Replace access conditions", (Auto-Translated) + "access-control-replace-all": "Substitua as condições de acesso", + + // "access-control-add-to-existing": "Add to existing ones", (Auto-Translated) + "access-control-add-to-existing": "Adicione aos existentes", + + // "access-control-limit-to-specific": "Limit the changes to specific bitstreams", (Auto-Translated) + "access-control-limit-to-specific": "Limitar as alterações em transmissões específicas", + + // "access-control-process-all-bitstreams": "Update all the bitstreams in the item", (Auto-Translated) + "access-control-process-all-bitstreams": "Atualize todos os streams de bits no item", + + // "access-control-bitstreams-selected": "bitstreams selected", (Auto-Translated) + "access-control-bitstreams-selected": "BitStreams selecionados", + + // "access-control-cancel": "Cancel", (Auto-Translated) + "access-control-cancel": "Cancelar", + + // "access-control-execute": "Execute", (Auto-Translated) + "access-control-execute": "Executar", + + // "access-control-add-more": "Add more", (Auto-Translated) + "access-control-add-more": "Adicione mais", + + // "access-control-select-bitstreams-modal.title": "Select bitstreams", (Auto-Translated) + "access-control-select-bitstreams-modal.title": "Selecione BitStreams", + + // "access-control-select-bitstreams-modal.no-items": "No items to show.", (Auto-Translated) + "access-control-select-bitstreams-modal.no-items": "Sem itens para mostrar.", + + // "access-control-select-bitstreams-modal.close": "Close", (Auto-Translated) + "access-control-select-bitstreams-modal.close": "Fechar", + + // "access-control-option-label": "Access condition type", (Auto-Translated) + "access-control-option-label": "Tipo de condição de acesso", + + // "access-control-option-note": "Choose an access condition to apply to selected objects.", (Auto-Translated) + "access-control-option-note": "Escolha uma condição de acesso para aplicar em objetos selecionados.", + + // "access-control-option-start-date": "Grant access from", (Auto-Translated) + "access-control-option-start-date": "Conceder acesso de", + + // "access-control-option-start-date-note": "Select the date from which the related access condition is applied", (Auto-Translated) + "access-control-option-start-date-note": "Selecione a data a partir da qual a condição de acesso relacionada é aplicada", + + // "access-control-option-end-date": "Grant access until", (Auto-Translated) + "access-control-option-end-date": "Conceder acesso até", + + // "access-control-option-end-date-note": "Select the date until which the related access condition is applied", (Auto-Translated) + "access-control-option-end-date-note": "Selecione a data até a qual a condição de acesso relacionada é aplicada", } From 07516985af7a1e66e3362d579a6623e8f20f7d59 Mon Sep 17 00:00:00 2001 From: Marco Aurelio Cardoso <marcoaurelio.cardoso@gmail.com> Date: Sun, 29 Oct 2023 07:18:04 -0300 Subject: [PATCH 179/282] fix(pt-BR.json5): fix and update the language file and previous errors Fix and update the pt-BR language file and the previous errors (cherry picked from commit 8b48a0b1180a0cf48531b906d410cab35263ab81) --- src/assets/i18n/pt-BR.json5 | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/assets/i18n/pt-BR.json5 b/src/assets/i18n/pt-BR.json5 index 79d332baced..ce35f1ec055 100644 --- a/src/assets/i18n/pt-BR.json5 +++ b/src/assets/i18n/pt-BR.json5 @@ -962,23 +962,23 @@ // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remove / Add", (Auto-Translated) "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit": "Remover / adicionar", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remove member with name "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remova o membro com o nome "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remove member with name \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.remove": "Remova o membro com o nome \"{{name}}\"", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Successfully added member: "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Membro adicionado com sucesso: "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Successfully added member: \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.addMember": "Membro adicionado com sucesso: \"{{name}}\"", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Failed to add member: "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Falha ao adicionar membro: "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Failed to add member: \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.addMember": "Falha ao adicionar membro: \"{{name}}\"", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Successfully deleted member: "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Membro excluído com sucesso: "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Successfully deleted member: \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.success.deleteMember": "Membro excluído com sucesso: \"{{name}}\"", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Failed to delete member: "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Falha ao excluir membro: "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Failed to delete member: \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.deleteMember": "Falha ao excluir membro: \"{{name}}\"", - // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Add member with name "{{name}}"", (Auto-Translated) - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Adicionar membro com o nome "{{name}}"", + // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Add member with name \"{{name}}\"", (Auto-Translated) + "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.edit.buttons.add": "Adicionar membro com o nome \"{{name}}\"", // "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "No current active group, submit a name first.", (Auto-Translated) "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.notification.failure.noActiveGroup": "Nenhum grupo ativo atual, envie um nome primeiro.", @@ -2321,8 +2321,8 @@ // "confirmation-modal.delete-subscription.header": "Delete Subscription", (Auto-Translated) "confirmation-modal.delete-subscription.header": "Excluir assinatura", - // "confirmation-modal.delete-subscription.info": "Are you sure you want to delete subscription for "{{ dsoName }}"", (Auto-Translated) - "confirmation-modal.delete-subscription.info": "Tem certeza de que deseja excluir a assinatura para "{{ dsoName }}"", + // "confirmation-modal.delete-subscription.info": "Are you sure you want to delete subscription for \"{{ dsoName }}\"", (Auto-Translated) + "confirmation-modal.delete-subscription.info": "Tem certeza de que deseja excluir a assinatura para \"{{ dsoName }}\"", // "confirmation-modal.delete-subscription.cancel": "Cancel", (Auto-Translated) "confirmation-modal.delete-subscription.cancel": "Cancelar", @@ -3555,11 +3555,11 @@ // "workflow-item.search.result.delete-supervision.modal.confirm": "Delete", (Auto-Translated) "workflow-item.search.result.delete-supervision.modal.confirm": "Excluir", - // "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order "{{name}}"", (Auto-Translated) - "workflow-item.search.result.notification.deleted.success": "Ordem de supervisão excluída com sucesso "{{name}}"", + // "workflow-item.search.result.notification.deleted.success": "Successfully deleted supervision order \"{{name}}\"", (Auto-Translated) + "workflow-item.search.result.notification.deleted.success": "Ordem de supervisão excluída com sucesso \"{{name}}\"", - // "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order "{{name}}"", (Auto-Translated) - "workflow-item.search.result.notification.deleted.failure": "Falha ao excluir a ordem de supervisão "{{name}}"", + // "workflow-item.search.result.notification.deleted.failure": "Failed to delete supervision order \"{{name}}\"", (Auto-Translated) + "workflow-item.search.result.notification.deleted.failure": "Falha ao excluir a ordem de supervisão \"{{name}}\"", // "workflow-item.search.result.list.element.supervised-by": "Supervised by:", (Auto-Translated) "workflow-item.search.result.list.element.supervised-by": "Supervisionado por:", From a3e6d9b09a2d6e529dc28f7d1a1924b2830077e6 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Mon, 30 Oct 2023 18:27:00 +0100 Subject: [PATCH 180/282] [DURACOM-195] Simplify vertical spacing in header and breadcrumbs --- src/app/breadcrumbs/breadcrumbs.component.html | 2 +- src/app/breadcrumbs/breadcrumbs.component.scss | 5 ++--- src/app/home-page/home-news/home-news.component.html | 2 +- src/app/home-page/home-news/home-news.component.scss | 2 -- src/app/root/root.component.html | 4 ++-- src/styles/_custom_variables.scss | 2 +- src/styles/_global-styles.scss | 10 ++++++++-- .../app/home-page/home-news/home-news.component.html | 2 +- .../app/home-page/home-news/home-news.component.scss | 1 - 9 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/app/breadcrumbs/breadcrumbs.component.html b/src/app/breadcrumbs/breadcrumbs.component.html index bff792eeff4..3bba89622ff 100644 --- a/src/app/breadcrumbs/breadcrumbs.component.html +++ b/src/app/breadcrumbs/breadcrumbs.component.html @@ -1,6 +1,6 @@ <ng-container *ngVar="(breadcrumbs$ | async) as breadcrumbs"> <nav *ngIf="(showBreadcrumbs$ | async)" aria-label="breadcrumb" class="nav-breadcrumb"> - <ol class="container breadcrumb"> + <ol class="container breadcrumb my-0"> <ng-container *ngTemplateOutlet="breadcrumbs?.length > 0 ? breadcrumb : activeBreadcrumb; context: {text: 'home.breadcrumbs', url: '/'}"></ng-container> <ng-container *ngFor="let bc of breadcrumbs; let last = last;"> diff --git a/src/app/breadcrumbs/breadcrumbs.component.scss b/src/app/breadcrumbs/breadcrumbs.component.scss index 52634f2a5b6..ac9cb42ce52 100644 --- a/src/app/breadcrumbs/breadcrumbs.component.scss +++ b/src/app/breadcrumbs/breadcrumbs.component.scss @@ -4,9 +4,8 @@ .breadcrumb { border-radius: 0; - margin-top: calc(-1 * var(--ds-content-spacing)); - padding-bottom: calc(var(--ds-content-spacing) / 3); - padding-top: calc(var(--ds-content-spacing) / 3); + padding-bottom: calc(var(--ds-content-spacing) / 2); + padding-top: calc(var(--ds-content-spacing) / 2); background-color: var(--ds-breadcrumb-bg); } diff --git a/src/app/home-page/home-news/home-news.component.html b/src/app/home-page/home-news/home-news.component.html index 6bee3cd76f0..8d3f99b60d4 100644 --- a/src/app/home-page/home-news/home-news.component.html +++ b/src/app/home-page/home-news/home-news.component.html @@ -1,4 +1,4 @@ -<div class="jumbotron jumbotron-fluid"> +<div class="jumbotron jumbotron-fluid mt-ncs"> <div class="container"> <div class="d-flex flex-wrap"> <div> diff --git a/src/app/home-page/home-news/home-news.component.scss b/src/app/home-page/home-news/home-news.component.scss index 9ab24daa25b..911a2fafc5d 100644 --- a/src/app/home-page/home-news/home-news.component.scss +++ b/src/app/home-page/home-news/home-news.component.scss @@ -1,7 +1,5 @@ :host { display: block; - margin-top: calc(-1 * var(--ds-content-spacing)); - margin-bottom: calc(-1 * var(--ds-content-spacing)); } .display-3 { diff --git a/src/app/root/root.component.html b/src/app/root/root.component.html index bf49e507c0b..ef8e33704fc 100644 --- a/src/app/root/root.component.html +++ b/src/app/root/root.component.html @@ -6,8 +6,8 @@ <div class="inner-wrapper"> <ds-system-wide-alert-banner></ds-system-wide-alert-banner> <ds-themed-header-navbar-wrapper></ds-themed-header-navbar-wrapper> - <main class="main-content"> - <ds-themed-breadcrumbs></ds-themed-breadcrumbs> + <ds-themed-breadcrumbs></ds-themed-breadcrumbs> + <main class="main-content my-cs"> <div class="container d-flex justify-content-center align-items-center h-100" *ngIf="shouldShowRouteLoader"> <ds-themed-loading [showMessage]="false"></ds-themed-loading> diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 778ef6e9e3a..ad9a074e1b4 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -1,5 +1,5 @@ :root { - --ds-content-spacing: #{$spacer * 1.5}; + --ds-content-spacing: #{$spacer}; // equivalent to Bootstrap spaces of size 3 --ds-button-height: #{$input-btn-padding-y * 2 + $input-btn-line-height + calculateRem($input-btn-border-width*2)}; diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index 81d4fe0787a..57a8455a193 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -26,8 +26,6 @@ body { .main-content { z-index: var(--ds-main-z-index); flex: 1 1 100%; - margin-top: var(--ds-content-spacing); - margin-bottom: var(--ds-content-spacing); } .alert.hide { @@ -317,3 +315,11 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { padding-top: 0.125rem !important; padding-bottom: 0.125rem !important; } + +// Margin utility classes based on DSpace content spacing +.mt-cs { margin-top: var(--ds-content-spacing); } +.mb-cs { margin-bottom: var(--ds-content-spacing); } +.my-cs { margin-top: var(--ds-content-spacing); margin-bottom: var(--ds-content-spacing); } +.mt-ncs { margin-top: calc(var(--ds-content-spacing) * -1); } +.mb-ncs { margin-bottom: calc(var(--ds-content-spacing) * -1); } +.my-ncs { margin-top: calc(var(--ds-content-spacing) * -1); margin-bottom: calc(var(--ds-content-spacing) * -1); } diff --git a/src/themes/dspace/app/home-page/home-news/home-news.component.html b/src/themes/dspace/app/home-page/home-news/home-news.component.html index ef576ed99cd..29711c1bf63 100644 --- a/src/themes/dspace/app/home-page/home-news/home-news.component.html +++ b/src/themes/dspace/app/home-page/home-news/home-news.component.html @@ -1,4 +1,4 @@ -<div class="background-image-container"> +<div class="background-image-container mt-ncs"> <div class="container"> <div class="jumbotron jumbotron-fluid"> <div class="d-flex flex-wrap"> diff --git a/src/themes/dspace/app/home-page/home-news/home-news.component.scss b/src/themes/dspace/app/home-page/home-news/home-news.component.scss index 93ec1763f34..3c3aa8b4450 100644 --- a/src/themes/dspace/app/home-page/home-news/home-news.component.scss +++ b/src/themes/dspace/app/home-page/home-news/home-news.component.scss @@ -1,6 +1,5 @@ :host { display: block; - margin-top: calc(var(--ds-content-spacing) * -1); div.background-image-container { color: white; From 4e2d6d109e13f8e16ca08b825a367fafad7ae991 Mon Sep 17 00:00:00 2001 From: lotte <lotte_hofstede@hotmail.com> Date: Thu, 9 Nov 2023 15:46:57 +0100 Subject: [PATCH 181/282] 108045: Fix for repeatable date field labels --- .../models/date-picker/date-picker.component.html | 2 +- .../ds-dynamic-form-ui/models/date-picker/date-picker.model.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html index 1046dd6b2d3..26803f3c67b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html @@ -1,6 +1,6 @@ <div> <fieldset class="d-flex"> - <legend [id]="'legend_' + model.id" [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"> + <legend *ngIf="!model.repeatable" [id]="'legend_' + model.id" [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"> {{model.placeholder}} <span *ngIf="model.required">*</span> </legend> <ds-number-picker diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts index 5af9b2bd323..88820cdaa33 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts @@ -15,6 +15,7 @@ export const DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER = 'DATE'; export interface DynamicDsDateControlModelConfig extends DynamicDatePickerModelConfig { legend?: string; typeBindRelations?: DynamicFormControlRelation[]; + repeatable: boolean; } /** @@ -37,7 +38,7 @@ export class DynamicDsDatePickerModel extends DynamicDateControlModel { this.metadataValue = (config as any).metadataValue; this.typeBindRelations = config.typeBindRelations ? config.typeBindRelations : []; this.hiddenUpdates = new BehaviorSubject<boolean>(this.hidden); - + this.repeatable = config.repeatable; // This was a subscription, then an async setTimeout, but it seems unnecessary const parentModel = this.getRootParent(this); if (parentModel && isNotUndefined(parentModel.hidden)) { From 0208a784378bf3f6226e6d9020523ae0fd38f9b4 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Tue, 31 Oct 2023 15:32:41 +0100 Subject: [PATCH 182/282] [DURACOM-180] Prevent header from covering media viewer controls (dspace theme) --- .../header-navbar-wrapper.component.html | 2 +- .../header-navbar-wrapper.component.scss | 7 +++++++ .../header-nav-wrapper/header-navbar-wrapper.component.ts | 2 +- src/themes/dspace/app/navbar/navbar.component.scss | 8 ++++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.html b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.html index 091d1522589..8c10efcb42e 100644 --- a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.html +++ b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.html @@ -1,3 +1,3 @@ -<div [ngClass]="{'open': !(isNavBarCollapsed | async)}"> +<div [class.open]="!(isNavBarCollapsed | async)" id="header-navbar-wrapper"> <ds-themed-header></ds-themed-header> </div> diff --git a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.scss b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.scss index e69de29bb2d..1daf4ebdbc3 100644 --- a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.scss +++ b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.scss @@ -0,0 +1,7 @@ +:host { + // The header-navbar-wrapper should not have a z-index, otherwise it would cover the media viewer despite its higher z-index + position: relative; + div#header-navbar-wrapper { + border-bottom: 5px var(--ds-header-navbar-border-bottom-color) solid; + } +} diff --git a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.ts b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.ts index 57ade022aee..36e23e174af 100644 --- a/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.ts +++ b/src/themes/dspace/app/header-nav-wrapper/header-navbar-wrapper.component.ts @@ -6,7 +6,7 @@ import { HeaderNavbarWrapperComponent as BaseComponent } from '../../../../app/h */ @Component({ selector: 'ds-header-navbar-wrapper', - styleUrls: ['../../../../app/header-nav-wrapper/header-navbar-wrapper.component.scss'], + styleUrls: ['header-navbar-wrapper.component.scss'], templateUrl: 'header-navbar-wrapper.component.html', }) export class HeaderNavbarWrapperComponent extends BaseComponent { diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index 300d1f419ad..28ead2f1def 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -1,7 +1,9 @@ nav.navbar { - border-top: 1px var(--ds-header-navbar-border-top-color) solid; - border-bottom: 5px var(--ds-header-navbar-border-bottom-color) solid; align-items: baseline; + + .navbar-inner-container { + border-top: 1px var(--ds-header-navbar-border-top-color) solid; + } } .navbar-nav { @@ -16,8 +18,10 @@ nav.navbar { position: absolute; overflow: hidden; height: 0; + z-index: var(--ds-nav-z-index); &.open { height: 100vh; //doesn't matter because wrapper is sticky + border-bottom: 5px var(--ds-header-navbar-border-bottom-color) solid; // open navbar covers header-navbar-wrapper border } } } From c042cd8d1154af59310b162c9a97e7d3820a1592 Mon Sep 17 00:00:00 2001 From: Davide Negretti <davide.negretti@4science.com> Date: Thu, 9 Nov 2023 15:24:22 +0100 Subject: [PATCH 183/282] [DURACOM-180] Prevent header from covering media viewer controls (base theme) --- .../header-nav-wrapper/header-navbar-wrapper.component.html | 2 +- .../header-nav-wrapper/header-navbar-wrapper.component.scss | 4 +++- src/app/navbar/navbar.component.scss | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html index f99070b738f..5756ad32b0b 100644 --- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html +++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html @@ -1,4 +1,4 @@ -<div [ngClass]="{'open': !(isNavBarCollapsed | async)}"> +<div [ngClass]="{'open': !(isNavBarCollapsed | async)}" id="header-navbar-wrapper"> <ds-themed-header></ds-themed-header> <ds-themed-navbar></ds-themed-navbar> </div> diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.scss b/src/app/header-nav-wrapper/header-navbar-wrapper.component.scss index b02b3c378ce..c1bc9c7e909 100644 --- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.scss +++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.scss @@ -1,4 +1,6 @@ :host { position: relative; - z-index: var(--ds-nav-z-index); + div#header-navbar-wrapper { + border-bottom: 1px var(--ds-header-navbar-border-bottom-color) solid; + } } diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss index 42e72aaffd8..dac8c0927f3 100644 --- a/src/app/navbar/navbar.component.scss +++ b/src/app/navbar/navbar.component.scss @@ -1,6 +1,5 @@ nav.navbar { background-color: var(--ds-navbar-bg); - border-bottom: 1px var(--ds-header-navbar-border-bottom-color) solid; align-items: baseline; } @@ -12,9 +11,11 @@ nav.navbar { position: absolute; overflow: hidden; height: 0; + z-index: var(--ds-nav-z-index); &.open { height: auto; min-height: 100vh; //doesn't matter because wrapper is sticky + border-bottom: 1px var(--ds-header-navbar-border-bottom-color) solid; // open navbar covers header-navbar-wrapper border } } } From 11d3771e72e3f54f73bb60a23abd970eff5d66a3 Mon Sep 17 00:00:00 2001 From: William Welling <wwelling@tamu.edu> Date: Fri, 3 Nov 2023 08:21:11 -0500 Subject: [PATCH 184/282] Update condition to render show more node `loadingNode` ends up being the current `node` after clicking it preventing it from rendering when more pages available. Update community list component spec Make the show more flat node id unique The nodes with same id are conflicting when added to the tree. Clicking on the second with same id places the show more button under the wrong branch and expands the wrong page. --- src/app/community-list-page/community-list-service.ts | 5 +++-- .../community-list/community-list.component.html | 2 +- .../community-list/community-list.component.spec.ts | 9 +++++---- .../community-list/community-list.component.ts | 7 +++---- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/app/community-list-page/community-list-service.ts b/src/app/community-list-page/community-list-service.ts index 67715716dad..bbf1c7cdb5d 100644 --- a/src/app/community-list-page/community-list-service.ts +++ b/src/app/community-list-page/community-list-service.ts @@ -24,6 +24,7 @@ import { FlatNode } from './flat-node.model'; import { ShowMoreFlatNode } from './show-more-flat-node.model'; import { FindListOptions } from '../core/data/find-list-options.model'; import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface'; +import { v4 as uuidv4 } from 'uuid'; // Helper method to combine and flatten an array of observables of flatNode arrays export const combineAndFlatten = (obsList: Observable<FlatNode[]>[]): Observable<FlatNode[]> => @@ -186,7 +187,7 @@ export class CommunityListService { return this.transformCommunity(community, level, parent, expandedNodes); }); if (currentPage < listOfPaginatedCommunities.totalPages && currentPage === listOfPaginatedCommunities.currentPage) { - obsList = [...obsList, observableOf([showMoreFlatNode('community', level, parent)])]; + obsList = [...obsList, observableOf([showMoreFlatNode(`community-${uuidv4()}`, level, parent)])]; } return combineAndFlatten(obsList); @@ -257,7 +258,7 @@ export class CommunityListService { let nodes = rd.payload.page .map((collection: Collection) => toFlatNode(collection, observableOf(false), level + 1, false, communityFlatNode)); if (currentCollectionPage < rd.payload.totalPages && currentCollectionPage === rd.payload.currentPage) { - nodes = [...nodes, showMoreFlatNode('collection', level + 1, communityFlatNode)]; + nodes = [...nodes, showMoreFlatNode(`collection-${uuidv4()}`, level + 1, communityFlatNode)]; } return nodes; } else { diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index 18e9e84577c..de67607bb4b 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -8,7 +8,7 @@ <span class="fa fa-chevron-right invisible" aria-hidden="true"></span> </button> <div class="align-middle pt-2"> - <button *ngIf="node!==loadingNode" (click)="getNextPage(node)" + <button *ngIf="!(dataSource.loading$ | async)" (click)="getNextPage(node)" class="btn btn-outline-primary btn-sm" role="button"> <i class="fas fa-angle-down"></i> {{ 'communityList.showMore' | translate }} </button> diff --git a/src/app/community-list-page/community-list/community-list.component.spec.ts b/src/app/community-list-page/community-list/community-list.component.spec.ts index ce6b27dbeb2..fb47f4994d2 100644 --- a/src/app/community-list-page/community-list/community-list.component.spec.ts +++ b/src/app/community-list-page/community-list/community-list.component.spec.ts @@ -17,6 +17,7 @@ import { By } from '@angular/platform-browser'; import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { FlatNode } from '../flat-node.model'; import { RouterLinkWithHref } from '@angular/router'; +import { v4 as uuidv4 } from 'uuid'; describe('CommunityListComponent', () => { let component: CommunityListComponent; @@ -138,7 +139,7 @@ describe('CommunityListComponent', () => { } if (expandedNodes === null || isEmpty(expandedNodes)) { if (showMoreTopComNode) { - return observableOf([...mockTopFlatnodesUnexpanded.slice(0, endPageIndex), showMoreFlatNode('community', 0, null)]); + return observableOf([...mockTopFlatnodesUnexpanded.slice(0, endPageIndex), showMoreFlatNode(`community-${uuidv4()}`, 0, null)]); } else { return observableOf(mockTopFlatnodesUnexpanded.slice(0, endPageIndex)); } @@ -165,21 +166,21 @@ describe('CommunityListComponent', () => { const endSubComIndex = this.pageSize * expandedParent.currentCommunityPage; flatnodes = [...flatnodes, ...subComFlatnodes.slice(0, endSubComIndex)]; if (subComFlatnodes.length > endSubComIndex) { - flatnodes = [...flatnodes, showMoreFlatNode('community', topNode.level + 1, expandedParent)]; + flatnodes = [...flatnodes, showMoreFlatNode(`community-${uuidv4()}`, topNode.level + 1, expandedParent)]; } } if (isNotEmpty(collFlatnodes)) { const endColIndex = this.pageSize * expandedParent.currentCollectionPage; flatnodes = [...flatnodes, ...collFlatnodes.slice(0, endColIndex)]; if (collFlatnodes.length > endColIndex) { - flatnodes = [...flatnodes, showMoreFlatNode('collection', topNode.level + 1, expandedParent)]; + flatnodes = [...flatnodes, showMoreFlatNode(`collection-${uuidv4()}`, topNode.level + 1, expandedParent)]; } } } } }); if (showMoreTopComNode) { - flatnodes = [...flatnodes, showMoreFlatNode('community', 0, null)]; + flatnodes = [...flatnodes, showMoreFlatNode(`community-${uuidv4()}`, 0, null)]; } return observableOf(flatnodes); } diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index 90dd6b3c05d..10ffb5e0b45 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -111,19 +111,18 @@ export class CommunityListComponent implements OnInit, OnDestroy { getNextPage(node: FlatNode): void { this.loadingNode = node; if (node.parent != null) { - if (node.id === 'collection') { + if (node.id.startsWith('collection')) { const parentNodeInExpandedNodes = this.expandedNodes.find((node2: FlatNode) => node.parent.id === node2.id); parentNodeInExpandedNodes.currentCollectionPage++; } - if (node.id === 'community') { + if (node.id.startsWith('community')) { const parentNodeInExpandedNodes = this.expandedNodes.find((node2: FlatNode) => node.parent.id === node2.id); parentNodeInExpandedNodes.currentCommunityPage++; } - this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes); } else { this.paginationConfig.currentPage++; - this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes); } + this.dataSource.loadCommunities(this.paginationConfig, this.expandedNodes); } } From dc2ef989e612c305ae98932be491db15a1fc74a4 Mon Sep 17 00:00:00 2001 From: William Welling <wwelling@tamu.edu> Date: Thu, 9 Nov 2023 11:24:31 -0600 Subject: [PATCH 185/282] Filter expanded nodes by id Co-Authored-By: Art Lowel <1567693+artlowel@users.noreply.github.com> --- .../community-list/community-list.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index 10ffb5e0b45..6b5c6578e1f 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -84,7 +84,7 @@ export class CommunityListComponent implements OnInit, OnDestroy { toggleExpanded(node: FlatNode) { this.loadingNode = node; if (node.isExpanded) { - this.expandedNodes = this.expandedNodes.filter((node2) => node2.name !== node.name); + this.expandedNodes = this.expandedNodes.filter((node2) => node2.id !== node.id); node.isExpanded = false; } else { this.expandedNodes.push(node); From 0da7c15f2eff6229caafccae1be8dd7b10ebc629 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 20 Sep 2023 14:28:08 -0500 Subject: [PATCH 186/282] Limit getMembers() and getSubgroups() to only fetching one object. These lists are only used to find the size of each --- .../group-registry/groups-registry.component.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/access-control/group-registry/groups-registry.component.ts b/src/app/access-control/group-registry/groups-registry.component.ts index ccfd155e393..06a048ad72d 100644 --- a/src/app/access-control/group-registry/groups-registry.component.ts +++ b/src/app/access-control/group-registry/groups-registry.component.ts @@ -216,18 +216,28 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy { /** * Get the members (epersons embedded value of a group) + * NOTE: At this time we only grab the *first* member in order to receive the `totalElements` value + * needed for our HTML template. * @param group */ getMembers(group: Group): Observable<RemoteData<PaginatedList<EPerson>>> { - return this.ePersonDataService.findListByHref(group._links.epersons.href).pipe(getFirstSucceededRemoteData()); + return this.ePersonDataService.findListByHref(group._links.epersons.href, { + currentPage: 1, + elementsPerPage: 1, + }).pipe(getFirstSucceededRemoteData()); } /** * Get the subgroups (groups embedded value of a group) + * NOTE: At this time we only grab the *first* subgroup in order to receive the `totalElements` value + * needed for our HTML template. * @param group */ getSubgroups(group: Group): Observable<RemoteData<PaginatedList<Group>>> { - return this.groupService.findListByHref(group._links.subgroups.href).pipe(getFirstSucceededRemoteData()); + return this.groupService.findListByHref(group._links.subgroups.href, { + currentPage: 1, + elementsPerPage: 1, + }).pipe(getFirstSucceededRemoteData()); } /** From 97479a29453eaf18031e095b612c1c054f9bb31f Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 20 Sep 2023 14:30:54 -0500 Subject: [PATCH 187/282] Remove isSubgroupOfGroup() functionality as it loads every subgroup at once. Bad peformance for large groups --- .../subgroups-list.component.html | 9 +---- .../subgroup-list/subgroups-list.component.ts | 33 ++----------------- 2 files changed, 3 insertions(+), 39 deletions(-) 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 d009f0283eb..8268eb5eb45 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,16 +62,9 @@ <h4 id="search" class="border-bottom pb-2"> <td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload) }}</td> <td class="align-middle"> <div class="btn-group edit-field"> - <button *ngIf="(isSubgroupOfGroup(group) | async) && !(isActiveGroup(group) | async)" - (click)="deleteSubgroupFromGroup(group)" - class="btn btn-outline-danger btn-sm deleteButton" - title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(group) } }}"> - <i class="fas fa-trash-alt fa-fw"></i> - </button> - <span *ngIf="(isActiveGroup(group) | async)">{{ messagePrefix + '.table.edit.currentGroup' | translate }}</span> - <button *ngIf="!(isSubgroupOfGroup(group) | async) && !(isActiveGroup(group) | async)" + <button *ngIf="!(isActiveGroup(group) | async)" (click)="addSubgroupToGroup(group)" class="btn btn-outline-primary btn-sm addButton" title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(group) } }}"> diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts index 0cff730c628..83df0d8cdde 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts @@ -3,15 +3,13 @@ import { UntypedFormBuilder } from '@angular/forms'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; -import { map, mergeMap, switchMap, take } from 'rxjs/operators'; +import { mergeMap, switchMap, take } from 'rxjs/operators'; import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { GroupDataService } from '../../../../core/eperson/group-data.service'; import { Group } from '../../../../core/eperson/models/group.model'; import { - getFirstCompletedRemoteData, - getFirstSucceededRemoteData, - getRemoteDataPayload + getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; @@ -131,33 +129,6 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { })); } - /** - * Whether or not the given group is a subgroup of the group currently being edited - * @param possibleSubgroup Group that is a possible subgroup (being tested) of the group currently being edited - */ - isSubgroupOfGroup(possibleSubgroup: Group): Observable<boolean> { - return this.groupDataService.getActiveGroup().pipe(take(1), - mergeMap((activeGroup: Group) => { - if (activeGroup != null) { - if (activeGroup.uuid === possibleSubgroup.uuid) { - return observableOf(false); - } else { - return this.groupDataService.findListByHref(activeGroup._links.subgroups.href, { - currentPage: 1, - elementsPerPage: 9999 - }) - .pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - map((listTotalGroups: PaginatedList<Group>) => listTotalGroups.page.filter((groupInList: Group) => groupInList.id === possibleSubgroup.id)), - map((groups: Group[]) => groups.length > 0)); - } - } else { - return observableOf(false); - } - })); - } - /** * Whether or not the given group is the current group being edited * @param group Group that is possibly the current group being edited From 229236634a06f5468dc078eb5d814981ecf3d497 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 20 Sep 2023 15:17:34 -0500 Subject: [PATCH 188/282] Fix bug where linked Community/Collection info was sometimes listed many times in a row --- .../group-form/group-form.component.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts index 0758a455f53..925a8bb8593 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/access-control/group-registry/group-form/group-form.component.ts @@ -230,12 +230,14 @@ export class GroupFormComponent implements OnInit, OnDestroy { this.groupBeingEdited = activeGroup; if (linkedObject?.name) { - this.formBuilderService.insertFormGroupControl(1, this.formGroup, this.formModel, this.groupCommunity); - this.formGroup.patchValue({ - groupName: activeGroup.name, - groupCommunity: linkedObject?.name ?? '', - groupDescription: activeGroup.firstMetadataValue('dc.description'), - }); + if (!this.formGroup.controls.groupCommunity) { + this.formBuilderService.insertFormGroupControl(1, this.formGroup, this.formModel, this.groupCommunity); + this.formGroup.patchValue({ + groupName: activeGroup.name, + groupCommunity: linkedObject?.name ?? '', + groupDescription: activeGroup.firstMetadataValue('dc.description'), + }); + } } else { this.formModel = [ this.groupName, From 43d37196fbaf45648dbd5e604a3ee8d5df2a129e Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 22 Sep 2023 12:13:39 -0500 Subject: [PATCH 189/282] Remove "isMemberOfGroup()" from members-list component. --- .../members-list/members-list.component.html | 21 +------ .../members-list/members-list.component.ts | 56 +++---------------- 2 files changed, 11 insertions(+), 66 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 cc9bf34d644..b90a3e405b1 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 @@ -69,16 +69,7 @@ <h4 id="search" class="border-bottom pb-2"> </td> <td class="align-middle"> <div class="btn-group edit-field"> - <button *ngIf="ePerson.memberOfGroup" - (click)="deleteMemberFromGroup(ePerson)" - [disabled]="actionConfig.remove.disabled" - [ngClass]="['btn btn-sm', actionConfig.remove.css]" - title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> - <i [ngClass]="actionConfig.remove.icon"></i> - </button> - - <button *ngIf="!ePerson.memberOfGroup" - (click)="addMemberToGroup(ePerson)" + <button (click)="addMemberToGroup(ePerson)" [disabled]="actionConfig.add.disabled" [ngClass]="['btn btn-sm', actionConfig.add.css]" title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> @@ -133,20 +124,12 @@ <h4>{{messagePrefix + '.headMembers' | translate}}</h4> </td> <td class="align-middle"> <div class="btn-group edit-field"> - <button *ngIf="ePerson.memberOfGroup" - (click)="deleteMemberFromGroup(ePerson)" + <button (click)="deleteMemberFromGroup(ePerson)" [disabled]="actionConfig.remove.disabled" [ngClass]="['btn btn-sm', actionConfig.remove.css]" title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> <i [ngClass]="actionConfig.remove.icon"></i> </button> - <button *ngIf="!ePerson.memberOfGroup" - (click)="addMemberToGroup(ePerson)" - [disabled]="actionConfig.add.disabled" - [ngClass]="['btn btn-sm', actionConfig.add.css]" - title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> - <i [ngClass]="actionConfig.add.icon"></i> - </button> </div> </td> </tr> 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<PaginatedList<EPerson>>) => { const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const dto$: Observable<EpersonDtoModel> = observableCombineLatest( - this.isMemberOfGroup(member), (isMember: ObservedValueOf<Observable<boolean>>) => { - 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<boolean> { - 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<EPerson>) => 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<PaginatedList<EPerson>>) => { const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => { - const dto$: Observable<EpersonDtoModel> = observableCombineLatest( - this.isMemberOfGroup(member), (isMember: ObservedValueOf<Observable<boolean>>) => { - 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 <tim.donohue@lyrasis.org> Date: Mon, 25 Sep 2023 16:34:04 -0500 Subject: [PATCH 190/282] 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 @@ <h4 id="search" class="border-bottom pb-2"> </div> </form> - <ds-pagination *ngIf="(ePeopleSearchDtos | async)?.totalElements > 0" + <ds-pagination *ngIf="(ePeopleSearch | async)?.totalElements > 0" [paginationOptions]="configSearch" - [pageInfoState]="(ePeopleSearchDtos | async)" - [collectionSize]="(ePeopleSearchDtos | async)?.totalElements" + [pageInfoState]="(ePeopleSearch | async)" + [collectionSize]="(ePeopleSearch | async)?.totalElements" [hideGear]="true" [hidePagerWhenSinglePage]="true"> @@ -55,24 +55,24 @@ <h4 id="search" class="border-bottom pb-2"> </tr> </thead> <tbody> - <tr *ngFor="let ePerson of (ePeopleSearchDtos | async)?.page"> - <td class="align-middle">{{ePerson.eperson.id}}</td> + <tr *ngFor="let eperson of (ePeopleSearch | async)?.page"> + <td class="align-middle">{{eperson.id}}</td> <td class="align-middle"> - <a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)" + <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> - {{ dsoNameService.getName(ePerson.eperson) }} + {{ dsoNameService.getName(eperson) }} </a> </td> <td class="align-middle"> - {{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}<br/> - {{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }} + {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}<br/> + {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }} </td> <td class="align-middle"> <div class="btn-group edit-field"> - <button (click)="addMemberToGroup(ePerson)" + <button (click)="addMemberToGroup(eperson)" [disabled]="actionConfig.add.disabled" [ngClass]="['btn btn-sm', actionConfig.add.css]" - title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> + title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(eperson) } }}"> <i [ngClass]="actionConfig.add.icon"></i> </button> </div> @@ -84,7 +84,7 @@ <h4 id="search" class="border-bottom pb-2"> </ds-pagination> - <div *ngIf="(ePeopleSearchDtos | async)?.totalElements == 0 && searchDone" + <div *ngIf="(ePeopleSearch | async)?.totalElements == 0 && searchDone" class="alert alert-info w-100 mb-2" role="alert"> {{messagePrefix + '.no-items' | translate}} @@ -92,10 +92,10 @@ <h4 id="search" class="border-bottom pb-2"> <h4>{{messagePrefix + '.headMembers' | translate}}</h4> - <ds-pagination *ngIf="(ePeopleMembersOfGroupDtos | async)?.totalElements > 0" + <ds-pagination *ngIf="(ePeopleMembersOfGroup | async)?.totalElements > 0" [paginationOptions]="config" - [pageInfoState]="(ePeopleMembersOfGroupDtos | async)" - [collectionSize]="(ePeopleMembersOfGroupDtos | async)?.totalElements" + [pageInfoState]="(ePeopleMembersOfGroup | async)" + [collectionSize]="(ePeopleMembersOfGroup | async)?.totalElements" [hideGear]="true" [hidePagerWhenSinglePage]="true"> @@ -110,24 +110,24 @@ <h4>{{messagePrefix + '.headMembers' | translate}}</h4> </tr> </thead> <tbody> - <tr *ngFor="let ePerson of (ePeopleMembersOfGroupDtos | async)?.page"> - <td class="align-middle">{{ePerson.eperson.id}}</td> + <tr *ngFor="let eperson of (ePeopleMembersOfGroup | async)?.page"> + <td class="align-middle">{{eperson.id}}</td> <td class="align-middle"> - <a (click)="ePersonDataService.startEditingNewEPerson(ePerson.eperson)" + <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> - {{ dsoNameService.getName(ePerson.eperson) }} + {{ dsoNameService.getName(eperson) }} </a> </td> <td class="align-middle"> - {{messagePrefix + '.table.email' | translate}}: {{ ePerson.eperson.email ? ePerson.eperson.email : '-' }}<br/> - {{messagePrefix + '.table.netid' | translate}}: {{ ePerson.eperson.netid ? ePerson.eperson.netid : '-' }} + {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}<br/> + {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }} </td> <td class="align-middle"> <div class="btn-group edit-field"> - <button (click)="deleteMemberFromGroup(ePerson)" + <button (click)="deleteMemberFromGroup(eperson)" [disabled]="actionConfig.remove.disabled" [ngClass]="['btn btn-sm', actionConfig.remove.css]" - title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(ePerson.eperson) } }}"> + title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(eperson) } }}"> <i [ngClass]="actionConfig.remove.icon"></i> </button> </div> @@ -139,7 +139,7 @@ <h4>{{messagePrefix + '.headMembers' | translate}}</h4> </ds-pagination> - <div *ngIf="(ePeopleMembersOfGroupDtos | async) == undefined || (ePeopleMembersOfGroupDtos | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" + <div *ngIf="(ePeopleMembersOfGroup | async) == undefined || (ePeopleMembersOfGroup | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> {{messagePrefix + '.no-members-yet' | translate}} </div> 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<RemoteData<PaginatedList<EPerson>>> { return createSuccessfulRemoteDataObject$(buildPaginatedList<EPerson>(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, + // This method is used to search across *non-members* searchByScope(scope: string, query: string): Observable<RemoteData<PaginatedList<EPerson>>> { 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<Group> { return observableOf(activeGroup); }, getEPersonMembers() { return this.epersonMembers; }, - searchGroups(query: string): Observable<RemoteData<PaginatedList<Group>>> { - if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), this.allGroups)); - } - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); - }, - addMemberToGroup(parentGroup, eperson: EPerson): Observable<RestResponse> { - this.epersonMembers = [...this.epersonMembers, eperson]; + addMemberToGroup(parentGroup, epersonToAdd: EPerson): Observable<RestResponse> { + // 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<RestResponse> { - 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<PaginatedList<EpersonDtoModel>> = new BehaviorSubject<PaginatedList<EpersonDtoModel>>(undefined); + ePeopleSearch: BehaviorSubject<PaginatedList<EPerson>> = new BehaviorSubject<PaginatedList<EPerson>>(undefined); /** * List of EPeople members of currently active group being edited */ - ePeopleMembersOfGroupDtos: BehaviorSubject<PaginatedList<EpersonDtoModel>> = new BehaviorSubject<PaginatedList<EpersonDtoModel>>(undefined); + ePeopleMembersOfGroup: BehaviorSubject<PaginatedList<EPerson>> = new BehaviorSubject<PaginatedList<EPerson>>(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<PaginatedList<EPerson>>) => { - 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<EpersonDtoModel>) => { - this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); + getRemoteDataPayload()) + .subscribe((paginatedListOfEPersons: PaginatedList<EPerson>) => { + 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<PaginatedList<EPerson>>) => { - 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<EpersonDtoModel>) => { - this.ePeopleSearchDtos.next(paginatedListOfDTOs); + getRemoteDataPayload()) + .subscribe((paginatedListOfEPersons: PaginatedList<EPerson>) => { + this.ePeopleSearch.next(paginatedListOfEPersons); })); } From b598f1b5ca9b54c4b5fe23daa3d7b502ee0dc6b2 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 26 Sep 2023 12:07:30 -0500 Subject: [PATCH 191/282] 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<ReviewersListComponent>; @@ -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<RemoteData<PaginatedList<EPerson>>> { return createSuccessfulRemoteDataObject$(buildPaginatedList<EPerson>(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, + // This method is used to search across *non-members* searchByScope(scope: string, query: string): Observable<RemoteData<PaginatedList<EPerson>>> { 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<Group> { return observableOf(activeGroup); }, getEPersonMembers() { return this.epersonMembers; }, - searchGroups(query: string): Observable<RemoteData<PaginatedList<Group>>> { - if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), this.allGroups)); - } - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); - }, - addMemberToGroup(parentGroup, eperson: EPerson): Observable<RestResponse> { - this.epersonMembers = [...this.epersonMembers, eperson]; + addMemberToGroup(parentGroup, epersonToAdd: EPerson): Observable<RestResponse> { + // 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<RestResponse> { - 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<EPerson[]> = 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<EpersonDtoModel> = new PaginatedList(); - paginatedListOfDTOs.page = this.selectedReviewers; - this.ePeopleMembersOfGroupDtos.next(paginatedListOfDTOs); + this.unsubFrom(SubKey.Members); + const paginatedListOfEPersons: PaginatedList<EPerson> = 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<boolean> { - 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 <tim.donohue@lyrasis.org> Date: Mon, 2 Oct 2023 16:35:26 -0500 Subject: [PATCH 192/282] 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<Group> { 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<RemoteData<PaginatedList<Group>>> { - return this.subgroups$.pipe( - map((currentGroups: Group[]) => { - return createSuccessfulRemoteDataObject(buildPaginatedList<Group>(new PageInfo(), currentGroups)); - }) - ); + return createSuccessfulRemoteDataObject$(buildPaginatedList<Group>(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<RemoteData<PaginatedList<Group>>> { if (query === '') { - return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), allGroups)); + return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupNonMembers)); } return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])); }, - addSubGroupToGroup(parentGroup, subgroup: Group): Observable<RestResponse> { - this.subgroups$.next([...this.subgroups$.getValue(), subgroup]); + addSubGroupToGroup(parentGroup, subgroupToAdd: Group): Observable<RestResponse> { + // 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<RestResponse> { - this.subgroups$.next(this.subgroups$.getValue().filter((group: Group) => { - if (group.id !== subgroup.id) { - return group; + deleteSubGroupFromGroup(parentGroup, subgroupToDelete: Group): Observable<RestResponse> { + // 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 <tim.donohue@lyrasis.org> Date: Fri, 13 Oct 2023 14:43:28 -0500 Subject: [PATCH 193/282] 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 @@ <h4 id="search" class="border-bottom pb-2"> </h4> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> - <div> - <select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope"> - <option value="metadata">{{messagePrefix + '.search.scope.metadata' | translate}}</option> - <option value="email">{{messagePrefix + '.search.scope.email' | translate}}</option> - </select> - </div> - <div class="flex-grow-1 mr-3 ml-3"> - <div class="form-group input-group"> + <div class="flex-grow-1 mr-3"> + <div class="form-group input-group mr-3"> <input type="text" name="query" id="query" formControlName="query" class="form-control" aria-label="Search input"> <span class="input-group-append"> 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<EPerson>(new PageInfo(), groupsDataServiceStub.getEPersonMembers())); }, // This method is used to search across *non-members* - searchByScope(scope: string, query: string): Observable<RemoteData<PaginatedList<EPerson>>> { + searchNonMembers(query: string, group: string): Observable<RemoteData<PaginatedList<EPerson>>> { 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<any>) => { 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 @@ <h4 id="search" class="border-bottom pb-2"> <td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload) }}</td> <td class="align-middle"> <div class="btn-group edit-field"> - <span *ngIf="(isActiveGroup(group) | async)">{{ messagePrefix + '.table.edit.currentGroup' | translate }}</span> - - <button *ngIf="!(isActiveGroup(group) | async)" - (click)="addSubgroupToGroup(group)" + <button (click)="addSubgroupToGroup(group)" class="btn btn-outline-primary btn-sm addButton" title="{{messagePrefix + '.table.edit.buttons.add' | translate: { name: dsoNameService.getName(group) } }}"> <i class="fas fa-plus fa-fw"></i> 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 7bbbb24f304..6fe7c2cf676 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 @@ -87,7 +87,7 @@ describe('SubgroupsListComponent', () => { 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<RemoteData<PaginatedList<Group>>> { + searchNonMemberGroups(query: string, group: string): Observable<RemoteData<PaginatedList<Group>>> { if (query === '') { return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), groupNonMembers)); } diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts index 83df0d8cdde..20200e47d22 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts @@ -2,8 +2,8 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormBuilder } from '@angular/forms'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; -import { mergeMap, switchMap, take } from 'rxjs/operators'; +import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { switchMap, take } from 'rxjs/operators'; import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { GroupDataService } from '../../../../core/eperson/group-data.service'; @@ -129,20 +129,6 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { })); } - /** - * Whether or not the given group is the current group being edited - * @param group Group that is possibly the current group being edited - */ - isActiveGroup(group: Group): Observable<boolean> { - return this.groupDataService.getActiveGroup().pipe(take(1), - mergeMap((activeGroup: Group) => { - if (activeGroup != null && activeGroup.uuid === group.uuid) { - return observableOf(true); - } - return observableOf(false); - })); - } - /** * Deletes given subgroup from the group currently being edited * @param subgroup Group we want to delete from the subgroups of the group currently being edited @@ -152,6 +138,11 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { if (activeGroup != null) { const response = this.groupDataService.deleteSubGroupFromGroup(activeGroup, subgroup); this.showNotifications('deleteSubgroup', response, this.dsoNameService.getName(subgroup), 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')); } @@ -168,6 +159,11 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { if (activeGroup.uuid !== subgroup.uuid) { const response = this.groupDataService.addSubGroupToGroup(activeGroup, subgroup); this.showNotifications('addSubgroup', response, this.dsoNameService.getName(subgroup), activeGroup); + // Reload search results (if there is an active query). + // This will potentially remove this added subgroup from search results. + if (this.currentSearchQuery != null) { + this.search({query: this.currentSearchQuery}); + } } else { this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure.subgroupToAddIsActiveGroup')); } @@ -178,7 +174,8 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { } /** - * Search in the groups (searches by group name and by uuid exact match) + * Search all non-member groups (searches by group name and by uuid exact match). Used to search for + * groups that could be added to current group as a subgroup. * @param data Contains query param */ search(data: any) { @@ -192,10 +189,10 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { this.unsubFrom(SubKey.SearchResults); this.subs.set(SubKey.SearchResults, this.paginationService.getCurrentPagination(this.configSearch.id, this.configSearch).pipe( - switchMap((config) => this.groupDataService.searchGroups(this.currentSearchQuery, { + switchMap((config) => this.groupDataService.searchNonMemberGroups(this.currentSearchQuery, this.groupBeingEdited.id, { currentPage: config.currentPage, elementsPerPage: config.pageSize - }, true, true, followLink('object') + }, false, true, followLink('object') )) ).subscribe((rd: RemoteData<PaginatedList<Group>>) => { this.searchResults$.next(rd); diff --git a/src/app/core/eperson/eperson-data.service.spec.ts b/src/app/core/eperson/eperson-data.service.spec.ts index b4b939eebf4..c1bc3563a32 100644 --- a/src/app/core/eperson/eperson-data.service.spec.ts +++ b/src/app/core/eperson/eperson-data.service.spec.ts @@ -11,6 +11,7 @@ import { EPeopleRegistryCancelEPersonAction, EPeopleRegistryEditEPersonAction } from '../../access-control/epeople-registry/epeople-registry.actions'; +import { GroupMock } from '../../shared/testing/group-mock'; import { RequestParam } from '../cache/models/request-param.model'; import { ChangeAnalyzer } from '../data/change-analyzer'; import { PatchRequest, PostRequest } from '../data/request.models'; @@ -140,6 +141,30 @@ describe('EPersonDataService', () => { }); }); + describe('searchNonMembers', () => { + beforeEach(() => { + spyOn(service, 'searchBy'); + }); + + it('search with empty query and a group ID', () => { + service.searchNonMembers('', GroupMock.id); + const options = Object.assign(new FindListOptions(), { + searchParams: [Object.assign(new RequestParam('query', '')), + Object.assign(new RequestParam('group', GroupMock.id))] + }); + expect(service.searchBy).toHaveBeenCalledWith('isNotMemberOf', options, true, true); + }); + + it('search with query and a group ID', () => { + service.searchNonMembers('test', GroupMock.id); + const options = Object.assign(new FindListOptions(), { + searchParams: [Object.assign(new RequestParam('query', 'test')), + Object.assign(new RequestParam('group', GroupMock.id))] + }); + expect(service.searchBy).toHaveBeenCalledWith('isNotMemberOf', options, true, true); + }); + }); + describe('updateEPerson', () => { beforeEach(() => { spyOn(service, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(EPersonMock)); diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts index 00620655de4..fb8b8bc9b00 100644 --- a/src/app/core/eperson/eperson-data.service.ts +++ b/src/app/core/eperson/eperson-data.service.ts @@ -177,6 +177,34 @@ export class EPersonDataService extends IdentifiableDataService<EPerson> impleme return this.searchBy(searchMethod, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } + /** + * Searches for all EPerons which are *not* a member of a given group, via a passed in query + * (searches all EPerson metadata and by exact UUID). + * Endpoint used: /eperson/epesons/search/isNotMemberOf?query=<:string>&group=<:uuid> + * @param query search query param + * @param group UUID of group to exclude results from. Members of this group will never be returned. + * @param options + * @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 + */ + public searchNonMembers(query: string, group: string, options?: FindListOptions, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<EPerson>[]): Observable<RemoteData<PaginatedList<EPerson>>> { + const searchParams = [new RequestParam('query', query), new RequestParam('group', group)]; + let findListOptions = new FindListOptions(); + if (options) { + findListOptions = Object.assign(new FindListOptions(), options); + } + if (findListOptions.searchParams) { + findListOptions.searchParams = [...findListOptions.searchParams, ...searchParams]; + } else { + findListOptions.searchParams = searchParams; + } + return this.searchBy('isNotMemberOf', findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } + /** * Add a new patch to the object cache * The patch is derived from the differences between the given object and its version in the object cache diff --git a/src/app/core/eperson/group-data.service.spec.ts b/src/app/core/eperson/group-data.service.spec.ts index b424aed1aa0..6eecfd7fa15 100644 --- a/src/app/core/eperson/group-data.service.spec.ts +++ b/src/app/core/eperson/group-data.service.spec.ts @@ -43,11 +43,11 @@ describe('GroupDataService', () => { let rdbService; let objectCache; function init() { - restEndpointURL = 'https://dspace.4science.it/dspace-spring-rest/api/eperson'; + restEndpointURL = 'https://rest.api/server/api/eperson'; groupsEndpoint = `${restEndpointURL}/groups`; groups = [GroupMock, GroupMock2]; groups$ = createSuccessfulRemoteDataObject$(createPaginatedList(groups)); - rdbService = getMockRemoteDataBuildServiceHrefMap(undefined, { 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups': groups$ }); + rdbService = getMockRemoteDataBuildServiceHrefMap(undefined, { 'https://rest.api/server/api/eperson/groups': groups$ }); halService = new HALEndpointServiceStub(restEndpointURL); objectCache = getMockObjectCacheService(); TestBed.configureTestingModule({ @@ -111,6 +111,30 @@ describe('GroupDataService', () => { }); }); + describe('searchNonMemberGroups', () => { + beforeEach(() => { + spyOn(service, 'searchBy'); + }); + + it('search with empty query and a group ID', () => { + service.searchNonMemberGroups('', GroupMock.id); + const options = Object.assign(new FindListOptions(), { + searchParams: [Object.assign(new RequestParam('query', '')), + Object.assign(new RequestParam('group', GroupMock.id))] + }); + expect(service.searchBy).toHaveBeenCalledWith('isNotMemberOf', options, true, true); + }); + + it('search with query and a group ID', () => { + service.searchNonMemberGroups('test', GroupMock.id); + const options = Object.assign(new FindListOptions(), { + searchParams: [Object.assign(new RequestParam('query', 'test')), + Object.assign(new RequestParam('group', GroupMock.id))] + }); + expect(service.searchBy).toHaveBeenCalledWith('isNotMemberOf', options, true, true); + }); + }); + describe('addSubGroupToGroup', () => { beforeEach(() => { objectCache.getByHref.and.returnValue(observableOf({ diff --git a/src/app/core/eperson/group-data.service.ts b/src/app/core/eperson/group-data.service.ts index 7b3a14c70b2..683d026bb68 100644 --- a/src/app/core/eperson/group-data.service.ts +++ b/src/app/core/eperson/group-data.service.ts @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'; import { createSelector, select, Store } from '@ngrx/store'; import { Observable, zip as observableZip } from 'rxjs'; -import { filter, map, take } from 'rxjs/operators'; +import { take } from 'rxjs/operators'; import { GroupRegistryCancelGroupAction, GroupRegistryEditGroupAction @@ -105,23 +105,31 @@ export class GroupDataService extends IdentifiableDataService<Group> implements } /** - * Check if the current user is member of to the indicated group - * - * @param groupName - * the group name - * @return boolean - * true if user is member of the indicated group, false otherwise + * Searches for all groups which are *not* a member of a given group, via a passed in query + * (searches in group name and by exact UUID). + * Endpoint used: /eperson/groups/search/isNotMemberOf?query=<:string>&group=<:uuid> + * @param query search query param + * @param group UUID of group to exclude results from. Members of this group will never be returned. + * @param options + * @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 */ - isMemberOf(groupName: string): Observable<boolean> { - const searchHref = 'isMemberOf'; - const options = new FindListOptions(); - options.searchParams = [new RequestParam('groupName', groupName)]; - - return this.searchBy(searchHref, options).pipe( - filter((groups: RemoteData<PaginatedList<Group>>) => !groups.isResponsePending), - take(1), - map((groups: RemoteData<PaginatedList<Group>>) => groups.payload.totalElements > 0) - ); + public searchNonMemberGroups(query: string, group: string, options?: FindListOptions, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Group>[]): Observable<RemoteData<PaginatedList<Group>>> { + const searchParams = [new RequestParam('query', query), new RequestParam('group', group)]; + let findListOptions = new FindListOptions(); + if (options) { + findListOptions = Object.assign(new FindListOptions(), options); + } + if (findListOptions.searchParams) { + findListOptions.searchParams = [...findListOptions.searchParams, ...searchParams]; + } else { + findListOptions.searchParams = searchParams; + } + return this.searchBy('isNotMemberOf', findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } /** diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 3b3578fac5d..2a67a7315dc 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -434,10 +434,6 @@ "admin.access-control.groups.form.members-list.headMembers": "Current Members", - "admin.access-control.groups.form.members-list.search.scope.metadata": "Metadata", - - "admin.access-control.groups.form.members-list.search.scope.email": "E-mail (exact)", - "admin.access-control.groups.form.members-list.search.button": "Search", "admin.access-control.groups.form.members-list.table.id": "ID", @@ -494,8 +490,6 @@ "admin.access-control.groups.form.subgroups-list.table.edit.buttons.add": "Add subgroup with name \"{{name}}\"", - "admin.access-control.groups.form.subgroups-list.table.edit.currentGroup": "Current group", - "admin.access-control.groups.form.subgroups-list.notification.success.addSubgroup": "Successfully added subgroup: \"{{name}}\"", "admin.access-control.groups.form.subgroups-list.notification.failure.addSubgroup": "Failed to add subgroup: \"{{name}}\"", @@ -632,10 +626,6 @@ "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.headMembers": "Current Members", - "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.search.scope.metadata": "Metadata", - - "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.button": "Search", "advanced-workflow-action-select-reviewer.groups.form.reviewers-list.table.id": "ID", From 2eb1a17e4e0fd0eb6a13f30c6f8b847f6d9d7a89 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 13 Oct 2023 14:56:45 -0500 Subject: [PATCH 194/282] Refactor subgroups-list component's "search()" to act same as member-list component's "search()". Avoids reloading the page as frequently. --- .../subgroup-list/subgroups-list.component.ts | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts index 20200e47d22..119b147a951 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts @@ -3,12 +3,13 @@ import { UntypedFormBuilder } from '@angular/forms'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { switchMap, take } from 'rxjs/operators'; +import { map, switchMap, take } from 'rxjs/operators'; import { PaginatedList } from '../../../../core/data/paginated-list.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { GroupDataService } from '../../../../core/eperson/group-data.service'; import { Group } from '../../../../core/eperson/models/group.model'; import { + getAllCompletedRemoteData, getFirstCompletedRemoteData } from '../../../../core/shared/operators'; import { NotificationsService } from '../../../../shared/notifications/notifications.service'; @@ -179,24 +180,36 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { * @param data Contains query param */ search(data: any) { - const query: string = data.query; - if (query != null && this.currentSearchQuery !== query) { - this.router.navigateByUrl(this.groupDataService.getGroupEditPageRouterLink(this.groupBeingEdited)); - this.currentSearchQuery = query; - this.configSearch.currentPage = 1; - } - this.searchDone = true; - this.unsubFrom(SubKey.SearchResults); - this.subs.set(SubKey.SearchResults, this.paginationService.getCurrentPagination(this.configSearch.id, this.configSearch).pipe( - switchMap((config) => this.groupDataService.searchNonMemberGroups(this.currentSearchQuery, this.groupBeingEdited.id, { - currentPage: config.currentPage, - elementsPerPage: config.pageSize - }, false, true, followLink('object') - )) - ).subscribe((rd: RemoteData<PaginatedList<Group>>) => { - this.searchResults$.next(rd); - })); + this.subs.set(SubKey.SearchResults, + this.paginationService.getCurrentPagination(this.configSearch.id, this.configSearch).pipe( + switchMap((paginationOptions) => { + const query: string = data.query; + if (query != null && this.currentSearchQuery !== query && this.groupBeingEdited) { + this.router.navigate([], { + queryParamsHandling: 'merge' + }); + this.currentSearchQuery = query; + this.paginationService.resetPage(this.configSearch.id); + } + this.searchDone = true; + + return this.groupDataService.searchNonMemberGroups(this.currentSearchQuery, this.groupBeingEdited.id, { + currentPage: paginationOptions.currentPage, + elementsPerPage: paginationOptions.pageSize + }, false, true, followLink('object')); + }), + getAllCompletedRemoteData(), + map((rd: RemoteData<any>) => { + if (rd.hasFailed) { + this.notificationsService.error(this.translateService.get(this.messagePrefix + '.notification.failure', { cause: rd.errorMessage })); + } else { + return rd; + } + })) + .subscribe((rd: RemoteData<PaginatedList<Group>>) => { + this.searchResults$.next(rd); + })); } /** From d163db13f219ab81ca821e1695a2193edb38c79a Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 13 Oct 2023 15:07:04 -0500 Subject: [PATCH 195/282] Remove seemingly unnecessary page reload after new search. --- .../group-form/members-list/members-list.component.ts | 3 --- .../group-form/subgroup-list/subgroups-list.component.ts | 3 --- 2 files changed, 6 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 4924f3168b5..d2ddd700a9b 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 @@ -252,9 +252,6 @@ export class MembersListComponent implements OnInit, OnDestroy { switchMap((paginationOptions) => { const query: string = data.query; if (query != null && this.currentSearchQuery !== query && this.groupBeingEdited) { - this.router.navigate([], { - queryParamsHandling: 'merge' - }); this.currentSearchQuery = query; this.paginationService.resetPage(this.configSearch.id); } diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts index 119b147a951..12cdc27943b 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts @@ -186,9 +186,6 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { switchMap((paginationOptions) => { const query: string = data.query; if (query != null && this.currentSearchQuery !== query && this.groupBeingEdited) { - this.router.navigate([], { - queryParamsHandling: 'merge' - }); this.currentSearchQuery = query; this.paginationService.resetPage(this.configSearch.id); } From 9117ac005f575277bf2e025d18afb878d18b0589 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Thu, 9 Nov 2023 13:57:04 -0600 Subject: [PATCH 196/282] Address feedback. Run empty search on init. Reorder sections to list current members before add members (for both eperson and groups) --- .../members-list/members-list.component.html | 108 +++++++++--------- .../members-list/members-list.component.ts | 1 + .../subgroups-list.component.html | 98 ++++++++-------- .../subgroup-list/subgroups-list.component.ts | 1 + 4 files changed, 105 insertions(+), 103 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 e185d37e286..c0c77f44ebc 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 @@ -1,6 +1,60 @@ <ng-container> <h3 class="border-bottom pb-2">{{messagePrefix + '.head' | translate}}</h3> + <h4>{{messagePrefix + '.headMembers' | translate}}</h4> + + <ds-pagination *ngIf="(ePeopleMembersOfGroup | async)?.totalElements > 0" + [paginationOptions]="config" + [pageInfoState]="(ePeopleMembersOfGroup | async)" + [collectionSize]="(ePeopleMembersOfGroup | async)?.totalElements" + [hideGear]="true" + [hidePagerWhenSinglePage]="true"> + + <div class="table-responsive"> + <table id="ePeopleMembersOfGroup" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.identity' | translate}}</th> + <th class="align-middle">{{messagePrefix + '.table.edit' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let eperson of (ePeopleMembersOfGroup | async)?.page"> + <td class="align-middle">{{eperson.id}}</td> + <td class="align-middle"> + <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" + [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> + {{ dsoNameService.getName(eperson) }} + </a> + </td> + <td class="align-middle"> + {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}<br/> + {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }} + </td> + <td class="align-middle"> + <div class="btn-group edit-field"> + <button (click)="deleteMemberFromGroup(eperson)" + [disabled]="actionConfig.remove.disabled" + [ngClass]="['btn btn-sm', actionConfig.remove.css]" + title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(eperson) } }}"> + <i [ngClass]="actionConfig.remove.icon"></i> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + + </ds-pagination> + + <div *ngIf="(ePeopleMembersOfGroup | async) == undefined || (ePeopleMembersOfGroup | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" + role="alert"> + {{messagePrefix + '.no-members-yet' | translate}} + </div> + <h4 id="search" class="border-bottom pb-2"> <span *dsContextHelp="{ @@ -84,58 +138,4 @@ <h4 id="search" class="border-bottom pb-2"> {{messagePrefix + '.no-items' | translate}} </div> - <h4>{{messagePrefix + '.headMembers' | translate}}</h4> - - <ds-pagination *ngIf="(ePeopleMembersOfGroup | async)?.totalElements > 0" - [paginationOptions]="config" - [pageInfoState]="(ePeopleMembersOfGroup | async)" - [collectionSize]="(ePeopleMembersOfGroup | async)?.totalElements" - [hideGear]="true" - [hidePagerWhenSinglePage]="true"> - - <div class="table-responsive"> - <table id="ePeopleMembersOfGroup" class="table table-striped table-hover table-bordered"> - <thead> - <tr> - <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.identity' | translate}}</th> - <th class="align-middle">{{messagePrefix + '.table.edit' | translate}}</th> - </tr> - </thead> - <tbody> - <tr *ngFor="let eperson of (ePeopleMembersOfGroup | async)?.page"> - <td class="align-middle">{{eperson.id}}</td> - <td class="align-middle"> - <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" - [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> - {{ dsoNameService.getName(eperson) }} - </a> - </td> - <td class="align-middle"> - {{messagePrefix + '.table.email' | translate}}: {{ eperson.email ? eperson.email : '-' }}<br/> - {{messagePrefix + '.table.netid' | translate}}: {{ eperson.netid ? eperson.netid : '-' }} - </td> - <td class="align-middle"> - <div class="btn-group edit-field"> - <button (click)="deleteMemberFromGroup(eperson)" - [disabled]="actionConfig.remove.disabled" - [ngClass]="['btn btn-sm', actionConfig.remove.css]" - title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(eperson) } }}"> - <i [ngClass]="actionConfig.remove.icon"></i> - </button> - </div> - </td> - </tr> - </tbody> - </table> - </div> - - </ds-pagination> - - <div *ngIf="(ePeopleMembersOfGroup | async) == undefined || (ePeopleMembersOfGroup | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" - role="alert"> - {{messagePrefix + '.no-members-yet' | translate}} - </div> - </ng-container> 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 @@ <ng-container> <h3 class="border-bottom pb-2">{{messagePrefix + '.head' | translate}}</h3> + <h4>{{messagePrefix + '.headSubgroups' | translate}}</h4> + + <ds-pagination *ngIf="(subGroups$ | async)?.payload?.totalElements > 0" + [paginationOptions]="config" + [pageInfoState]="(subGroups$ | async)?.payload" + [collectionSize]="(subGroups$ | async)?.payload?.totalElements" + [hideGear]="true" + [hidePagerWhenSinglePage]="true"> + + <div class="table-responsive"> + <table id="subgroupsOfGroup" class="table table-striped table-hover table-bordered"> + <thead> + <tr> + <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> + <th scope="col" class="align-middle">{{messagePrefix + '.table.collectionOrCommunity' | translate}}</th> + <th>{{messagePrefix + '.table.edit' | translate}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let group of (subGroups$ | async)?.payload?.page"> + <td class="align-middle">{{group.id}}</td> + <td class="align-middle"> + <a (click)="groupDataService.startEditingNewGroup(group)" + [routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]"> + {{ dsoNameService.getName(group) }} + </a> + </td> + <td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload)}}</td> + <td class="align-middle"> + <div class="btn-group edit-field"> + <button (click)="deleteSubgroupFromGroup(group)" + class="btn btn-outline-danger btn-sm deleteButton" + title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(group) } }}"> + <i class="fas fa-trash-alt fa-fw"></i> + </button> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </ds-pagination> + + <div *ngIf="(subGroups$ | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" + role="alert"> + {{messagePrefix + '.no-subgroups-yet' | translate}} + </div> + <h4 id="search" class="border-bottom pb-2"> <span *dsContextHelp="{ content: 'admin.access-control.groups.form.tooltip.editGroup.addSubgroups', @@ -80,53 +129,4 @@ <h4 id="search" class="border-bottom pb-2"> {{messagePrefix + '.no-items' | translate}} </div> - <h4>{{messagePrefix + '.headSubgroups' | translate}}</h4> - - <ds-pagination *ngIf="(subGroups$ | async)?.payload?.totalElements > 0" - [paginationOptions]="config" - [pageInfoState]="(subGroups$ | async)?.payload" - [collectionSize]="(subGroups$ | async)?.payload?.totalElements" - [hideGear]="true" - [hidePagerWhenSinglePage]="true"> - - <div class="table-responsive"> - <table id="subgroupsOfGroup" class="table table-striped table-hover table-bordered"> - <thead> - <tr> - <th scope="col" class="align-middle">{{messagePrefix + '.table.id' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.name' | translate}}</th> - <th scope="col" class="align-middle">{{messagePrefix + '.table.collectionOrCommunity' | translate}}</th> - <th>{{messagePrefix + '.table.edit' | translate}}</th> - </tr> - </thead> - <tbody> - <tr *ngFor="let group of (subGroups$ | async)?.payload?.page"> - <td class="align-middle">{{group.id}}</td> - <td class="align-middle"> - <a (click)="groupDataService.startEditingNewGroup(group)" - [routerLink]="[groupDataService.getGroupEditPageRouterLink(group)]"> - {{ dsoNameService.getName(group) }} - </a> - </td> - <td class="align-middle">{{ dsoNameService.getName((group.object | async)?.payload)}}</td> - <td class="align-middle"> - <div class="btn-group edit-field"> - <button (click)="deleteSubgroupFromGroup(group)" - class="btn btn-outline-danger btn-sm deleteButton" - title="{{messagePrefix + '.table.edit.buttons.remove' | translate: { name: dsoNameService.getName(group) } }}"> - <i class="fas fa-trash-alt fa-fw"></i> - </button> - </div> - </td> - </tr> - </tbody> - </table> - </div> - </ds-pagination> - - <div *ngIf="(subGroups$ | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" - role="alert"> - {{messagePrefix + '.no-subgroups-yet' | translate}} - </div> - </ng-container> diff --git a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts index 12cdc27943b..aea545e5543 100644 --- a/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts +++ b/src/app/access-control/group-registry/group-form/subgroup-list/subgroups-list.component.ts @@ -102,6 +102,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy { if (activeGroup != null) { this.groupBeingEdited = activeGroup; this.retrieveSubGroups(); + this.search({query: ''}); } })); } From a7faf7d449a44ce793bfe4b72cf7b377445ae181 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 16 Oct 2023 22:16:22 +0200 Subject: [PATCH 197/282] 107671: Fix handle theme not working with canonical prefix https://hdl.handle.net/ --- .../core/data/configuration-data.service.ts | 1 - .../curation-form.component.spec.ts | 12 +-- .../curation-form/curation-form.component.ts | 82 +++++++++-------- src/app/shared/handle.service.spec.ts | 84 ++++++++++++------ src/app/shared/handle.service.ts | 86 +++++++++++++----- .../configuration-data.service.stub.ts | 14 +++ .../theme-support/theme.service.spec.ts | 43 ++++++--- src/app/shared/theme-support/theme.service.ts | 71 ++++++++------- src/config/theme.model.spec.ts | 87 ++++++++++++++----- src/config/theme.model.ts | 34 +++++--- 10 files changed, 348 insertions(+), 166 deletions(-) create mode 100644 src/app/shared/testing/configuration-data.service.stub.ts diff --git a/src/app/core/data/configuration-data.service.ts b/src/app/core/data/configuration-data.service.ts index de044e25e33..557e13f57ba 100644 --- a/src/app/core/data/configuration-data.service.ts +++ b/src/app/core/data/configuration-data.service.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-classes-per-file */ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; diff --git a/src/app/curation-form/curation-form.component.spec.ts b/src/app/curation-form/curation-form.component.spec.ts index dc70b925e83..a0bdee21f49 100644 --- a/src/app/curation-form/curation-form.component.spec.ts +++ b/src/app/curation-form/curation-form.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync, fakeAsync, flush } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CurationFormComponent } from './curation-form.component'; @@ -16,6 +16,7 @@ import { ConfigurationDataService } from '../core/data/configuration-data.servic import { ConfigurationProperty } from '../core/shared/configuration-property.model'; import { getProcessDetailRoute } from '../process-page/process-page-routing.paths'; import { HandleService } from '../shared/handle.service'; +import { of as observableOf } from 'rxjs'; describe('CurationFormComponent', () => { let comp: CurationFormComponent; @@ -54,7 +55,7 @@ describe('CurationFormComponent', () => { }); handleService = { - normalizeHandle: (a) => a + normalizeHandle: (a: string) => observableOf(a), } as any; notificationsService = new NotificationsServiceStub(); @@ -151,12 +152,13 @@ describe('CurationFormComponent', () => { ], []); }); - it(`should show an error notification and return when an invalid dsoHandle is provided`, () => { + it(`should show an error notification and return when an invalid dsoHandle is provided`, fakeAsync(() => { comp.dsoHandle = 'test-handle'; - spyOn(handleService, 'normalizeHandle').and.returnValue(null); + spyOn(handleService, 'normalizeHandle').and.returnValue(observableOf(null)); comp.submit(); + flush(); expect(notificationsService.error).toHaveBeenCalled(); expect(scriptDataService.invoke).not.toHaveBeenCalled(); - }); + })); }); diff --git a/src/app/curation-form/curation-form.component.ts b/src/app/curation-form/curation-form.component.ts index 2c0e900a662..cc2c14f89fb 100644 --- a/src/app/curation-form/curation-form.component.ts +++ b/src/app/curation-form/curation-form.component.ts @@ -1,22 +1,22 @@ -import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ScriptDataService } from '../core/data/processes/script-data.service'; import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { getFirstCompletedRemoteData } from '../core/shared/operators'; -import { find, map } from 'rxjs/operators'; +import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../core/shared/operators'; +import { map } from 'rxjs/operators'; import { NotificationsService } from '../shared/notifications/notifications.service'; import { TranslateService } from '@ngx-translate/core'; import { hasValue, isEmpty, isNotEmpty } from '../shared/empty.util'; import { RemoteData } from '../core/data/remote-data'; import { Router } from '@angular/router'; -import { ProcessDataService } from '../core/data/processes/process-data.service'; import { Process } from '../process-page/processes/process.model'; import { ConfigurationDataService } from '../core/data/configuration-data.service'; import { ConfigurationProperty } from '../core/shared/configuration-property.model'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { getProcessDetailRoute } from '../process-page/process-page-routing.paths'; import { HandleService } from '../shared/handle.service'; export const CURATION_CFG = 'plugin.named.org.dspace.curate.CurationTask'; + /** * Component responsible for rendering the Curation Task form */ @@ -24,7 +24,7 @@ export const CURATION_CFG = 'plugin.named.org.dspace.curate.CurationTask'; selector: 'ds-curation-form', templateUrl: './curation-form.component.html' }) -export class CurationFormComponent implements OnInit { +export class CurationFormComponent implements OnDestroy, OnInit { config: Observable<RemoteData<ConfigurationProperty>>; tasks: string[]; @@ -33,10 +33,11 @@ export class CurationFormComponent implements OnInit { @Input() dsoHandle: string; + subs: Subscription[] = []; + constructor( private scriptDataService: ScriptDataService, private configurationDataService: ConfigurationDataService, - private processDataService: ProcessDataService, private notificationsService: NotificationsService, private translateService: TranslateService, private handleService: HandleService, @@ -45,6 +46,10 @@ export class CurationFormComponent implements OnInit { ) { } + ngOnDestroy(): void { + this.subs.forEach((sub: Subscription) => sub.unsubscribe()); + } + ngOnInit(): void { this.form = new UntypedFormGroup({ task: new UntypedFormControl(''), @@ -52,16 +57,15 @@ export class CurationFormComponent implements OnInit { }); this.config = this.configurationDataService.findByPropertyName(CURATION_CFG); - this.config.pipe( - find((rd: RemoteData<ConfigurationProperty>) => rd.hasSucceeded), - map((rd: RemoteData<ConfigurationProperty>) => rd.payload) - ).subscribe((configProperties) => { + this.subs.push(this.config.pipe( + getFirstSucceededRemoteDataPayload(), + ).subscribe((configProperties: ConfigurationProperty) => { this.tasks = configProperties.values .filter((value) => isNotEmpty(value) && value.includes('=')) .map((value) => value.split('=')[1].trim()); this.form.get('task').patchValue(this.tasks[0]); this.cdr.detectChanges(); - }); + })); } /** @@ -77,33 +81,41 @@ export class CurationFormComponent implements OnInit { */ submit() { const taskName = this.form.get('task').value; - let handle; + let handle$: Observable<string | null>; if (this.hasHandleValue()) { - handle = this.handleService.normalizeHandle(this.dsoHandle); - if (isEmpty(handle)) { - this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'), - this.translateService.get('curation.form.submit.error.invalid-handle')); - return; - } + handle$ = this.handleService.normalizeHandle(this.dsoHandle).pipe( + map((handle: string | null) => { + if (isEmpty(handle)) { + this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'), + this.translateService.get('curation.form.submit.error.invalid-handle')); + } + return handle; + }), + ); } else { - handle = this.handleService.normalizeHandle(this.form.get('handle').value); - if (isEmpty(handle)) { - handle = 'all'; - } + handle$ = this.handleService.normalizeHandle(this.form.get('handle').value).pipe( + map((handle: string | null) => isEmpty(handle) ? 'all' : handle), + ); } - this.scriptDataService.invoke('curate', [ - { name: '-t', value: taskName }, - { name: '-i', value: handle }, - ], []).pipe(getFirstCompletedRemoteData()).subscribe((rd: RemoteData<Process>) => { - if (rd.hasSucceeded) { - this.notificationsService.success(this.translateService.get('curation.form.submit.success.head'), - this.translateService.get('curation.form.submit.success.content')); - this.router.navigateByUrl(getProcessDetailRoute(rd.payload.processId)); - } else { - this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'), - this.translateService.get('curation.form.submit.error.content')); + this.subs.push(handle$.subscribe((handle: string) => { + if (hasValue(handle)) { + this.subs.push(this.scriptDataService.invoke('curate', [ + { name: '-t', value: taskName }, + { name: '-i', value: handle }, + ], []).pipe( + getFirstCompletedRemoteData(), + ).subscribe((rd: RemoteData<Process>) => { + if (rd.hasSucceeded) { + this.notificationsService.success(this.translateService.get('curation.form.submit.success.head'), + this.translateService.get('curation.form.submit.success.content')); + void this.router.navigateByUrl(getProcessDetailRoute(rd.payload.processId)); + } else { + this.notificationsService.error(this.translateService.get('curation.form.submit.error.head'), + this.translateService.get('curation.form.submit.error.content')); + } + })); } - }); + })); } } diff --git a/src/app/shared/handle.service.spec.ts b/src/app/shared/handle.service.spec.ts index b326eb04163..a499bdd464d 100644 --- a/src/app/shared/handle.service.spec.ts +++ b/src/app/shared/handle.service.spec.ts @@ -1,47 +1,79 @@ import { HandleService } from './handle.service'; +import { TestBed } from '@angular/core/testing'; +import { ConfigurationDataServiceStub } from './testing/configuration-data.service.stub'; +import { ConfigurationDataService } from '../core/data/configuration-data.service'; +import { of as observableOf } from 'rxjs'; describe('HandleService', () => { let service: HandleService; + let configurationService: ConfigurationDataServiceStub; + beforeEach(() => { - service = new HandleService(); + configurationService = new ConfigurationDataServiceStub(); + + TestBed.configureTestingModule({ + providers: [ + { provide: ConfigurationDataService, useValue: configurationService }, + ], + }); + service = TestBed.inject(HandleService); }); describe(`normalizeHandle`, () => { - it(`should simply return an already normalized handle`, () => { - let input, output; - - input = '123456789/123456'; - output = service.normalizeHandle(input); - expect(output).toEqual(input); + it('should normalize a handle url with custom conical prefix with trailing slash', (done: DoneFn) => { + service.canonicalPrefix$ = observableOf('https://hdl.handle.net/'); - input = '12.3456.789/123456'; - output = service.normalizeHandle(input); - expect(output).toEqual(input); + service.normalizeHandle('https://hdl.handle.net/123456789/123456').subscribe((handle: string | null) => { + expect(handle).toBe('123456789/123456'); + done(); + }); }); - it(`should normalize a handle url`, () => { - let input, output; + it('should normalize a handle url with custom conical prefix without trailing slash', (done: DoneFn) => { + service.canonicalPrefix$ = observableOf('https://hdl.handle.net'); - input = 'https://hdl.handle.net/handle/123456789/123456'; - output = service.normalizeHandle(input); - expect(output).toEqual('123456789/123456'); + service.normalizeHandle('https://hdl.handle.net/123456789/123456').subscribe((handle: string | null) => { + expect(handle).toBe('123456789/123456'); + done(); + }); + }); + + describe('should simply return an already normalized handle', () => { + it('123456789/123456', (done: DoneFn) => { + service.normalizeHandle('123456789/123456').subscribe((handle: string | null) => { + expect(handle).toBe('123456789/123456'); + done(); + }); + }); - input = 'https://rest.api/server/handle/123456789/123456'; - output = service.normalizeHandle(input); - expect(output).toEqual('123456789/123456'); + it('12.3456.789/123456', (done: DoneFn) => { + service.normalizeHandle('12.3456.789/123456').subscribe((handle: string | null) => { + expect(handle).toBe('12.3456.789/123456'); + done(); + }); + }); }); - it(`should return null if the input doesn't contain a handle`, () => { - let input, output; + it('should normalize handle urls starting with handle', (done: DoneFn) => { + service.normalizeHandle('https://rest.api/server/handle/123456789/123456').subscribe((handle: string | null) => { + expect(handle).toBe('123456789/123456'); + done(); + }); + }); - input = 'https://hdl.handle.net/handle/123456789'; - output = service.normalizeHandle(input); - expect(output).toBeNull(); + it('should return null if the input doesn\'t contain a valid handle', (done: DoneFn) => { + service.normalizeHandle('https://hdl.handle.net/123456789').subscribe((handle: string | null) => { + expect(handle).toBeNull(); + done(); + }); + }); - input = 'something completely different'; - output = service.normalizeHandle(input); - expect(output).toBeNull(); + it('should return null if the input doesn\'t contain a handle', (done: DoneFn) => { + service.normalizeHandle('something completely different').subscribe((handle: string | null) => { + expect(handle).toBeNull(); + done(); + }); }); }); }); diff --git a/src/app/shared/handle.service.ts b/src/app/shared/handle.service.ts index da0f17f7de3..56b3922753b 100644 --- a/src/app/shared/handle.service.ts +++ b/src/app/shared/handle.service.ts @@ -1,7 +1,18 @@ import { Injectable } from '@angular/core'; -import { isNotEmpty, isEmpty } from './empty.util'; +import { isEmpty, hasNoValue } from './empty.util'; +import { ConfigurationDataService } from '../core/data/configuration-data.service'; +import { getFirstCompletedRemoteData } from '../core/shared/operators'; +import { map, take } from 'rxjs/operators'; +import { ConfigurationProperty } from '../core/shared/configuration-property.model'; +import { Observable } from 'rxjs'; +import { RemoteData } from '../core/data/remote-data'; -const PREFIX_REGEX = /handle\/([^\/]+\/[^\/]+)$/; +export const CANONICAL_PREFIX_KEY = 'handle.canonical.prefix'; + +const PREFIX_REGEX = (prefix: string | undefined) => { + const formattedPrefix: string = prefix?.replace(/\/$/, ''); + return new RegExp(`(${formattedPrefix ? formattedPrefix + '|' : '' }handle)\/([^\/]+\/[^\/]+)$`); +}; const NO_PREFIX_REGEX = /^([^\/]+\/[^\/]+)$/; @Injectable({ @@ -9,33 +20,62 @@ const NO_PREFIX_REGEX = /^([^\/]+\/[^\/]+)$/; }) export class HandleService { + canonicalPrefix$: Observable<string | undefined>; + + constructor( + protected configurationService: ConfigurationDataService, + ) { + this.canonicalPrefix$ = this.configurationService.findByPropertyName(CANONICAL_PREFIX_KEY).pipe( + getFirstCompletedRemoteData(), + take(1), + map((configurationPropertyRD: RemoteData<ConfigurationProperty>) => { + if (configurationPropertyRD.hasSucceeded) { + return configurationPropertyRD.payload.values.length >= 1 ? configurationPropertyRD.payload.values[0] : undefined; + } else { + return undefined; + } + }), + ); + } /** * Turns a handle string into the default 123456789/12345 format * - * @param handle the input handle + * When the <b>handle.canonical.prefix</b> doesn't end with handle, be sure to expose the variable so that the + * frontend can find the handle * - * normalizeHandle('123456789/123456') // '123456789/123456' - * normalizeHandle('12.3456.789/123456') // '12.3456.789/123456' - * normalizeHandle('https://hdl.handle.net/handle/123456789/123456') // '123456789/123456' - * normalizeHandle('https://rest.api/server/handle/123456789/123456') // '123456789/123456' - * normalizeHandle('https://rest.api/server/handle/123456789') // null + * @param handle the input handle + * @return + * <ul> + * <li>normalizeHandle('123456789/123456') // '123456789/123456'</li> + * <li>normalizeHandle('12.3456.789/123456') // '12.3456.789/123456'</li> + * <li>normalizeHandle('https://hdl.handle.net/123456789/123456') // '123456789/123456'</li> + * <li>normalizeHandle('https://rest.api/server/handle/123456789/123456') // '123456789/123456'</li> + * <li>normalizeHandle('https://rest.api/server/handle/123456789') // null</li> + * </ul> */ - normalizeHandle(handle: string): string { - let matches: string[]; - if (isNotEmpty(handle)) { - matches = handle.match(PREFIX_REGEX); - } - - if (isEmpty(matches) || matches.length < 2) { - matches = handle.match(NO_PREFIX_REGEX); - } - - if (isEmpty(matches) || matches.length < 2) { - return null; - } else { - return matches[1]; - } + normalizeHandle(handle: string): Observable<string | null> { + return this.canonicalPrefix$.pipe( + map((prefix: string | undefined) => { + let matches: string[]; + if (hasNoValue(handle)) { + return null; + } + + matches = handle.match(PREFIX_REGEX(prefix)); + + if (isEmpty(matches) || matches.length < 3) { + matches = handle.match(NO_PREFIX_REGEX); + } + + if (isEmpty(matches) || matches.length < 2) { + return null; + } else { + return matches[matches.length - 1]; + } + }), + take(1), + ); } } diff --git a/src/app/shared/testing/configuration-data.service.stub.ts b/src/app/shared/testing/configuration-data.service.stub.ts new file mode 100644 index 00000000000..f17e2d7b5ba --- /dev/null +++ b/src/app/shared/testing/configuration-data.service.stub.ts @@ -0,0 +1,14 @@ +import { Observable } from 'rxjs'; +import { RemoteData } from '../../core/data/remote-data'; +import { ConfigurationProperty } from '../../core/shared/configuration-property.model'; +import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils'; + +export class ConfigurationDataServiceStub { + + findByPropertyName(_name: string): Observable<RemoteData<ConfigurationProperty>> { + const configurationProperty = new ConfigurationProperty(); + configurationProperty.values = []; + return createSuccessfulRemoteDataObject$(configurationProperty); + } + +} diff --git a/src/app/shared/theme-support/theme.service.spec.ts b/src/app/shared/theme-support/theme.service.spec.ts index f56fb86cbc1..c4669408e1c 100644 --- a/src/app/shared/theme-support/theme.service.spec.ts +++ b/src/app/shared/theme-support/theme.service.spec.ts @@ -24,6 +24,8 @@ import { ROUTER_NAVIGATED } from '@ngrx/router-store'; import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { CommonModule, DOCUMENT } from '@angular/common'; import { RouterMock } from '../mocks/router.mock'; +import { ConfigurationDataServiceStub } from '../testing/configuration-data.service.stub'; +import { ConfigurationDataService } from '../../core/data/configuration-data.service'; /** * LinkService able to mock recursively resolving DSO parent links @@ -49,6 +51,7 @@ class MockLinkService { describe('ThemeService', () => { let themeService: ThemeService; let linkService: LinkService; + let configurationService: ConfigurationDataServiceStub; let initialState; let ancestorDSOs: DSpaceObject[]; @@ -78,6 +81,7 @@ describe('ThemeService', () => { currentTheme: 'custom', }, }; + configurationService = new ConfigurationDataServiceStub(); } function setupServiceWithActions(mockActions) { @@ -96,6 +100,7 @@ describe('ThemeService', () => { provideMockActions(() => mockActions), { provide: DSpaceObjectDataService, useValue: mockDsoService }, { provide: Router, useValue: new RouterMock() }, + { provide: ConfigurationDataService, useValue: configurationService }, ] }); @@ -112,7 +117,7 @@ describe('ThemeService', () => { function spyOnPrivateMethods() { spyOn((themeService as any), 'getAncestorDSOs').and.returnValue(() => observableOf([dso])); - spyOn((themeService as any), 'matchThemeToDSOs').and.returnValue(new Theme({ name: 'custom' })); + spyOn((themeService as any), 'matchThemeToDSOs').and.returnValue(observableOf(new Theme({ name: 'custom' }))); spyOn((themeService as any), 'getActionForMatch').and.returnValue(new SetThemeAction('custom')); } @@ -283,13 +288,13 @@ describe('ThemeService', () => { beforeEach(() => { nonMatchingTheme = Object.assign(new Theme({ name: 'non-matching-theme' }), { - matches: () => false + matches: () => observableOf(false), }); itemMatchingTheme = Object.assign(new Theme({ name: 'item-matching-theme' }), { - matches: (url, dso) => (dso as any).type === ITEM.value + matches: (url, dso) => observableOf((dso as any).type === ITEM.value), }); communityMatchingTheme = Object.assign(new Theme({ name: 'community-matching-theme' }), { - matches: (url, dso) => (dso as any).type === COMMUNITY.value + matches: (url, dso) => observableOf((dso as any).type === COMMUNITY.value), }); dsos = [ Object.assign(new Item(), { @@ -313,8 +318,11 @@ describe('ThemeService', () => { themeService.themes = themes; }); - it('should return undefined', () => { - expect((themeService as any).matchThemeToDSOs(dsos, '')).toBeUndefined(); + it('should return undefined', (done: DoneFn) => { + (themeService as any).matchThemeToDSOs(dsos, '').subscribe((theme: Theme) => { + expect(theme).toBeUndefined(); + done(); + }); }); }); @@ -324,20 +332,31 @@ describe('ThemeService', () => { themeService.themes = themes; }); - it('should return the matching theme', () => { - expect((themeService as any).matchThemeToDSOs(dsos, '')).toEqual(itemMatchingTheme); + it('should return the matching theme', (done: DoneFn) => { + (themeService as any).matchThemeToDSOs(dsos, '').subscribe((theme: Theme) => { + expect(theme).toBe(itemMatchingTheme); + done(); + }); }); }); describe('when multiple themes match some of the DSOs', () => { - it('should return the first matching theme', () => { + it('should return the first matching theme (itemMatchingTheme)', (done: DoneFn) => { themes = [ nonMatchingTheme, itemMatchingTheme, communityMatchingTheme ]; themeService.themes = themes; - expect((themeService as any).matchThemeToDSOs(dsos, '')).toEqual(itemMatchingTheme); + (themeService as any).matchThemeToDSOs(dsos, '').subscribe((theme: Theme) => { + expect(theme).toBe(itemMatchingTheme); + done(); + }); + }); + it('should return the first matching theme (communityMatchingTheme)', (done: DoneFn) => { themes = [ nonMatchingTheme, communityMatchingTheme, itemMatchingTheme ]; themeService.themes = themes; - expect((themeService as any).matchThemeToDSOs(dsos, '')).toEqual(communityMatchingTheme); + (themeService as any).matchThemeToDSOs(dsos, '').subscribe((theme: Theme) => { + expect(theme).toBe(communityMatchingTheme); + done(); + }); }); }); }); @@ -382,6 +401,7 @@ describe('ThemeService', () => { const mockDsoService = { findById: () => createSuccessfulRemoteDataObject$(mockCommunity) }; + configurationService = new ConfigurationDataServiceStub(); TestBed.configureTestingModule({ imports: [ @@ -393,6 +413,7 @@ describe('ThemeService', () => { provideMockStore({ initialState }), { provide: DSpaceObjectDataService, useValue: mockDsoService }, { provide: Router, useValue: new RouterMock() }, + { provide: ConfigurationDataService, useValue: configurationService }, ] }); diff --git a/src/app/shared/theme-support/theme.service.ts b/src/app/shared/theme-support/theme.service.ts index 4ce976dd58c..daf2e3960e4 100644 --- a/src/app/shared/theme-support/theme.service.ts +++ b/src/app/shared/theme-support/theme.service.ts @@ -1,17 +1,13 @@ import { Injectable, Inject, Injector } from '@angular/core'; import { Store, createFeatureSelector, createSelector, select } from '@ngrx/store'; -import { BehaviorSubject, EMPTY, Observable, of as observableOf } from 'rxjs'; +import { BehaviorSubject, EMPTY, Observable, of as observableOf, from, concatMap } from 'rxjs'; import { ThemeState } from './theme.reducer'; import { SetThemeAction, ThemeActionTypes } from './theme.actions'; -import { expand, filter, map, switchMap, take, toArray } from 'rxjs/operators'; +import { defaultIfEmpty, expand, filter, map, switchMap, take, toArray } from 'rxjs/operators'; import { hasNoValue, hasValue, isNotEmpty } from '../empty.util'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { - getFirstCompletedRemoteData, - getFirstSucceededRemoteData, - getRemoteDataPayload -} from '../../core/shared/operators'; +import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload } from '../../core/shared/operators'; import { HeadTagConfig, Theme, ThemeConfig, themeFactory } from '../../../config/theme.model'; import { NO_OP_ACTION_TYPE, NoOpAction } from '../ngrx/no-op.action'; import { followLink } from '../utils/follow-link-config.model'; @@ -219,7 +215,7 @@ export class ThemeService { // create new head tags (not yet added to DOM) const headTagFragment = this.document.createDocumentFragment(); this.createHeadTags(themeName) - .forEach(newHeadTag => headTagFragment.appendChild(newHeadTag)); + .forEach(newHeadTag => headTagFragment.appendChild(newHeadTag)); // add new head tags to DOM head.appendChild(headTagFragment); @@ -268,7 +264,7 @@ export class ThemeService { if (hasValue(headTagConfig.attributes)) { Object.entries(headTagConfig.attributes) - .forEach(([key, value]) => tag.setAttribute(key, value)); + .forEach(([key, value]) => tag.setAttribute(key, value)); } // 'class' attribute should always be 'theme-head-tag' for removal @@ -292,7 +288,7 @@ export class ThemeService { // and the current theme from the store const currentTheme$: Observable<string> = this.store.pipe(select(currentThemeSelector)); - const action$ = currentTheme$.pipe( + const action$: Observable<SetThemeAction | NoOpAction> = currentTheme$.pipe( switchMap((currentTheme: string) => { const snapshotWithData = this.findRouteData(activatedRouteSnapshot); if (this.hasDynamicTheme === true && isNotEmpty(this.themes)) { @@ -302,8 +298,10 @@ export class ThemeService { // Start with the resolved dso and go recursively through its parents until you reach the top-level community return observableOf(dsoRD.payload).pipe( this.getAncestorDSOs(), - map((dsos: DSpaceObject[]) => { - const dsoMatch = this.matchThemeToDSOs(dsos, currentRouteUrl); + switchMap((dsos: DSpaceObject[]) => { + return this.matchThemeToDSOs(dsos, currentRouteUrl); + }), + map((dsoMatch: Theme) => { return this.getActionForMatch(dsoMatch, currentTheme); }) ); @@ -316,33 +314,41 @@ export class ThemeService { getFirstSucceededRemoteData(), getRemoteDataPayload(), this.getAncestorDSOs(), - map((dsos: DSpaceObject[]) => { - const dsoMatch = this.matchThemeToDSOs(dsos, currentRouteUrl); + switchMap((dsos: DSpaceObject[]) => { + return this.matchThemeToDSOs(dsos, currentRouteUrl); + }), + map((dsoMatch: Theme) => { return this.getActionForMatch(dsoMatch, currentTheme); }) ); } // check whether the route itself matches - const routeMatch = this.themes.find((theme: Theme) => theme.matches(currentRouteUrl, undefined)); - - return [this.getActionForMatch(routeMatch, currentTheme)]; + return from(this.themes).pipe( + concatMap((theme: Theme) => theme.matches(currentRouteUrl, undefined).pipe( + filter((result: boolean) => result === true), + map(() => theme), + take(1), + )), + take(1), + map((theme: Theme) => this.getActionForMatch(theme, currentTheme)) + ); + } else { + // If there are no themes configured, do nothing + return observableOf(new NoOpAction()); } - - // If there are no themes configured, do nothing - return [new NoOpAction()]; }), take(1), ); action$.pipe( - filter((action) => action.type !== NO_OP_ACTION_TYPE), - ).subscribe((action) => { + filter((action: SetThemeAction | NoOpAction) => action.type !== NO_OP_ACTION_TYPE), + ).subscribe((action: SetThemeAction | NoOpAction) => { this.store.dispatch(action); }); return action$.pipe( - map((action) => action.type === ThemeActionTypes.SET), + map((action: SetThemeAction | NoOpAction) => action.type === ThemeActionTypes.SET), ); } @@ -433,14 +439,17 @@ export class ThemeService { * @param currentRouteUrl The url for the current route * @private */ - private matchThemeToDSOs(dsos: DSpaceObject[], currentRouteUrl: string): Theme { - // iterate over the themes in order, and return the first one that matches - return this.themes.find((theme: Theme) => { - // iterate over the dsos's in order (most specific one first, so Item, Collection, - // Community), and return the first one that matches the current theme - const match = dsos.find((dso: DSpaceObject) => theme.matches(currentRouteUrl, dso)); - return hasValue(match); - }); + private matchThemeToDSOs(dsos: DSpaceObject[], currentRouteUrl: string): Observable<Theme> { + return from(this.themes).pipe( + concatMap((theme: Theme) => from(dsos).pipe( + concatMap((dso: DSpaceObject) => theme.matches(currentRouteUrl, dso)), + filter((result: boolean) => result === true), + map(() => theme), + take(1), + )), + take(1), + defaultIfEmpty(undefined), + ); } /** diff --git a/src/config/theme.model.spec.ts b/src/config/theme.model.spec.ts index 79b5a1f32bf..d5005cb2457 100644 --- a/src/config/theme.model.spec.ts +++ b/src/config/theme.model.spec.ts @@ -9,12 +9,15 @@ import { Item } from '../app/core/shared/item.model'; import { ITEM } from '../app/core/shared/item.resource-type'; import { getItemModuleRoute } from '../app/item-page/item-page-routing-paths'; import { HandleService } from '../app/shared/handle.service'; +import { TestBed } from '@angular/core/testing'; +import { ConfigurationDataService } from '../app/core/data/configuration-data.service'; +import { ConfigurationDataServiceStub } from '../app/shared/testing/configuration-data.service.stub'; describe('Theme Models', () => { let theme: Theme; describe('RegExTheme', () => { - it('should return true when the regex matches the community\'s DSO route', () => { + it('should return true when the regex matches the community\'s DSO route', (done: DoneFn) => { theme = new RegExTheme({ name: 'community', regex: getCommunityModuleRoute() + '/.*', @@ -23,10 +26,13 @@ describe('Theme Models', () => { type: COMMUNITY.value, uuid: 'community-uuid', }); - expect(theme.matches('', dso)).toEqual(true); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return true when the regex matches the collection\'s DSO route', () => { + it('should return true when the regex matches the collection\'s DSO route', (done: DoneFn) => { theme = new RegExTheme({ name: 'collection', regex: getCollectionModuleRoute() + '/.*', @@ -35,10 +41,13 @@ describe('Theme Models', () => { type: COLLECTION.value, uuid: 'collection-uuid', }); - expect(theme.matches('', dso)).toEqual(true); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return true when the regex matches the item\'s DSO route', () => { + it('should return true when the regex matches the item\'s DSO route', (done: DoneFn) => { theme = new RegExTheme({ name: 'item', regex: getItemModuleRoute() + '/.*', @@ -47,32 +56,51 @@ describe('Theme Models', () => { type: ITEM.value, uuid: 'item-uuid', }); - expect(theme.matches('', dso)).toEqual(true); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return true when the regex matches the url', () => { + it('should return true when the regex matches the url', (done: DoneFn) => { theme = new RegExTheme({ name: 'url', regex: '.*partial.*', }); - expect(theme.matches('theme/partial/url/match', null)).toEqual(true); + theme.matches('theme/partial/url/match', null).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return false when the regex matches neither the url, nor the DSO route', () => { + it('should return false when the regex matches neither the url, nor the DSO route', (done: DoneFn) => { theme = new RegExTheme({ name: 'no-match', regex: '.*no/match.*', }); - expect(theme.matches('theme/partial/url/match', null)).toEqual(false); + theme.matches('theme/partial/url/match', null).subscribe((matches: boolean) => { + expect(matches).toBeFalse(); + done(); + }); }); }); describe('HandleTheme', () => { - let handleService; + let handleService: HandleService; + + let configurationService: ConfigurationDataServiceStub; + beforeEach(() => { - handleService = new HandleService(); + configurationService = new ConfigurationDataServiceStub(); + + TestBed.configureTestingModule({ + providers: [ + { provide: ConfigurationDataService, useValue: configurationService }, + ], }); - it('should return true when the DSO\'s handle matches the theme\'s handle', () => { + handleService = TestBed.inject(HandleService); + }); + it('should return true when the DSO\'s handle matches the theme\'s handle', (done: DoneFn) => { theme = new HandleTheme({ name: 'matching-handle', handle: '1234/5678', @@ -82,9 +110,12 @@ describe('Theme Models', () => { uuid: 'item-uuid', handle: '1234/5678', }, handleService); - expect(theme.matches('', matchingDso)).toEqual(true); + theme.matches('', matchingDso).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return false when the DSO\'s handle contains the theme\'s handle as a subpart', () => { + it('should return false when the DSO\'s handle contains the theme\'s handle as a subpart', (done: DoneFn) => { theme = new HandleTheme({ name: 'matching-handle', handle: '1234/5678', @@ -94,10 +125,13 @@ describe('Theme Models', () => { uuid: 'item-uuid', handle: '1234/567891011', }); - expect(theme.matches('', dso)).toEqual(false); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeFalse(); + done(); + }); }); - it('should return false when the handles don\'t match', () => { + it('should return false when the handles don\'t match', (done: DoneFn) => { theme = new HandleTheme({ name: 'no-matching-handle', handle: '1234/5678', @@ -107,12 +141,15 @@ describe('Theme Models', () => { uuid: 'item-uuid', handle: '1234/6789', }); - expect(theme.matches('', dso)).toEqual(false); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeFalse(); + done(); + }); }); }); describe('UUIDTheme', () => { - it('should return true when the DSO\'s UUID matches the theme\'s UUID', () => { + it('should return true when the DSO\'s UUID matches the theme\'s UUID', (done: DoneFn) => { theme = new UUIDTheme({ name: 'matching-uuid', uuid: 'item-uuid', @@ -121,10 +158,13 @@ describe('Theme Models', () => { type: ITEM.value, uuid: 'item-uuid', }); - expect(theme.matches('', dso)).toEqual(true); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeTrue(); + done(); + }); }); - it('should return true when the UUIDs don\'t match', () => { + it('should return true when the UUIDs don\'t match', (done: DoneFn) => { theme = new UUIDTheme({ name: 'matching-uuid', uuid: 'item-uuid', @@ -133,7 +173,10 @@ describe('Theme Models', () => { type: COLLECTION.value, uuid: 'collection-uuid', }); - expect(theme.matches('', dso)).toEqual(false); + theme.matches('', dso).subscribe((matches: boolean) => { + expect(matches).toBeFalse(); + done(); + }); }); }); }); diff --git a/src/config/theme.model.ts b/src/config/theme.model.ts index 019540f18a8..571d47a1d1d 100644 --- a/src/config/theme.model.ts +++ b/src/config/theme.model.ts @@ -6,6 +6,8 @@ import { getDSORoute } from '../app/app-routing-paths'; import { HandleObject } from '../app/core/shared/handle-object.model'; import { Injector } from '@angular/core'; import { HandleService } from '../app/shared/handle.service'; +import { combineLatest, Observable, of as observableOf } from 'rxjs'; +import { map, take } from 'rxjs/operators'; export interface NamedThemeConfig extends Config { name: string; @@ -55,8 +57,8 @@ export class Theme { constructor(public config: NamedThemeConfig) { } - matches(url: string, dso: DSpaceObject): boolean { - return true; + matches(url: string, dso: DSpaceObject): Observable<boolean> { + return observableOf(true); } } @@ -68,7 +70,7 @@ export class RegExTheme extends Theme { this.regex = new RegExp(this.config.regex); } - matches(url: string, dso: DSpaceObject): boolean { + matches(url: string, dso: DSpaceObject): Observable<boolean> { let match; const route = getDSORoute(dso); @@ -80,25 +82,33 @@ export class RegExTheme extends Theme { match = url.match(this.regex); } - return hasValue(match); + return observableOf(hasValue(match)); } } export class HandleTheme extends Theme { - private normalizedHandle; + private normalizedHandle$: Observable<string | null>; constructor(public config: HandleThemeConfig, protected handleService: HandleService ) { super(config); - this.normalizedHandle = this.handleService.normalizeHandle(this.config.handle); - + this.normalizedHandle$ = this.handleService.normalizeHandle(this.config.handle).pipe( + take(1), + ); } - matches<T extends DSpaceObject & HandleObject>(url: string, dso: T): boolean { - return hasValue(dso) && hasValue(dso.handle) - && this.handleService.normalizeHandle(dso.handle) === this.normalizedHandle; + matches<T extends DSpaceObject & HandleObject>(url: string, dso: T): Observable<boolean> { + return combineLatest([ + this.handleService.normalizeHandle(dso?.handle), + this.normalizedHandle$, + ]).pipe( + map(([handle, normalizedHandle]: [string | null, string | null]) => { + return hasValue(dso) && hasValue(dso.handle) && handle === normalizedHandle; + }), + take(1), + ); } } @@ -107,8 +117,8 @@ export class UUIDTheme extends Theme { super(config); } - matches(url: string, dso: DSpaceObject): boolean { - return hasValue(dso) && dso.uuid === this.config.uuid; + matches(url: string, dso: DSpaceObject): Observable<boolean> { + return observableOf(hasValue(dso) && dso.uuid === this.config.uuid); } } From da8880e5ba4ca1bff5936618391d14ce9a8d6153 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 31 Oct 2023 00:04:46 +0100 Subject: [PATCH 198/282] 107671: Split Theme model & ThemeConfig classes in separate files to prevent circular dependencies --- src/app/root/root.component.ts | 2 +- src/app/shared/mocks/theme-service.mock.ts | 2 +- .../listable-object.decorator.ts | 2 +- .../shared/theme-support}/theme.model.ts | 66 +++---------------- .../theme-support/theme.service.spec.ts | 2 +- src/app/shared/theme-support/theme.service.ts | 3 +- .../theme-support/themed.component.spec.ts | 2 +- src/config/app-config.interface.ts | 2 +- src/config/config.util.spec.ts | 2 +- src/config/config.util.ts | 2 +- src/config/default-app-config.ts | 2 +- src/config/theme.config.ts | 51 ++++++++++++++ src/config/theme.model.spec.ts | 2 +- 13 files changed, 71 insertions(+), 69 deletions(-) rename src/{config => app/shared/theme-support}/theme.model.ts (60%) create mode 100644 src/config/theme.config.ts diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index 3c2d65fc1f5..d7b33560d1b 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -13,7 +13,7 @@ import { AuthService } from '../core/auth/auth.service'; import { CSSVariableService } from '../shared/sass-helper/css-variable.service'; import { MenuService } from '../shared/menu/menu.service'; import { HostWindowService } from '../shared/host-window.service'; -import { ThemeConfig } from '../../config/theme.model'; +import { ThemeConfig } from '../../config/theme.config'; import { Angulartics2DSpace } from '../statistics/angulartics/dspace-provider'; import { environment } from '../../environments/environment'; import { slideSidebarPadding } from '../shared/animations/slide'; diff --git a/src/app/shared/mocks/theme-service.mock.ts b/src/app/shared/mocks/theme-service.mock.ts index e3c2960e51f..3997d175047 100644 --- a/src/app/shared/mocks/theme-service.mock.ts +++ b/src/app/shared/mocks/theme-service.mock.ts @@ -1,6 +1,6 @@ import { ThemeService } from '../theme-support/theme.service'; import { of as observableOf } from 'rxjs'; -import { ThemeConfig } from '../../../config/theme.model'; +import { ThemeConfig } from '../../../config/theme.config'; import { isNotEmpty } from '../empty.util'; export function getMockThemeService(themeName = 'base', themes?: ThemeConfig[]): ThemeService { diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts index e5654e63e00..470bcfcdafd 100644 --- a/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts +++ b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts @@ -4,7 +4,7 @@ import { hasNoValue, hasValue, isNotEmpty } from '../../../empty.util'; import { GenericConstructor } from '../../../../core/shared/generic-constructor'; import { ListableObject } from '../listable-object.model'; import { environment } from '../../../../../environments/environment'; -import { ThemeConfig } from '../../../../../config/theme.model'; +import { ThemeConfig } from '../../../../../config/theme.config'; import { InjectionToken } from '@angular/core'; export const DEFAULT_VIEW_MODE = ViewMode.ListElement; diff --git a/src/config/theme.model.ts b/src/app/shared/theme-support/theme.model.ts similarity index 60% rename from src/config/theme.model.ts rename to src/app/shared/theme-support/theme.model.ts index 571d47a1d1d..ce470dedc07 100644 --- a/src/config/theme.model.ts +++ b/src/app/shared/theme-support/theme.model.ts @@ -1,57 +1,13 @@ /* eslint-disable max-classes-per-file */ -import { Config } from './config.interface'; -import { hasValue, hasNoValue, isNotEmpty } from '../app/shared/empty.util'; -import { DSpaceObject } from '../app/core/shared/dspace-object.model'; -import { getDSORoute } from '../app/app-routing-paths'; -import { HandleObject } from '../app/core/shared/handle-object.model'; +import { hasValue, hasNoValue, isNotEmpty } from '../empty.util'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { getDSORoute } from '../../app-routing-paths'; +import { HandleObject } from '../../core/shared/handle-object.model'; import { Injector } from '@angular/core'; -import { HandleService } from '../app/shared/handle.service'; +import { HandleService } from '../handle.service'; import { combineLatest, Observable, of as observableOf } from 'rxjs'; import { map, take } from 'rxjs/operators'; - -export interface NamedThemeConfig extends Config { - name: string; - - /** - * Specify another theme to build upon: whenever a themed component is not found in the current theme, - * its ancestor theme(s) will be checked recursively before falling back to the default theme. - */ - extends?: string; - - /** - * A list of HTML tags that should be added to the HEAD section of the document, whenever this theme is active. - */ - headTags?: HeadTagConfig[]; -} - -/** - * Interface that represents a single theme-specific HTML tag in the HEAD section of the page. - */ -export interface HeadTagConfig extends Config { - /** - * The name of the HTML tag - */ - tagName: string; - - /** - * The attributes on the HTML tag - */ - attributes?: { - [key: string]: string; - }; -} - -export interface RegExThemeConfig extends NamedThemeConfig { - regex: string; -} - -export interface HandleThemeConfig extends NamedThemeConfig { - handle: string; -} - -export interface UUIDThemeConfig extends NamedThemeConfig { - uuid: string; -} +import { HandleThemeConfig, NamedThemeConfig, RegExThemeConfig, UUIDThemeConfig, ThemeConfig } from '../../../config/theme.config'; export class Theme { constructor(public config: NamedThemeConfig) { @@ -71,7 +27,7 @@ export class RegExTheme extends Theme { } matches(url: string, dso: DSpaceObject): Observable<boolean> { - let match; + let match: RegExpMatchArray; const route = getDSORoute(dso); if (isNotEmpty(route)) { @@ -92,7 +48,7 @@ export class HandleTheme extends Theme { constructor(public config: HandleThemeConfig, protected handleService: HandleService - ) { + ) { super(config); this.normalizedHandle$ = this.handleService.normalizeHandle(this.config.handle).pipe( take(1), @@ -133,9 +89,3 @@ export const themeFactory = (config: ThemeConfig, injector: Injector): Theme => return new Theme(config as NamedThemeConfig); } }; - -export type ThemeConfig - = NamedThemeConfig - | RegExThemeConfig - | HandleThemeConfig - | UUIDThemeConfig; diff --git a/src/app/shared/theme-support/theme.service.spec.ts b/src/app/shared/theme-support/theme.service.spec.ts index c4669408e1c..34dffe2ef21 100644 --- a/src/app/shared/theme-support/theme.service.spec.ts +++ b/src/app/shared/theme-support/theme.service.spec.ts @@ -4,7 +4,7 @@ import { provideMockActions } from '@ngrx/effects/testing'; import { LinkService } from '../../core/cache/builders/link.service'; import { hot } from 'jasmine-marbles'; import { SetThemeAction } from './theme.actions'; -import { Theme } from '../../../config/theme.model'; +import { Theme } from './theme.model'; import { provideMockStore } from '@ngrx/store/testing'; import { Community } from '../../core/shared/community.model'; import { COMMUNITY } from '../../core/shared/community.resource-type'; diff --git a/src/app/shared/theme-support/theme.service.ts b/src/app/shared/theme-support/theme.service.ts index daf2e3960e4..40aa559b23d 100644 --- a/src/app/shared/theme-support/theme.service.ts +++ b/src/app/shared/theme-support/theme.service.ts @@ -8,7 +8,8 @@ import { hasNoValue, hasValue, isNotEmpty } from '../empty.util'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload } from '../../core/shared/operators'; -import { HeadTagConfig, Theme, ThemeConfig, themeFactory } from '../../../config/theme.model'; +import { Theme, themeFactory } from './theme.model'; +import { ThemeConfig, HeadTagConfig } from '../../../config/theme.config'; import { NO_OP_ACTION_TYPE, NoOpAction } from '../ngrx/no-op.action'; import { followLink } from '../utils/follow-link-config.model'; import { LinkService } from '../../core/cache/builders/link.service'; diff --git a/src/app/shared/theme-support/themed.component.spec.ts b/src/app/shared/theme-support/themed.component.spec.ts index 7776e603798..3ddc13ab6c6 100644 --- a/src/app/shared/theme-support/themed.component.spec.ts +++ b/src/app/shared/theme-support/themed.component.spec.ts @@ -6,7 +6,7 @@ import { VarDirective } from '../utils/var.directive'; import { ThemeService } from './theme.service'; import { getMockThemeService } from '../mocks/theme-service.mock'; import { TestComponent } from './test/test.component.spec'; -import { ThemeConfig } from '../../../config/theme.model'; +import { ThemeConfig } from '../../../config/theme.config'; @Component({ selector: 'ds-test-themed-component', diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index 84a30549a72..69aeab7cbf8 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -9,7 +9,7 @@ import { FormConfig } from './form-config.interfaces'; import { LangConfig } from './lang-config.interface'; import { ItemConfig } from './item-config.interface'; import { CollectionPageConfig } from './collection-page-config.interface'; -import { ThemeConfig } from './theme.model'; +import { ThemeConfig } from './theme.config'; import { AuthConfig } from './auth-config.interfaces'; import { UIServerConfig } from './ui-server-config.interface'; import { MediaViewerConfig } from './media-viewer-config.interface'; diff --git a/src/config/config.util.spec.ts b/src/config/config.util.spec.ts index 2d1d8e1be79..4dc2b67260e 100644 --- a/src/config/config.util.spec.ts +++ b/src/config/config.util.spec.ts @@ -1,7 +1,7 @@ import { environment } from '../environments/environment.production'; import { extendEnvironmentWithAppConfig } from './config.util'; import { DefaultAppConfig } from './default-app-config'; -import { HandleThemeConfig } from './theme.model'; +import { HandleThemeConfig } from './theme.config'; describe('Config Util', () => { describe('extendEnvironmentWithAppConfig', () => { diff --git a/src/config/config.util.ts b/src/config/config.util.ts index 9912a817d6f..c1d87e34909 100644 --- a/src/config/config.util.ts +++ b/src/config/config.util.ts @@ -5,7 +5,7 @@ import { environment } from '../environments/environment'; import { hasNoValue } from '../app/shared/empty.util'; import { AppConfig } from './app-config.interface'; -import { ThemeConfig, NamedThemeConfig } from './theme.model'; +import { ThemeConfig, NamedThemeConfig } from './theme.config'; import { BASE_THEME_NAME } from '../app/shared/theme-support/theme.constants'; /** diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index a6e9e092e46..32bb6e0370b 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -12,7 +12,7 @@ import { MediaViewerConfig } from './media-viewer-config.interface'; import { INotificationBoardOptions } from './notifications-config.interfaces'; import { ServerConfig } from './server-config.interface'; import { SubmissionConfig } from './submission-config.interface'; -import { ThemeConfig } from './theme.model'; +import { ThemeConfig } from './theme.config'; import { UIServerConfig } from './ui-server-config.interface'; import { BundleConfig } from './bundle-config.interface'; import { ActuatorsConfig } from './actuators.config'; diff --git a/src/config/theme.config.ts b/src/config/theme.config.ts new file mode 100644 index 00000000000..7989dc3af9d --- /dev/null +++ b/src/config/theme.config.ts @@ -0,0 +1,51 @@ +import { Config } from './config.interface'; + +export interface NamedThemeConfig extends Config { + name: string; + + /** + * Specify another theme to build upon: whenever a themed component is not found in the current theme, + * its ancestor theme(s) will be checked recursively before falling back to the default theme. + */ + extends?: string; + + /** + * A list of HTML tags that should be added to the HEAD section of the document, whenever this theme is active. + */ + headTags?: HeadTagConfig[]; +} + +/** + * Interface that represents a single theme-specific HTML tag in the HEAD section of the page. + */ +export interface HeadTagConfig extends Config { + /** + * The name of the HTML tag + */ + tagName: string; + + /** + * The attributes on the HTML tag + */ + attributes?: { + [key: string]: string; + }; +} + +export interface RegExThemeConfig extends NamedThemeConfig { + regex: string; +} + +export interface HandleThemeConfig extends NamedThemeConfig { + handle: string; +} + +export interface UUIDThemeConfig extends NamedThemeConfig { + uuid: string; +} + +export type ThemeConfig + = NamedThemeConfig + | RegExThemeConfig + | HandleThemeConfig + | UUIDThemeConfig; diff --git a/src/config/theme.model.spec.ts b/src/config/theme.model.spec.ts index d5005cb2457..de2e2f7cef6 100644 --- a/src/config/theme.model.spec.ts +++ b/src/config/theme.model.spec.ts @@ -1,4 +1,4 @@ -import { HandleTheme, RegExTheme, Theme, UUIDTheme } from './theme.model'; +import { HandleTheme, RegExTheme, Theme, UUIDTheme } from '../app/shared/theme-support/theme.model'; import { getCommunityModuleRoute } from '../app/community-page/community-page-routing-paths'; import { Community } from '../app/core/shared/community.model'; import { COMMUNITY } from '../app/core/shared/community.resource-type'; From 4e54cca6004e0e28d532c175ac29895fe7e7c0db Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 1 Nov 2023 00:20:50 +0100 Subject: [PATCH 199/282] 107671: Fixed bug where config property would still sometimes be undefined whey calling the ngOnDestroy in the ThemedComponent --- .../community-page-sub-collection-list.component.ts | 11 +++++++---- .../community-page-sub-community-list.component.ts | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.ts b/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.ts index 3a77149e5be..ed14096ce03 100644 --- a/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.ts +++ b/src/app/community-page/sub-collection-list/community-page-sub-collection-list.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest as observableCombineLatest, Subscription } from 'rxjs'; import { RemoteData } from '../../core/data/remote-data'; import { Collection } from '../../core/shared/collection.model'; @@ -50,6 +50,8 @@ export class CommunityPageSubCollectionListComponent implements OnInit, OnDestro */ subCollectionsRDObs: BehaviorSubject<RemoteData<PaginatedList<Collection>>> = new BehaviorSubject<RemoteData<PaginatedList<Collection>>>({} as any); + subscriptions: Subscription[] = []; + constructor( protected cds: CollectionDataService, protected paginationService: PaginationService, @@ -77,7 +79,7 @@ export class CommunityPageSubCollectionListComponent implements OnInit, OnDestro const pagination$ = this.paginationService.getCurrentPagination(this.config.id, this.config); const sort$ = this.paginationService.getCurrentSort(this.config.id, this.sortConfig); - observableCombineLatest([pagination$, sort$]).pipe( + this.subscriptions.push(observableCombineLatest([pagination$, sort$]).pipe( switchMap(([currentPagination, currentSort]) => { return this.cds.findByParent(this.community.id, { currentPage: currentPagination.currentPage, @@ -87,11 +89,12 @@ export class CommunityPageSubCollectionListComponent implements OnInit, OnDestro }) ).subscribe((results) => { this.subCollectionsRDObs.next(results); - }); + })); } ngOnDestroy(): void { - this.paginationService.clearPagination(this.config.id); + this.paginationService.clearPagination(this.config?.id); + this.subscriptions.map((subscription: Subscription) => subscription.unsubscribe()); } } diff --git a/src/app/community-page/sub-community-list/community-page-sub-community-list.component.ts b/src/app/community-page/sub-community-list/community-page-sub-community-list.component.ts index 5a0409a0519..08c9509edbd 100644 --- a/src/app/community-page/sub-community-list/community-page-sub-community-list.component.ts +++ b/src/app/community-page/sub-community-list/community-page-sub-community-list.component.ts @@ -1,7 +1,7 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { BehaviorSubject, combineLatest as observableCombineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest as observableCombineLatest, Subscription } from 'rxjs'; import { RemoteData } from '../../core/data/remote-data'; import { Community } from '../../core/shared/community.model'; @@ -52,6 +52,8 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy */ subCommunitiesRDObs: BehaviorSubject<RemoteData<PaginatedList<Community>>> = new BehaviorSubject<RemoteData<PaginatedList<Community>>>({} as any); + subscriptions: Subscription[] = []; + constructor( protected cds: CommunityDataService, protected paginationService: PaginationService, @@ -79,7 +81,7 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy const pagination$ = this.paginationService.getCurrentPagination(this.config.id, this.config); const sort$ = this.paginationService.getCurrentSort(this.config.id, this.sortConfig); - observableCombineLatest([pagination$, sort$]).pipe( + this.subscriptions.push(observableCombineLatest([pagination$, sort$]).pipe( switchMap(([currentPagination, currentSort]) => { return this.cds.findByParent(this.community.id, { currentPage: currentPagination.currentPage, @@ -89,11 +91,12 @@ export class CommunityPageSubCommunityListComponent implements OnInit, OnDestroy }) ).subscribe((results) => { this.subCommunitiesRDObs.next(results); - }); + })); } ngOnDestroy(): void { - this.paginationService.clearPagination(this.config.id); + this.paginationService.clearPagination(this.config?.id); + this.subscriptions.map((subscription: Subscription) => subscription.unsubscribe()); } } From 3bf2eb1997aff92abc9bb7f642d5e7c77866d552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= <paulo1978@gmail.com> Date: Fri, 10 Nov 2023 00:04:45 +0000 Subject: [PATCH 200/282] Create new access-status-badge.component.scss --- .../access-status-badge/access-status-badge.component.scss | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.scss diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.scss b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.scss new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.scss @@ -0,0 +1 @@ + From 6378dbec4afc635a3e3e3dc37f573122a5097746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= <paulo1978@gmail.com> Date: Fri, 10 Nov 2023 00:09:46 +0000 Subject: [PATCH 201/282] new accessStatusClass atribute --- .../access-status-badge.component.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts index 2be44669b02..e7bb15a75ba 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts @@ -11,7 +11,8 @@ import { ITEM } from '../../../../../core/shared/item.resource-type'; @Component({ selector: 'ds-access-status-badge', - templateUrl: './access-status-badge.component.html' + templateUrl: './access-status-badge.component.html', + styleUrls: ['./access-status-badge.component.scss'] }) /** * Component rendering the access status of an item as a badge @@ -26,6 +27,11 @@ export class AccessStatusBadgeComponent { */ showAccessStatus: boolean; + /** + * Value based stylesheet class for access status badge + */ + accessStatusClass: string; + /** * Initialize instance variables * @@ -57,5 +63,12 @@ export class AccessStatusBadgeComponent { map((status: string) => `access-status.${status.toLowerCase()}.listelement.badge`), catchError(() => observableOf('access-status.unknown.listelement.badge')) ); + + // stylesheet based on the access status value + this.accessStatus$.pipe( + map((accessStatusClass: string) => accessStatusClass.replace(/\./g, '-')) + ).subscribe((accessStatusClass: string) => { + this.accessStatusClass = accessStatusClass; + }); } } From c7eae9242a69cb9a598c2a55843dda72f5125ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= <paulo1978@gmail.com> Date: Fri, 10 Nov 2023 00:10:55 +0000 Subject: [PATCH 202/282] remove replaceAll and use an object property --- .../access-status-badge/access-status-badge.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html index 264bd3621ca..5b20860684b 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.html @@ -1,5 +1,5 @@ <ng-container *ngIf="showAccessStatus"> <span *ngIf="accessStatus$ | async as accessStatus"> - <span [class]="'badge badge-secondary access-status-list-element-badge ' + accessStatus.replaceAll('.','-')">{{ accessStatus | translate }}</span> + <span [class]="'badge badge-secondary access-status-list-element-badge ' + accessStatusClass">{{ accessStatus | translate }}</span> </span> </ng-container> From 6e6cfbb86e845afb12374648b1239409c7fad1d0 Mon Sep 17 00:00:00 2001 From: lotte <lotte_hofstede@hotmail.com> Date: Thu, 9 Nov 2023 15:46:57 +0100 Subject: [PATCH 203/282] 108045: Fix for repeatable date field labels --- .../models/date-picker/date-picker.component.html | 2 +- .../ds-dynamic-form-ui/models/date-picker/date-picker.model.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html index 1046dd6b2d3..26803f3c67b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html @@ -1,6 +1,6 @@ <div> <fieldset class="d-flex"> - <legend [id]="'legend_' + model.id" [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"> + <legend *ngIf="!model.repeatable" [id]="'legend_' + model.id" [ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]"> {{model.placeholder}} <span *ngIf="model.required">*</span> </legend> <ds-number-picker diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts index 5af9b2bd323..88820cdaa33 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.model.ts @@ -15,6 +15,7 @@ export const DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER = 'DATE'; export interface DynamicDsDateControlModelConfig extends DynamicDatePickerModelConfig { legend?: string; typeBindRelations?: DynamicFormControlRelation[]; + repeatable: boolean; } /** @@ -37,7 +38,7 @@ export class DynamicDsDatePickerModel extends DynamicDateControlModel { this.metadataValue = (config as any).metadataValue; this.typeBindRelations = config.typeBindRelations ? config.typeBindRelations : []; this.hiddenUpdates = new BehaviorSubject<boolean>(this.hidden); - + this.repeatable = config.repeatable; // This was a subscription, then an async setTimeout, but it seems unnecessary const parentModel = this.getRootParent(this); if (parentModel && isNotUndefined(parentModel.hidden)) { From ccf1cc45473a8a92d117215adc0eb650a27d6d77 Mon Sep 17 00:00:00 2001 From: Vlad Nouski <uladzislau.nouski@4science.com> Date: Fri, 10 Nov 2023 14:38:56 +0100 Subject: [PATCH 204/282] [DURACOM-202] feature: item edit pages are accessible by administrator --- .../edit-item-page.routing.module.ts | 10 ++++-- .../item-page-access-control.guard.ts | 31 +++++++++++++++++++ .../edit-item-page/item-page-curate.guard.ts | 31 +++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/app/item-page/edit-item-page/item-page-access-control.guard.ts create mode 100644 src/app/item-page/edit-item-page/item-page-curate.guard.ts diff --git a/src/app/item-page/edit-item-page/edit-item-page.routing.module.ts b/src/app/item-page/edit-item-page/edit-item-page.routing.module.ts index f22027916fe..5266b1b926d 100644 --- a/src/app/item-page/edit-item-page/edit-item-page.routing.module.ts +++ b/src/app/item-page/edit-item-page/edit-item-page.routing.module.ts @@ -38,6 +38,8 @@ import { ItemPageBitstreamsGuard } from './item-page-bitstreams.guard'; import { ItemPageRelationshipsGuard } from './item-page-relationships.guard'; import { ItemPageVersionHistoryGuard } from './item-page-version-history.guard'; import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.guard'; +import { ItemPageCurateGuard } from './item-page-curate.guard'; +import { ItemPageAccessControlGuard } from './item-page-access-control.guard'; import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component'; import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard'; import { ItemCurateComponent } from './item-curate/item-curate.component'; @@ -87,7 +89,8 @@ import { ItemAccessControlComponent } from './item-access-control/item-access-co { path: 'curate', component: ItemCurateComponent, - data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true } + data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true }, + canActivate: [ItemPageCurateGuard] }, { path: 'relationships', @@ -116,7 +119,8 @@ import { ItemAccessControlComponent } from './item-access-control/item-access-co { path: 'access-control', component: ItemAccessControlComponent, - data: { title: 'item.edit.tabs.access-control.title', showBreadcrumbs: true } + data: { title: 'item.edit.tabs.access-control.title', showBreadcrumbs: true }, + canActivate: [ItemPageAccessControlGuard] }, { path: 'mapper', @@ -202,11 +206,13 @@ import { ItemAccessControlComponent } from './item-access-control/item-access-co ItemPageWithdrawGuard, ItemPageAdministratorGuard, ItemPageMetadataGuard, + ItemPageCurateGuard, ItemPageStatusGuard, ItemPageBitstreamsGuard, ItemPageRelationshipsGuard, ItemPageVersionHistoryGuard, ItemPageCollectionMapperGuard, + ItemPageAccessControlGuard, ItemPageRegisterDoiGuard, ] }) diff --git a/src/app/item-page/edit-item-page/item-page-access-control.guard.ts b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts new file mode 100644 index 00000000000..49975e5cfe9 --- /dev/null +++ b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { ItemPageResolver } from '../item-page.resolver'; +import { Item } from '../../core/shared/item.model'; +import { DsoPageSingleFeatureGuard } from '../../core/data/feature-authorization/feature-authorization-guard/dso-page-single-feature.guard'; +import { Observable, of as observableOf } from 'rxjs'; +import { FeatureID } from '../../core/data/feature-authorization/feature-id'; +import { AuthService } from '../../core/auth/auth.service'; + +@Injectable({ + providedIn: 'root' +}) +/** + * Guard for preventing unauthorized access to certain {@link Item} pages requiring manage mappings rights + */ +export class ItemPageAccessControlGuard extends DsoPageSingleFeatureGuard<Item> { + constructor(protected resolver: ItemPageResolver, + protected authorizationService: AuthorizationDataService, + protected router: Router, + protected authService: AuthService) { + super(resolver, authorizationService, router, authService); + } + + /** + * Check manage mappings authorization rights + */ + getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> { + return observableOf(FeatureID.AdministratorOf); + } +} diff --git a/src/app/item-page/edit-item-page/item-page-curate.guard.ts b/src/app/item-page/edit-item-page/item-page-curate.guard.ts new file mode 100644 index 00000000000..b0594e016b2 --- /dev/null +++ b/src/app/item-page/edit-item-page/item-page-curate.guard.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; +import { ItemPageResolver } from '../item-page.resolver'; +import { Item } from '../../core/shared/item.model'; +import { DsoPageSingleFeatureGuard } from '../../core/data/feature-authorization/feature-authorization-guard/dso-page-single-feature.guard'; +import { Observable, of as observableOf } from 'rxjs'; +import { FeatureID } from '../../core/data/feature-authorization/feature-id'; +import { AuthService } from '../../core/auth/auth.service'; + +@Injectable({ + providedIn: 'root' +}) +/** + * Guard for preventing unauthorized access to certain {@link Item} pages requiring edit metadata rights + */ +export class ItemPageCurateGuard extends DsoPageSingleFeatureGuard<Item> { + constructor(protected resolver: ItemPageResolver, + protected authorizationService: AuthorizationDataService, + protected router: Router, + protected authService: AuthService) { + super(resolver, authorizationService, router, authService); + } + + /** + * Check edit curate authorization rights + */ + getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> { + return observableOf(FeatureID.AdministratorOf); + } +} From a3181a06899896f1ee7f97d31dd7687995be99a9 Mon Sep 17 00:00:00 2001 From: lotte <lotte_hofstede@hotmail.com> Date: Fri, 10 Nov 2023 14:42:03 +0100 Subject: [PATCH 205/282] Fixed test --- .../ds-dynamic-form-control-container.component.spec.ts | 2 +- .../models/date-picker/date-picker.component.spec.ts | 1 + src/app/shared/form/builder/form-builder.service.spec.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts index e0e519aaa92..5cdcfba537b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts @@ -165,7 +165,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => { metadataFields: [], hasSelectableMetadata: false }), - new DynamicDsDatePickerModel({ id: 'datepicker' }), + new DynamicDsDatePickerModel({ id: 'datepicker', repeatable: false }), new DynamicLookupModel({ id: 'lookup', metadataFields: [], diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts index 4989dab93a7..eb35af9dbe8 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts @@ -28,6 +28,7 @@ export const DATE_TEST_MODEL_CONFIG = { placeholder: 'Date', readOnly: false, required: true, + repeatable: false, toggleIcon: 'fas fa-calendar' }; diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts index b68963e5ad5..91f3cbcafc7 100644 --- a/src/app/shared/form/builder/form-builder.service.spec.ts +++ b/src/app/shared/form/builder/form-builder.service.spec.ts @@ -284,7 +284,7 @@ describe('FormBuilderService test suite', () => { hasSelectableMetadata: true }), - new DynamicDsDatePickerModel({ id: 'testDate' }), + new DynamicDsDatePickerModel({ id: 'testDate', repeatable: false}), new DynamicLookupModel({ id: 'testLookup', From b6d515ff09011d6ceef358c6836f2616cc059657 Mon Sep 17 00:00:00 2001 From: Vlad Nouski <uladzislau.nouski@4science.com> Date: Fri, 10 Nov 2023 15:09:02 +0100 Subject: [PATCH 206/282] [DURACOM-202] refactor: code --- .../item-page/edit-item-page/item-page-access-control.guard.ts | 2 +- src/app/item-page/edit-item-page/item-page-curate.guard.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-page-access-control.guard.ts b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts index 49975e5cfe9..a036fd95765 100644 --- a/src/app/item-page/edit-item-page/item-page-access-control.guard.ts +++ b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts @@ -12,7 +12,7 @@ import { AuthService } from '../../core/auth/auth.service'; providedIn: 'root' }) /** - * Guard for preventing unauthorized access to certain {@link Item} pages requiring manage mappings rights + * Guard for preventing unauthorized access to certain {@link Item} pages requiring administrator rights */ export class ItemPageAccessControlGuard extends DsoPageSingleFeatureGuard<Item> { constructor(protected resolver: ItemPageResolver, diff --git a/src/app/item-page/edit-item-page/item-page-curate.guard.ts b/src/app/item-page/edit-item-page/item-page-curate.guard.ts index b0594e016b2..40f9444524a 100644 --- a/src/app/item-page/edit-item-page/item-page-curate.guard.ts +++ b/src/app/item-page/edit-item-page/item-page-curate.guard.ts @@ -12,7 +12,7 @@ import { AuthService } from '../../core/auth/auth.service'; providedIn: 'root' }) /** - * Guard for preventing unauthorized access to certain {@link Item} pages requiring edit metadata rights + * Guard for preventing unauthorized access to certain {@link Item} pages requiring administrator rights */ export class ItemPageCurateGuard extends DsoPageSingleFeatureGuard<Item> { constructor(protected resolver: ItemPageResolver, From 6f64db1645623d9ac735ccab107439c77cc9969f Mon Sep 17 00:00:00 2001 From: Vlad Nouski <uladzislau.nouski@4science.com> Date: Fri, 10 Nov 2023 15:11:09 +0100 Subject: [PATCH 207/282] [DURACOM-202] refactor: code --- .../item-page/edit-item-page/item-page-access-control.guard.ts | 2 +- src/app/item-page/edit-item-page/item-page-curate.guard.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-page-access-control.guard.ts b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts index a036fd95765..9bc953db1e6 100644 --- a/src/app/item-page/edit-item-page/item-page-access-control.guard.ts +++ b/src/app/item-page/edit-item-page/item-page-access-control.guard.ts @@ -23,7 +23,7 @@ export class ItemPageAccessControlGuard extends DsoPageSingleFeatureGuard<Item> } /** - * Check manage mappings authorization rights + * Check administrator authorization rights */ getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> { return observableOf(FeatureID.AdministratorOf); diff --git a/src/app/item-page/edit-item-page/item-page-curate.guard.ts b/src/app/item-page/edit-item-page/item-page-curate.guard.ts index 40f9444524a..387b1b8bb9e 100644 --- a/src/app/item-page/edit-item-page/item-page-curate.guard.ts +++ b/src/app/item-page/edit-item-page/item-page-curate.guard.ts @@ -23,7 +23,7 @@ export class ItemPageCurateGuard extends DsoPageSingleFeatureGuard<Item> { } /** - * Check edit curate authorization rights + * Check administrator authorization rights */ getFeatureID(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<FeatureID> { return observableOf(FeatureID.AdministratorOf); From 75b788d05b819715feefc31e645d97368ae63054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulo=20Gra=C3=A7a?= <paulo1978@gmail.com> Date: Fri, 10 Nov 2023 15:19:36 +0000 Subject: [PATCH 208/282] adding ngOnDestroy for dealing with unsubscribe --- .../access-status-badge.component.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts index e7bb15a75ba..5f27ba4f65d 100644 --- a/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts +++ b/src/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { catchError, map } from 'rxjs/operators'; -import { Observable, of as observableOf } from 'rxjs'; +import { Observable, of as observableOf, Subscription } from 'rxjs'; import { AccessStatusObject } from './access-status.model'; import { hasValue } from '../../../../empty.util'; import { environment } from 'src/environments/environment'; @@ -32,6 +32,11 @@ export class AccessStatusBadgeComponent { */ accessStatusClass: string; + /** + * List of subscriptions + */ + subs: Subscription[] = []; + /** * Initialize instance variables * @@ -65,10 +70,16 @@ export class AccessStatusBadgeComponent { ); // stylesheet based on the access status value - this.accessStatus$.pipe( - map((accessStatusClass: string) => accessStatusClass.replace(/\./g, '-')) - ).subscribe((accessStatusClass: string) => { - this.accessStatusClass = accessStatusClass; - }); + this.subs.push( + this.accessStatus$.pipe( + map((accessStatusClass: string) => accessStatusClass.replace(/\./g, '-')) + ).subscribe((accessStatusClass: string) => { + this.accessStatusClass = accessStatusClass; + }) + ); + } + + ngOnDestroy(): void { + this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe()); } } From ef9f31d3c612b5aa93a9f8950888bd034ad03d01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:44:04 +0000 Subject: [PATCH 209/282] Bump axios from 0.27.2 to 1.6.0 Bumps [axios](https://github.com/axios/axios) from 0.27.2 to 1.6.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.27.2...v1.6.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> --- package.json | 2 +- yarn.lock | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 3e23de10151..553962dfeb7 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "@types/grecaptcha": "^3.0.4", "angular-idle-preload": "3.0.0", "angulartics2": "^12.2.0", - "axios": "^0.27.2", + "axios": "^1.6.0", "bootstrap": "^4.6.1", "cerialize": "0.1.18", "cli-progress": "^3.12.0", diff --git a/yarn.lock b/yarn.lock index dff9302cc72..27307aefa2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3467,13 +3467,14 @@ axios@0.21.4: dependencies: follow-redirects "^1.14.0" -axios@^0.27.2: - version "0.27.2" - resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== +axios@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== dependencies: - follow-redirects "^1.14.9" + follow-redirects "^1.15.0" form-data "^4.0.0" + proxy-from-env "^1.1.0" axobject-query@3.1.1: version "3.1.1" @@ -5857,10 +5858,10 @@ flatted@^3.1.0, flatted@^3.2.7: resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.14.9: - version "1.15.2" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.15.0: + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== for-each@^0.3.3: version "0.3.3" @@ -9478,6 +9479,11 @@ proxy-from-env@1.0.0: resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz" integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" From 7529ed8b350878bda844138a3c78a6587a3034a9 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 11 Nov 2023 02:03:39 +0100 Subject: [PATCH 210/282] 107671: Fixed theme matching by handle not working in production mode --- src/app/shared/handle.service.spec.ts | 17 ++++++++--- src/app/shared/handle.service.ts | 31 +++++++++------------ src/app/shared/theme-support/theme.model.ts | 27 +++++++++--------- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/app/shared/handle.service.spec.ts b/src/app/shared/handle.service.spec.ts index a499bdd464d..8203940c6ad 100644 --- a/src/app/shared/handle.service.spec.ts +++ b/src/app/shared/handle.service.spec.ts @@ -1,8 +1,9 @@ -import { HandleService } from './handle.service'; +import { HandleService, CANONICAL_PREFIX_KEY } from './handle.service'; import { TestBed } from '@angular/core/testing'; import { ConfigurationDataServiceStub } from './testing/configuration-data.service.stub'; import { ConfigurationDataService } from '../core/data/configuration-data.service'; -import { of as observableOf } from 'rxjs'; +import { createSuccessfulRemoteDataObject$ } from './remote-data.utils'; +import { ConfigurationProperty } from '../core/shared/configuration-property.model'; describe('HandleService', () => { let service: HandleService; @@ -22,7 +23,11 @@ describe('HandleService', () => { describe(`normalizeHandle`, () => { it('should normalize a handle url with custom conical prefix with trailing slash', (done: DoneFn) => { - service.canonicalPrefix$ = observableOf('https://hdl.handle.net/'); + spyOn(configurationService, 'findByPropertyName').and.returnValue(createSuccessfulRemoteDataObject$({ + ... new ConfigurationProperty(), + name: CANONICAL_PREFIX_KEY, + values: ['https://hdl.handle.net/'], + })); service.normalizeHandle('https://hdl.handle.net/123456789/123456').subscribe((handle: string | null) => { expect(handle).toBe('123456789/123456'); @@ -31,7 +36,11 @@ describe('HandleService', () => { }); it('should normalize a handle url with custom conical prefix without trailing slash', (done: DoneFn) => { - service.canonicalPrefix$ = observableOf('https://hdl.handle.net'); + spyOn(configurationService, 'findByPropertyName').and.returnValue(createSuccessfulRemoteDataObject$({ + ... new ConfigurationProperty(), + name: CANONICAL_PREFIX_KEY, + values: ['https://hdl.handle.net/'], + })); service.normalizeHandle('https://hdl.handle.net/123456789/123456').subscribe((handle: string | null) => { expect(handle).toBe('123456789/123456'); diff --git a/src/app/shared/handle.service.ts b/src/app/shared/handle.service.ts index 56b3922753b..1f22c7d3045 100644 --- a/src/app/shared/handle.service.ts +++ b/src/app/shared/handle.service.ts @@ -4,7 +4,7 @@ import { ConfigurationDataService } from '../core/data/configuration-data.servic import { getFirstCompletedRemoteData } from '../core/shared/operators'; import { map, take } from 'rxjs/operators'; import { ConfigurationProperty } from '../core/shared/configuration-property.model'; -import { Observable } from 'rxjs'; +import { Observable, of as observableOf } from 'rxjs'; import { RemoteData } from '../core/data/remote-data'; export const CANONICAL_PREFIX_KEY = 'handle.canonical.prefix'; @@ -20,22 +20,9 @@ const NO_PREFIX_REGEX = /^([^\/]+\/[^\/]+)$/; }) export class HandleService { - canonicalPrefix$: Observable<string | undefined>; - constructor( protected configurationService: ConfigurationDataService, ) { - this.canonicalPrefix$ = this.configurationService.findByPropertyName(CANONICAL_PREFIX_KEY).pipe( - getFirstCompletedRemoteData(), - take(1), - map((configurationPropertyRD: RemoteData<ConfigurationProperty>) => { - if (configurationPropertyRD.hasSucceeded) { - return configurationPropertyRD.payload.values.length >= 1 ? configurationPropertyRD.payload.values[0] : undefined; - } else { - return undefined; - } - }), - ); } /** @@ -55,12 +42,20 @@ export class HandleService { * </ul> */ normalizeHandle(handle: string): Observable<string | null> { - return this.canonicalPrefix$.pipe( + if (hasNoValue(handle)) { + return observableOf(null); + } + return this.configurationService.findByPropertyName(CANONICAL_PREFIX_KEY).pipe( + getFirstCompletedRemoteData(), + map((configurationPropertyRD: RemoteData<ConfigurationProperty>) => { + if (configurationPropertyRD.hasSucceeded) { + return configurationPropertyRD.payload.values.length >= 1 ? configurationPropertyRD.payload.values[0] : undefined; + } else { + return undefined; + } + }), map((prefix: string | undefined) => { let matches: string[]; - if (hasNoValue(handle)) { - return null; - } matches = handle.match(PREFIX_REGEX(prefix)); diff --git a/src/app/shared/theme-support/theme.model.ts b/src/app/shared/theme-support/theme.model.ts index ce470dedc07..470f09853c3 100644 --- a/src/app/shared/theme-support/theme.model.ts +++ b/src/app/shared/theme-support/theme.model.ts @@ -44,27 +44,26 @@ export class RegExTheme extends Theme { export class HandleTheme extends Theme { - private normalizedHandle$: Observable<string | null>; - constructor(public config: HandleThemeConfig, protected handleService: HandleService ) { super(config); - this.normalizedHandle$ = this.handleService.normalizeHandle(this.config.handle).pipe( - take(1), - ); } matches<T extends DSpaceObject & HandleObject>(url: string, dso: T): Observable<boolean> { - return combineLatest([ - this.handleService.normalizeHandle(dso?.handle), - this.normalizedHandle$, - ]).pipe( - map(([handle, normalizedHandle]: [string | null, string | null]) => { - return hasValue(dso) && hasValue(dso.handle) && handle === normalizedHandle; - }), - take(1), - ); + if (hasValue(dso?.handle)) { + return combineLatest([ + this.handleService.normalizeHandle(dso?.handle), + this.handleService.normalizeHandle(this.config.handle), + ]).pipe( + map(([handle, normalizedHandle]: [string | null, string | null]) => { + return hasValue(dso) && hasValue(dso.handle) && handle === normalizedHandle; + }), + take(1), + ); + } else { + return observableOf(false); + } } } From b894dce3b0d4e98c7859efe40a1112bbb3265538 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 11 Nov 2023 19:31:01 +0100 Subject: [PATCH 211/282] Fix handle redirect not working with custom nameSpace --- src/app/core/data/dso-redirect.service.spec.ts | 11 +++++++---- src/app/core/data/dso-redirect.service.ts | 6 ++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/app/core/data/dso-redirect.service.spec.ts b/src/app/core/data/dso-redirect.service.spec.ts index 2122dc663a1..9271bd5f7f4 100644 --- a/src/app/core/data/dso-redirect.service.spec.ts +++ b/src/app/core/data/dso-redirect.service.spec.ts @@ -11,6 +11,8 @@ import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils import { Item } from '../shared/item.model'; import { EMBED_SEPARATOR } from './base/base-data.service'; import { HardRedirectService } from '../services/hard-redirect.service'; +import { environment } from '../../../environments/environment.test'; +import { AppConfig } from '../../../config/app-config.interface'; describe('DsoRedirectService', () => { let scheduler: TestScheduler; @@ -56,6 +58,7 @@ describe('DsoRedirectService', () => { }); service = new DsoRedirectService( + environment as AppConfig, requestService, rdbService, objectCache, @@ -107,7 +110,7 @@ describe('DsoRedirectService', () => { redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); - expect(redirectService.redirect).toHaveBeenCalledWith('/items/' + remoteData.payload.uuid, 301); + expect(redirectService.redirect).toHaveBeenCalledWith(`${environment.ui.nameSpace}/items/${remoteData.payload.uuid}`, 301); }); it('should navigate to entities route with the corresponding entity type', () => { remoteData.payload.type = 'item'; @@ -124,7 +127,7 @@ describe('DsoRedirectService', () => { redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); - expect(redirectService.redirect).toHaveBeenCalledWith('/entities/publication/' + remoteData.payload.uuid, 301); + expect(redirectService.redirect).toHaveBeenCalledWith(`${environment.ui.nameSpace}/entities/publication/${remoteData.payload.uuid}`, 301); }); it('should navigate to collections route', () => { @@ -133,7 +136,7 @@ describe('DsoRedirectService', () => { redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); - expect(redirectService.redirect).toHaveBeenCalledWith('/collections/' + remoteData.payload.uuid, 301); + expect(redirectService.redirect).toHaveBeenCalledWith(`${environment.ui.nameSpace}/collections/${remoteData.payload.uuid}`, 301); }); it('should navigate to communities route', () => { @@ -142,7 +145,7 @@ describe('DsoRedirectService', () => { redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); - expect(redirectService.redirect).toHaveBeenCalledWith('/communities/' + remoteData.payload.uuid, 301); + expect(redirectService.redirect).toHaveBeenCalledWith(`${environment.ui.nameSpace}/communities/${remoteData.payload.uuid}`, 301); }); }); diff --git a/src/app/core/data/dso-redirect.service.ts b/src/app/core/data/dso-redirect.service.ts index a27d1fb11f3..4585df5b4bd 100644 --- a/src/app/core/data/dso-redirect.service.ts +++ b/src/app/core/data/dso-redirect.service.ts @@ -6,7 +6,7 @@ * http://www.dspace.org/license/ */ /* eslint-disable max-classes-per-file */ -import { Injectable } from '@angular/core'; +import { Injectable, Inject } from '@angular/core'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { hasValue } from '../../shared/empty.util'; @@ -21,6 +21,7 @@ import { DSpaceObject } from '../shared/dspace-object.model'; import { IdentifiableDataService } from './base/identifiable-data.service'; import { getDSORoute } from '../../app-routing-paths'; import { HardRedirectService } from '../services/hard-redirect.service'; +import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface'; const ID_ENDPOINT = 'pid'; const UUID_ENDPOINT = 'dso'; @@ -70,6 +71,7 @@ export class DsoRedirectService { private dataService: DsoByIdOrUUIDDataService; constructor( + @Inject(APP_CONFIG) protected appConfig: AppConfig, protected requestService: RequestService, protected rdbService: RemoteDataBuildService, protected objectCache: ObjectCacheService, @@ -98,7 +100,7 @@ export class DsoRedirectService { let newRoute = getDSORoute(dso); if (hasValue(newRoute)) { // Use a "301 Moved Permanently" redirect for SEO purposes - this.hardRedirectService.redirect(newRoute, 301); + this.hardRedirectService.redirect(this.appConfig.ui.nameSpace.replace(/\/$/, '') + newRoute, 301); } } } From 35f8b55f588985146482313a6ebad80154b6edbd Mon Sep 17 00:00:00 2001 From: Vlad Nouski <uladzislau.nouski@4science.com> Date: Tue, 31 Oct 2023 14:21:42 +0100 Subject: [PATCH 212/282] fix: random order of buttons in status tab --- .../item-operation/itemOperation.model.ts | 8 + .../item-status/item-status.component.html | 2 +- .../item-status/item-status.component.ts | 212 +++++++++--------- 3 files changed, 121 insertions(+), 101 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-operation/itemOperation.model.ts b/src/app/item-page/edit-item-page/item-operation/itemOperation.model.ts index 33302dcba6c..a6f08ac95ce 100644 --- a/src/app/item-page/edit-item-page/item-operation/itemOperation.model.ts +++ b/src/app/item-page/edit-item-page/item-operation/itemOperation.model.ts @@ -28,4 +28,12 @@ export class ItemOperation { this.disabled = disabled; } + /** + * Set whether this operation is authorized + * @param authorized + */ + setAuthorized(authorized: boolean): void { + this.authorized = authorized; + } + } diff --git a/src/app/item-page/edit-item-page/item-status/item-status.component.html b/src/app/item-page/edit-item-page/item-status/item-status.component.html index 8d4faaa2ac5..155b9478043 100644 --- a/src/app/item-page/edit-item-page/item-status/item-status.component.html +++ b/src/app/item-page/edit-item-page/item-status/item-status.component.html @@ -27,7 +27,7 @@ </div> <div *ngFor="let operation of (operations$ | async)" class="w-100" [ngClass]="{'pt-3': operation}"> - <ds-item-operation *ngIf="operation" [operation]="operation"></ds-item-operation> + <ds-item-operation [operation]="operation"></ds-item-operation> </div> </div> diff --git a/src/app/item-page/edit-item-page/item-status/item-status.component.ts b/src/app/item-page/edit-item-page/item-status/item-status.component.ts index 828f8d74391..8e04985c184 100644 --- a/src/app/item-page/edit-item-page/item-status/item-status.component.ts +++ b/src/app/item-page/edit-item-page/item-status/item-status.component.ts @@ -3,21 +3,20 @@ import { fadeIn, fadeInOut } from '../../../shared/animations/fade'; import { Item } from '../../../core/shared/item.model'; import { ActivatedRoute } from '@angular/router'; import { ItemOperation } from '../item-operation/itemOperation.model'; -import { distinctUntilChanged, map, mergeMap, switchMap, toArray } from 'rxjs/operators'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { concatMap, distinctUntilChanged, first, map, mergeMap, switchMap, toArray } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, Observable, of, Subscription } from 'rxjs'; import { RemoteData } from '../../../core/data/remote-data'; import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; -import { hasValue, isNotEmpty } from '../../../shared/empty.util'; -import { - getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload, -} from '../../../core/shared/operators'; +import { hasValue } from '../../../shared/empty.util'; +import { getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, } from '../../../core/shared/operators'; import { IdentifierDataService } from '../../../core/data/identifier-data.service'; import { Identifier } from '../../../shared/object-list/identifier-data/identifier.model'; import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; import { IdentifierData } from '../../../shared/object-list/identifier-data/identifier-data.model'; +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; @Component({ selector: 'ds-item-status', @@ -73,6 +72,7 @@ export class ItemStatusComponent implements OnInit { private authorizationService: AuthorizationDataService, private identifierDataService: IdentifierDataService, private configurationService: ConfigurationDataService, + private orcidAuthService: OrcidAuthService ) { } @@ -82,14 +82,16 @@ export class ItemStatusComponent implements OnInit { ngOnInit(): void { this.itemRD$ = this.route.parent.data.pipe(map((data) => data.dso)); this.itemRD$.pipe( + first(), map((data: RemoteData<Item>) => data.payload) - ).subscribe((item: Item) => { - this.statusData = Object.assign({ - id: item.id, - handle: item.handle, - lastModified: item.lastModified - }); - this.statusDataKeys = Object.keys(this.statusData); + ).pipe( + switchMap((item: Item) => { + this.statusData = Object.assign({ + id: item.id, + handle: item.handle, + lastModified: item.lastModified + }); + this.statusDataKeys = Object.keys(this.statusData); // Observable for item identifiers (retrieved from embedded link) this.identifiers$ = this.identifierDataService.getIdentifierDataFor(item).pipe( @@ -105,99 +107,108 @@ export class ItemStatusComponent implements OnInit { // Observable for configuration determining whether the Register DOI feature is enabled let registerConfigEnabled$: Observable<boolean> = this.configurationService.findByPropertyName('identifiers.item-status.register-doi').pipe( getFirstCompletedRemoteData(), - map((rd: RemoteData<ConfigurationProperty>) => { - // If the config property is exposed via rest and has a value set, return it - if (rd.hasSucceeded && hasValue(rd.payload) && isNotEmpty(rd.payload.values)) { - return rd.payload.values[0] === 'true'; - } - // Otherwise, return false - return false; - }) + map((enabledRD: RemoteData<ConfigurationProperty>) => enabledRD.hasSucceeded && enabledRD.payload.values.length > 0) ); - /* - Construct a base list of operations. - The key is used to build messages - i18n example: 'item.edit.tabs.status.buttons.<key>.label' - The value is supposed to be a href for the button - */ - const operations: ItemOperation[] = []; - operations.push(new ItemOperation('authorizations', this.getCurrentUrl(item) + '/authorizations', FeatureID.CanManagePolicies, true)); - operations.push(new ItemOperation('mappedCollections', this.getCurrentUrl(item) + '/mapper', FeatureID.CanManageMappings, true)); - if (item.isWithdrawn) { - operations.push(new ItemOperation('reinstate', this.getCurrentUrl(item) + '/reinstate', FeatureID.ReinstateItem, true)); - } else { - operations.push(new ItemOperation('withdraw', this.getCurrentUrl(item) + '/withdraw', FeatureID.WithdrawItem, true)); - } - if (item.isDiscoverable) { - operations.push(new ItemOperation('private', this.getCurrentUrl(item) + '/private', FeatureID.CanMakePrivate, true)); - } else { - operations.push(new ItemOperation('public', this.getCurrentUrl(item) + '/public', FeatureID.CanMakePrivate, true)); - } - operations.push(new ItemOperation('delete', this.getCurrentUrl(item) + '/delete', FeatureID.CanDelete, true)); - operations.push(new ItemOperation('move', this.getCurrentUrl(item) + '/move', FeatureID.CanMove, true)); - this.operations$.next(operations); - - /* - When the identifier data stream changes, determine whether the register DOI button should be shown or not. - This is based on whether the DOI is in the right state (minted or pending, not already queued for registration - or registered) and whether the configuration property identifiers.item-status.register-doi is true + /** + * Construct a base list of operations. + * The key is used to build messages + * i18n example: 'item.edit.tabs.status.buttons.<key>.label' + * The value is supposed to be a href for the button */ - this.identifierDataService.getIdentifierDataFor(item).pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - mergeMap((data: IdentifierData) => { - let identifiers = data.identifiers; - let no_doi = true; - let pending = false; - if (identifiers !== undefined && identifiers !== null) { - identifiers.forEach((identifier: Identifier) => { - if (hasValue(identifier) && identifier.identifierType === 'doi') { - // The item has some kind of DOI - no_doi = false; - if (identifier.identifierStatus === 'PENDING' || identifier.identifierStatus === 'MINTED' - || identifier.identifierStatus == null) { - // The item's DOI is pending, minted or null. - // It isn't registered, reserved, queued for registration or reservation or update, deleted - // or queued for deletion. - pending = true; - } + const currentUrl = this.getCurrentUrl(item); + const inititalOperations: ItemOperation[] = [ + new ItemOperation('authorizations', `${currentUrl}/authorizations`, FeatureID.CanManagePolicies, true), + new ItemOperation('mappedCollections', `${currentUrl}/mapper`, FeatureID.CanManageMappings, true), + item.isWithdrawn + ? new ItemOperation('reinstate', `${currentUrl}/reinstate`, FeatureID.ReinstateItem, true) + : new ItemOperation('withdraw', `${currentUrl}/withdraw`, FeatureID.WithdrawItem, true), + item.isDiscoverable + ? new ItemOperation('private', `${currentUrl}/private`, FeatureID.CanMakePrivate, true) + : new ItemOperation('public', `${currentUrl}/public`, FeatureID.CanMakePrivate, true), + new ItemOperation('move', `${currentUrl}/move`, FeatureID.CanMove, true), + new ItemOperation('delete', `${currentUrl}/delete`, FeatureID.CanDelete, true) + ]; + + this.operations$.next(inititalOperations); + + /** + * When the identifier data stream changes, determine whether the register DOI button should be shown or not. + * This is based on whether the DOI is in the right state (minted or pending, not already queued for registration + * or registered) and whether the configuration property identifiers.item-status.register-doi is true + */ + const ops$ = this.identifierDataService.getIdentifierDataFor(item).pipe( + getFirstCompletedRemoteData(), + mergeMap((dataRD: RemoteData<IdentifierData>) => { + if (dataRD.hasSucceeded) { + let identifiers = dataRD.payload.identifiers; + let no_doi = true; + let pending = false; + if (identifiers !== undefined && identifiers !== null) { + identifiers.forEach((identifier: Identifier) => { + if (hasValue(identifier) && identifier.identifierType === 'doi') { + // The item has some kind of DOI + no_doi = false; + if (['PENDING', 'MINTED', null].includes(identifier.identifierStatus)) { + // The item's DOI is pending, minted or null. + // It isn't registered, reserved, queued for registration or reservation or update, deleted + // or queued for deletion. + pending = true; + } + } + }); } - }); - } - // If there is no DOI, or a pending/minted/null DOI, and the config is enabled, return true - return registerConfigEnabled$.pipe( - map((enabled: boolean) => { - return enabled && (pending || no_doi); + // If there is no DOI, or a pending/minted/null DOI, and the config is enabled, return true + return registerConfigEnabled$.pipe( + map((enabled: boolean) => { + return enabled && (pending || no_doi); + } + )); + } else { + return of(false); + } + }), + // Switch map pushes the register DOI operation onto a copy of the base array then returns to the pipe + switchMap((showDoi: boolean) => { + const ops = [...inititalOperations]; + if (showDoi) { + const op = new ItemOperation('register-doi', `${currentUrl}/register-doi`, FeatureID.CanRegisterDOI, true); + ops.splice(ops.length - 1, 0, op); // Add item before last + } + return inititalOperations; + }), + concatMap((op: ItemOperation) => { + if (hasValue(op.featureID)) { + return this.authorizationService.isAuthorized(op.featureID, item.self).pipe( + distinctUntilChanged(), + map((authorized) => { + op.setDisabled(!authorized); + op.setAuthorized(authorized); + return op; + }) + ); } - )); - }), - // Switch map pushes the register DOI operation onto a copy of the base array then returns to the pipe - switchMap((showDoi: boolean) => { - let ops = [...operations]; - if (showDoi) { - ops.push(new ItemOperation('register-doi', this.getCurrentUrl(item) + '/register-doi', FeatureID.CanRegisterDOI, true)); - } - return ops; - }), - // Merge map checks and transforms each operation in the array based on whether it is authorized or not (disabled) - mergeMap((op: ItemOperation) => { - if (hasValue(op.featureID)) { - return this.authorizationService.isAuthorized(op.featureID, item.self).pipe( - distinctUntilChanged(), - map((authorized) => new ItemOperation(op.operationKey, op.operationUrl, op.featureID, !authorized, authorized)) - ); - } else { return [op]; - } - }), - // Wait for all operations to be emitted and return as an array - toArray(), - ).subscribe((data) => { - // Update the operations$ subject that draws the administrative buttons on the status page - this.operations$.next(data); - }); - }); + }), + toArray() + ); + + let orcidOps$ = of([]); + if (this.orcidAuthService.isLinkedToOrcid(item)) { + orcidOps$ = this.orcidAuthService.onlyAdminCanDisconnectProfileFromOrcid().pipe( + map((canDisconnect) => { + if (canDisconnect) { + return [new ItemOperation('unlinkOrcid', `${currentUrl}/unlink-orcid`)]; + } + return []; + }) + ); + } + + return combineLatest([ops$, orcidOps$]); + }), + map(([ops, orcidOps]: [ItemOperation[], ItemOperation[]]) => [...ops, ...orcidOps]) + ).subscribe((ops) => this.operations$.next(ops)); this.itemPageRoute$ = this.itemRD$.pipe( getAllSucceededRemoteDataPayload(), @@ -206,6 +217,7 @@ export class ItemStatusComponent implements OnInit { } + /** * Get the current url without query params * @returns {string} url From fbbbc18844b44f6f56b7c5f1f5e07e4886877d20 Mon Sep 17 00:00:00 2001 From: Vlad Nouski <uladzislau.nouski@4science.com> Date: Mon, 13 Nov 2023 15:02:27 +0100 Subject: [PATCH 213/282] refactor: code --- .../item-status/item-status.component.spec.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/edit-item-page/item-status/item-status.component.spec.ts b/src/app/item-page/edit-item-page/item-status/item-status.component.spec.ts index a67de2f435a..17ac3efa09d 100644 --- a/src/app/item-page/edit-item-page/item-status/item-status.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-status/item-status.component.spec.ts @@ -16,6 +16,7 @@ import { AuthorizationDataService } from '../../../core/data/feature-authorizati import { IdentifierDataService } from '../../../core/data/identifier-data.service'; import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; +import { OrcidAuthService } from '../../../core/orcid/orcid-auth.service'; let mockIdentifierDataService: IdentifierDataService; let mockConfigurationDataService: ConfigurationDataService; @@ -57,12 +58,18 @@ describe('ItemStatusComponent', () => { }; let authorizationService: AuthorizationDataService; + let orcidAuthService: any; beforeEach(waitForAsync(() => { authorizationService = jasmine.createSpyObj('authorizationService', { isAuthorized: observableOf(true) }); + orcidAuthService = jasmine.createSpyObj('OrcidAuthService', { + onlyAdminCanDisconnectProfileFromOrcid: observableOf ( true ), + isLinkedToOrcid: true + }); + TestBed.configureTestingModule({ imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule], declarations: [ItemStatusComponent], @@ -71,7 +78,8 @@ describe('ItemStatusComponent', () => { { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }, { provide: AuthorizationDataService, useValue: authorizationService }, { provide: IdentifierDataService, useValue: mockIdentifierDataService }, - { provide: ConfigurationDataService, useValue: mockConfigurationDataService } + { provide: ConfigurationDataService, useValue: mockConfigurationDataService }, + { provide: OrcidAuthService, useValue: orcidAuthService }, ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }).compileComponents(); })); From 394dc677471231d5b09bb25c2c976b8ceab70422 Mon Sep 17 00:00:00 2001 From: Thomas Misilo <tmisilo@ksu.edu> Date: Thu, 16 Nov 2023 11:36:06 -0600 Subject: [PATCH 214/282] Setup the Docker GH Action for Matrix Building This change enables building of the amd64 and arm64 images simultaneously. Once both images finish, the manifest is sent to Docker Hub, allowing for a single image that has both the amd64/arm64 images. --- .github/workflows/docker.yml | 173 +++++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 20 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0c36d5af987..18bdef78be6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,6 +17,7 @@ permissions: env: + REGISTRY_IMAGE: dspace/dspace-angular # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. # For a new commit on other branches, use the branch name as the tag for Docker image. @@ -30,21 +31,30 @@ env: # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) TAGS_FLAVOR: | latest=false - # Architectures / Platforms for which we will build Docker images - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. - PLATFORMS: linux/amd64${{ github.event_name != 'pull_request' && ', linux/arm64' || '' }} - jobs: - ############################################### - # Build/Push the 'dspace/dspace-angular' image - ############################################### + ############################################################# + # Build/Push the '${{ env.REGISTRY_IMAGE }}' image + ############################################################# dspace-angular: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' if: github.repository == 'dspace/dspace-angular' - runs-on: ubuntu-latest + strategy: + matrix: + isPr: + - ${{ github.event_name == 'pull_request' }} + # Architectures / Platforms for which we will build Docker images + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. + arch: ['linux/amd64', 'linux/arm64'] + os: [ubuntu-latest] + exclude: + - isPr: true + os: ubuntu-latest + arch: linux/arm64 + + runs-on: ${{ matrix.os }} steps: # https://github.com/actions/checkout - name: Checkout codebase @@ -61,7 +71,7 @@ jobs: # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' + if: ${{ ! matrix.isPr }} uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} @@ -73,7 +83,7 @@ jobs: id: meta_build uses: docker/metadata-action@v4 with: - images: dspace/dspace-angular + images: ${{ env.REGISTRY_IMAGE }} tags: ${{ env.IMAGE_TAGS }} flavor: ${{ env.TAGS_FLAVOR }} @@ -84,22 +94,89 @@ jobs: with: context: . file: ./Dockerfile - platforms: ${{ env.PLATFORMS }} + platforms: ${{ matrix.arch }} # For pull requests, we run the Docker build (to ensure no PR changes break the build), # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} + push: ${{ ! matrix.isPr }} # Use tags / labels provided by 'docker/metadata-action' above tags: ${{ steps.meta_build.outputs.tags }} labels: ${{ steps.meta_build.outputs.labels }} + - name: Export digest + if: ${{ ! matrix.isPr }} + run: | + mkdir -p /tmp/digests + digest="${{ steps.docker_build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + if: ${{ ! matrix.isPr }} + uses: actions/upload-artifact@v3 + with: + name: digests + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + if: ${{ github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: + - dspace-angular + steps: + - name: Download digests + uses: actions/download-artifact@v3 + with: + name: digests + path: /tmp/digests + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + tags: ${{ env.IMAGE_TAGS }} + flavor: ${{ env.TAGS_FLAVOR }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} + ############################################################# - # Build/Push the 'dspace/dspace-angular' image ('-dist' tag) + # Build/Push the '${{ env.REGISTRY_IMAGE }}' image ('-dist' tag) ############################################################# dspace-angular-dist: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' if: github.repository == 'dspace/dspace-angular' - runs-on: ubuntu-latest + strategy: + matrix: + isPr: + - ${{ github.event_name == 'pull_request' }} + # Architectures / Platforms for which we will build Docker images + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. + arch: ['linux/amd64', 'linux/arm64'] + os: [ubuntu-latest] + exclude: + - isPr: true + os: ubuntu-latest + arch: linux/arm64 + + runs-on: ${{ matrix.os }} steps: # https://github.com/actions/checkout - name: Checkout codebase @@ -116,7 +193,7 @@ jobs: # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: github.event_name != 'pull_request' + if: ${{ ! matrix.isPr }} uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} @@ -128,10 +205,10 @@ jobs: id: meta_build_dist uses: docker/metadata-action@v4 with: - images: dspace/dspace-angular + images: ${{ env.REGISTRY_IMAGE }} tags: ${{ env.IMAGE_TAGS }} # As this is a "dist" image, its tags are all suffixed with "-dist". Otherwise, it uses the same - # tagging logic as the primary 'dspace/dspace-angular' image above. + # tagging logic as the primary '${{ env.REGISTRY_IMAGE }}' image above. flavor: ${{ env.TAGS_FLAVOR }} suffix=-dist @@ -141,10 +218,66 @@ jobs: with: context: . file: ./Dockerfile.dist - platforms: ${{ env.PLATFORMS }} + platforms: ${{ matrix.arch }} # For pull requests, we run the Docker build (to ensure no PR changes break the build), # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ github.event_name != 'pull_request' }} + push: ${{ ! matrix.isPr }} # Use tags / labels provided by 'docker/metadata-action' above tags: ${{ steps.meta_build_dist.outputs.tags }} labels: ${{ steps.meta_build_dist.outputs.labels }} + + - name: Export digest + if: ${{ ! matrix.isPr }} + run: | + mkdir -p /tmp/digests/dist + digest="${{ steps.docker_build_dist.outputs.digest }}" + touch "/tmp/digests/dist/${digest#sha256:}" + + - name: Upload digest + if: ${{ ! matrix.isPr }} + uses: actions/upload-artifact@v3 + with: + name: digests + path: /tmp/digests/dist/* + if-no-files-found: error + retention-days: 1 + + merge-dist: + if: ${{ github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: + - dspace-angular-dist + steps: + - name: Download digests + uses: actions/download-artifact@v3 + with: + name: digests + path: /tmp/digests + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker meta + id: meta_dist + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + tags: ${{ env.IMAGE_TAGS }} + # As this is a "dist" image, its tags are all suffixed with "-dist". Otherwise, it uses the same + # tagging logic as the primary '${{ env.REGISTRY_IMAGE }}' image above. + flavor: ${{ env.TAGS_FLAVOR }} + suffix=-dist + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + + - name: Create manifest list and push + working-directory: /tmp/digests/dist + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta_dist.outputs.version }} From 41eba0dc2fac4c20d8d9cf5511eb1e7e50a51b44 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 17 Nov 2023 09:31:09 -0600 Subject: [PATCH 215/282] Fix bug in Docker manifest. Each build must use a separate artifact to store digests. Other minor cleanup & comments added. --- .github/workflows/docker.yml | 81 ++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 18bdef78be6..23919d573c7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -42,13 +42,13 @@ jobs: strategy: matrix: - isPr: - - ${{ github.event_name == 'pull_request' }} # Architectures / Platforms for which we will build Docker images - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. arch: ['linux/amd64', 'linux/arm64'] os: [ubuntu-latest] + isPr: + - ${{ github.event_name == 'pull_request' }} + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # The below exclude therefore ensures we do NOT build ARM64 for PRs. exclude: - isPr: true os: ubuntu-latest @@ -58,21 +58,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: ${{ ! matrix.isPr }} - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -81,7 +81,7 @@ jobs: # Get Metadata for docker_build step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular' image id: meta_build - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY_IMAGE }} tags: ${{ env.IMAGE_TAGS }} @@ -90,7 +90,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push 'dspace-angular' image id: docker_build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile @@ -102,6 +102,7 @@ jobs: tags: ${{ steps.meta_build.outputs.tags }} labels: ${{ steps.meta_build.outputs.labels }} + # Export the digest of Docker build locally (for non PRs only) - name: Export digest if: ${{ ! matrix.isPr }} run: | @@ -109,6 +110,7 @@ jobs: digest="${{ steps.docker_build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" + # Upload digest to an artifact, so that it can be used in manifest below - name: Upload digest if: ${{ ! matrix.isPr }} uses: actions/upload-artifact@v3 @@ -118,7 +120,12 @@ jobs: if-no-files-found: error retention-days: 1 - merge: + # Merge digests into a manifest. + # This runs after all Docker builds complete above, and it tells hub.docker.com + # that these builds should be all included in the manifest for this tag. + # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image) + # Borrowed from https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners + dspace-angular_manifest: if: ${{ github.event_name != 'pull_request' }} runs-on: ubuntu-latest needs: @@ -129,9 +136,11 @@ jobs: with: name: digests path: /tmp/digests + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Docker meta + + - name: Add Docker metadata for image id: meta uses: docker/metadata-action@v5 with: @@ -145,7 +154,7 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: Create manifest list and push + - name: Create manifest list from digests and push working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ @@ -164,13 +173,13 @@ jobs: strategy: matrix: - isPr: - - ${{ github.event_name == 'pull_request' }} # Architectures / Platforms for which we will build Docker images - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # If this is NOT a PR (e.g. a tag or merge commit), also build for ARM64. arch: ['linux/amd64', 'linux/arm64'] os: [ubuntu-latest] + isPr: + - ${{ github.event_name == 'pull_request' }} + # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. + # The below exclude therefore ensures we do NOT build ARM64 for PRs. exclude: - isPr: true os: ubuntu-latest @@ -180,21 +189,21 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-qemu-action - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # https://github.com/docker/login-action - name: Login to DockerHub # Only login if not a PR, as PRs only trigger a Docker build and not a push if: ${{ ! matrix.isPr }} - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} @@ -203,7 +212,7 @@ jobs: # Get Metadata for docker_build_dist step below - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular-dist' image id: meta_build_dist - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY_IMAGE }} tags: ${{ env.IMAGE_TAGS }} @@ -214,7 +223,7 @@ jobs: - name: Build and push 'dspace-angular-dist' image id: docker_build_dist - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.dist @@ -226,6 +235,7 @@ jobs: tags: ${{ steps.meta_build_dist.outputs.tags }} labels: ${{ steps.meta_build_dist.outputs.labels }} + # Export the digest of Docker build locally (for non PRs only) - name: Export digest if: ${{ ! matrix.isPr }} run: | @@ -233,29 +243,38 @@ jobs: digest="${{ steps.docker_build_dist.outputs.digest }}" touch "/tmp/digests/dist/${digest#sha256:}" + # Upload Digest to an artifact, so that it can be used in manifest below - name: Upload digest if: ${{ ! matrix.isPr }} uses: actions/upload-artifact@v3 with: - name: digests - path: /tmp/digests/dist/* + # NOTE: It's important that this artifact has a unique name so that two + # image builds don't upload digests to the same artifact. + name: digests-dist + path: /tmp/digests/* if-no-files-found: error retention-days: 1 - merge-dist: + # Merge *-dist digests into a manifest. + # This runs after all Docker builds complete above, and it tells hub.docker.com + # that these builds should be all included in the manifest for this tag. + # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image) + dspace-angular-dist_manifest: if: ${{ github.event_name != 'pull_request' }} runs-on: ubuntu-latest needs: - dspace-angular-dist steps: - - name: Download digests + - name: Download digests for -dist builds uses: actions/download-artifact@v3 with: - name: digests + name: digests-dist path: /tmp/digests + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Docker meta + + - name: Add Docker metadata for image id: meta_dist uses: docker/metadata-action@v5 with: @@ -272,8 +291,8 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: Create manifest list and push - working-directory: /tmp/digests/dist + - name: Create manifest list from digests and push + working-directory: /tmp/digests run: | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) From 9f12ca3265299160dd93ecc6e0cadfd5aeec9117 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 17 Nov 2023 11:05:46 -0600 Subject: [PATCH 216/282] Update GH actions to latest versions. Fix bug in codecov to ensure it retries on error. --- .github/workflows/build.yml | 16 ++++++++++------ .github/workflows/codescan.yml | 2 +- .github/workflows/port_merged_pull_request.yml | 4 ++-- .github/workflows/pull_request_opened.yml | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 219074780e3..e2680420a21 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,11 +43,11 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v3 + uses: actions/checkout@v4 # https://github.com/actions/setup-node - name: Install Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -118,7 +118,7 @@ jobs: # https://github.com/cypress-io/github-action # (NOTE: to run these e2e tests locally, just use 'ng e2e') - name: Run e2e tests (integration tests) - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 with: # Run tests in Chrome, headless mode (default) browser: chrome @@ -191,7 +191,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Download artifacts from previous 'tests' job - name: Download coverage artifacts @@ -203,10 +203,14 @@ jobs: # Retry action: https://github.com/marketplace/actions/retry-action # Codecov action: https://github.com/codecov/codecov-action - name: Upload coverage to Codecov.io - uses: Wandalen/wretry.action@v1.0.36 + uses: Wandalen/wretry.action@v1.3.0 with: action: codecov/codecov-action@v3 - # Try upload 5 times max + # Ensure codecov-action throws an error when it fails to upload + # This allows us to auto-restart the action if an error is thrown + with: | + fail_ci_if_error: true + # Try re-running action 5 times max attempt_limit: 5 # Run again in 30 seconds attempt_delay: 30000 diff --git a/.github/workflows/codescan.yml b/.github/workflows/codescan.yml index 8b415296c71..d96e786cc37 100644 --- a/.github/workflows/codescan.yml +++ b/.github/workflows/codescan.yml @@ -35,7 +35,7 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. # https://github.com/github/codeql-action diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml index 109835d14d3..857f22755e4 100644 --- a/.github/workflows/port_merged_pull_request.yml +++ b/.github/workflows/port_merged_pull_request.yml @@ -23,11 +23,11 @@ jobs: if: github.event.pull_request.merged steps: # Checkout code - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Port PR to other branch (ONLY if labeled with "port to") # See https://github.com/korthout/backport-action - name: Create backport pull requests - uses: korthout/backport-action@v1 + uses: korthout/backport-action@v2 with: # Trigger based on a "port to [branch]" label on PR # (This label must specify the branch name to port to) diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml index 9b61af72d18..f16e81c9fd2 100644 --- a/.github/workflows/pull_request_opened.yml +++ b/.github/workflows/pull_request_opened.yml @@ -21,4 +21,4 @@ jobs: # Assign the PR to whomever created it. This is useful for visualizing assignments on project boards # See https://github.com/toshimaru/auto-author-assign - name: Assign PR to creator - uses: toshimaru/auto-author-assign@v1.6.2 + uses: toshimaru/auto-author-assign@v2.0.1 From c99fe3a6c1d1a69126ef83d0aadf9489db1edb9e Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 17 Nov 2023 11:56:48 -0600 Subject: [PATCH 217/282] Fix directory structure for -dist digests --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 23919d573c7..04112f7b70b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -239,9 +239,9 @@ jobs: - name: Export digest if: ${{ ! matrix.isPr }} run: | - mkdir -p /tmp/digests/dist + mkdir -p /tmp/digests digest="${{ steps.docker_build_dist.outputs.digest }}" - touch "/tmp/digests/dist/${digest#sha256:}" + touch "/tmp/digests/${digest#sha256:}" # Upload Digest to an artifact, so that it can be used in manifest below - name: Upload digest From ecca8286b5e8c4d90d9d04e9ea71238dd5046f8e Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 18 Nov 2023 15:24:56 +0100 Subject: [PATCH 218/282] 108587: Deselect all fields on component destruction --- .../metadata-schema/metadata-schema.component.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.ts b/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.ts index d0827e6e4d5..4dec129eadd 100644 --- a/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.ts +++ b/src/app/admin/admin-registries/metadata-schema/metadata-schema.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; import { RegistryService } from '../../../core/registry/registry.service'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { BehaviorSubject, combineLatest as observableCombineLatest, @@ -32,7 +32,7 @@ import { PaginationService } from '../../../core/pagination/pagination.service'; * A component used for managing all existing metadata fields within the current metadata schema. * The admin can create, edit or delete metadata fields here. */ -export class MetadataSchemaComponent implements OnInit { +export class MetadataSchemaComponent implements OnInit, OnDestroy { /** * The metadata schema */ @@ -60,7 +60,6 @@ export class MetadataSchemaComponent implements OnInit { constructor(private registryService: RegistryService, private route: ActivatedRoute, private notificationsService: NotificationsService, - private router: Router, private paginationService: PaginationService, private translateService: TranslateService) { @@ -86,7 +85,7 @@ export class MetadataSchemaComponent implements OnInit { */ private updateFields() { this.metadataFields$ = this.paginationService.getCurrentPagination(this.config.id, this.config).pipe( - switchMap((currentPagination) => combineLatest(this.metadataSchema$, this.needsUpdate$, observableOf(currentPagination))), + switchMap((currentPagination) => combineLatest([this.metadataSchema$, this.needsUpdate$, observableOf(currentPagination)])), switchMap(([schema, update, currentPagination]: [MetadataSchema, boolean, PaginationComponentOptions]) => { if (update) { this.needsUpdate$.next(false); @@ -193,10 +192,10 @@ export class MetadataSchemaComponent implements OnInit { showNotification(success: boolean, amount: number) { const prefix = 'admin.registries.schema.notification'; const suffix = success ? 'success' : 'failure'; - const messages = observableCombineLatest( + const messages = observableCombineLatest([ this.translateService.get(success ? `${prefix}.${suffix}` : `${prefix}.${suffix}`), this.translateService.get(`${prefix}.field.deleted.${suffix}`, { amount: amount }) - ); + ]); messages.subscribe(([head, content]) => { if (success) { this.notificationsService.success(head, content); @@ -207,6 +206,7 @@ export class MetadataSchemaComponent implements OnInit { } ngOnDestroy(): void { this.paginationService.clearPagination(this.config.id); + this.registryService.deselectAllMetadataField(); } } From fd645452a54748c8f91c4803279ad3585055a7ed Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 21 Nov 2023 12:15:42 -0600 Subject: [PATCH 219/282] Trigger redeploy of demo/sandbox from GitHub Actions after DockerHub image updated. --- .github/workflows/docker.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 23919d573c7..7e322caf8bc 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -23,8 +23,8 @@ env: # For a new commit on other branches, use the branch name as the tag for Docker image. # For a new tag, copy that tag name as the tag for Docker image. IMAGE_TAGS: | - type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} - type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }} + type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }} + type=ref,event=branch,enable=${{ github.ref_name != github.event.repository.default_branch }} type=ref,event=tag # Define default tag "flavor" for docker/metadata-action per # https://github.com/docker/metadata-action#flavor-input @@ -300,3 +300,25 @@ jobs: - name: Inspect image run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta_dist.outputs.version }} + + # Deploy latest -dist image to Demo or Sandbox site, based on the branch updated + dspace-angular-dist_deploy: + if: ${{ github.event_name != 'pull_request' }} + runs-on: ubuntu-latest + needs: + # Requires manifest to be fully updated on DockerHub + - dspace-angular-dist_manifest + steps: + - name: Redeploy sandbox.dspace.org (based on main branch) + if: ${{ github.ref_name == github.event.repository.default_branch }} + run: | + curl -X POST -d '{}' $REDEPLOY_SANDBOX_URL + env: + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} + + - name: Redeploy demo.dspace.org (based on maintenace branch) + if: ${{ github.ref_name == 'dspace-7_x' }} + run: | + curl -X POST -d '{}' $REDEPLOY_DEMO_URL + env: + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} From ff677a83d663393cb529c4abc0ba45b96019055c Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 22 Nov 2023 10:51:28 -0600 Subject: [PATCH 220/282] Redeploy demo/sandbox more quickly by only waiting for AMD64 image --- .github/workflows/docker.yml | 40 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c482d8f29a2..a581b63e7b0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -255,6 +255,24 @@ jobs: if-no-files-found: error retention-days: 1 + # If the 'linux/amd64' -dist image was just updated for the 'main' branch, + # Then redeploy https://sandbox.dspace.org using that updated image. + - name: Redeploy sandbox.dspace.org (based on main branch) + if: ${{ ! matrix.isPr && matrix.arch == 'linux/amd64' && github.ref_name == github.event.repository.default_branch }} + run: | + curl -X POST $REDEPLOY_SANDBOX_URL + env: + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} + + # If the 'linux/amd64' -dist image was just updated for the maintenance branch, + # Then redeploy https://demo.dspace.org using that updated image. + - name: Redeploy demo.dspace.org (based on maintenace branch) + if: ${{ ! matrix.isPr && matrix.arch == 'linux/amd64' && github.ref_name == 'dspace-7_x' }} + run: | + curl -X POST $REDEPLOY_DEMO_URL + env: + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} + # Merge *-dist digests into a manifest. # This runs after all Docker builds complete above, and it tells hub.docker.com # that these builds should be all included in the manifest for this tag. @@ -300,25 +318,3 @@ jobs: - name: Inspect image run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta_dist.outputs.version }} - - # Deploy latest -dist image to Demo or Sandbox site, based on the branch updated - dspace-angular-dist_deploy: - if: ${{ github.event_name != 'pull_request' }} - runs-on: ubuntu-latest - needs: - # Requires manifest to be fully updated on DockerHub - - dspace-angular-dist_manifest - steps: - - name: Redeploy sandbox.dspace.org (based on main branch) - if: ${{ github.ref_name == github.event.repository.default_branch }} - run: | - curl -X POST -d '{}' $REDEPLOY_SANDBOX_URL - env: - REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} - - - name: Redeploy demo.dspace.org (based on maintenace branch) - if: ${{ github.ref_name == 'dspace-7_x' }} - run: | - curl -X POST -d '{}' $REDEPLOY_DEMO_URL - env: - REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} From 430ee3846a2446e16914764e71c1d0c5e739ae2c Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Thu, 23 Nov 2023 21:04:02 +0100 Subject: [PATCH 221/282] Fixed ePerson link on edit group page --- .../group-form/members-list/members-list.component.html | 6 ++---- .../members-list/members-list.component.spec.ts | 3 --- .../group-form/members-list/members-list.component.ts | 3 +++ src/app/core/eperson/eperson-data.service.ts | 9 +-------- .../reviewers-list/reviewers-list.component.spec.ts | 3 --- 5 files changed, 6 insertions(+), 18 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 c0c77f44ebc..1e61f2cdb2f 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 @@ -24,8 +24,7 @@ <h4>{{messagePrefix + '.headMembers' | translate}}</h4> <tr *ngFor="let eperson of (ePeopleMembersOfGroup | async)?.page"> <td class="align-middle">{{eperson.id}}</td> <td class="align-middle"> - <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" - [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> + <a [routerLink]="getEPersonEditRoute(eperson.id)"> {{ dsoNameService.getName(eperson) }} </a> </td> @@ -106,8 +105,7 @@ <h4 id="search" class="border-bottom pb-2"> <tr *ngFor="let eperson of (ePeopleSearch | async)?.page"> <td class="align-middle">{{eperson.id}}</td> <td class="align-middle"> - <a (click)="ePersonDataService.startEditingNewEPerson(eperson)" - [routerLink]="[ePersonDataService.getEPeoplePageRouterLink()]"> + <a [routerLink]="getEPersonEditRoute(eperson.id)"> {{ dsoNameService.getName(eperson) }} </a> </td> 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 5d97dcade8d..99ee9827e81 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 @@ -68,9 +68,6 @@ describe('MembersListComponent', () => { clearLinkRequests() { // empty }, - getEPeoplePageRouterLink(): string { - return '/access-control/epeople'; - } }; groupsDataServiceStub = { activeGroup: activeGroup, 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 feb90b52b37..6129d4d02d5 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 @@ -23,6 +23,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model'; import { PaginationService } from '../../../../core/pagination/pagination.service'; import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service'; +import { getEPersonEditRoute } from '../../../access-control-routing-paths'; /** * Keys to keep track of specific subscriptions @@ -131,6 +132,8 @@ export class MembersListComponent implements OnInit, OnDestroy { // current active group being edited groupBeingEdited: Group; + readonly getEPersonEditRoute = getEPersonEditRoute; + constructor( protected groupDataService: GroupDataService, public ePersonDataService: EPersonDataService, diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts index fb8b8bc9b00..a85d471e7db 100644 --- a/src/app/core/eperson/eperson-data.service.ts +++ b/src/app/core/eperson/eperson-data.service.ts @@ -34,7 +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'; +import { getEPersonEditRoute } from '../../access-control/access-control-routing-paths'; const ePeopleRegistryStateSelector = (state: AppState) => state.epeopleRegistry; const editEPersonSelector = createSelector(ePeopleRegistryStateSelector, (ePeopleRegistryState: EPeopleRegistryState) => ePeopleRegistryState.editEPerson); @@ -313,13 +313,6 @@ export class EPersonDataService extends IdentifiableDataService<EPerson> impleme return getEPersonEditRoute(ePerson.id); } - /** - * Get EPeople admin page - */ - public getEPeoplePageRouterLink(): string { - return getEPersonsRoute(); - } - /** * Create a new EPerson using a token * @param eperson 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 bcbeef56830..91e200e85d2 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 @@ -72,9 +72,6 @@ describe('ReviewersListComponent', () => { clearLinkRequests() { // empty }, - getEPeoplePageRouterLink(): string { - return '/access-control/epeople'; - } }; groupsDataServiceStub = { activeGroup: activeGroup, From e229be44d6450f9c50ed2d53f4b5d9cb7939fcd1 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sat, 25 Nov 2023 14:21:57 +0100 Subject: [PATCH 222/282] Added missing aria labels to edit bitstream tab --- .../item-bitstreams/item-bitstreams.component.html | 7 +++++++ .../item-edit-bitstream-bundle.component.html | 1 + 2 files changed, 8 insertions(+) diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html index 4cb9577fcb5..bd4c9334ad3 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-bitstreams.component.html @@ -1,21 +1,25 @@ <div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles"> <div class="button-row top d-flex mt-2 space-children-mr"> <button class="mr-auto btn btn-success" + [attr.aria-label]="'item.edit.bitstreams.upload-button' | translate" [routerLink]="[itemPageRoute, 'bitstreams', 'new']"><i class="fas fa-upload"></i> <span class="d-none d-sm-inline"> {{"item.edit.bitstreams.upload-button" | translate}}</span> </button> <button class="btn btn-warning" *ngIf="isReinstatable() | async" + [attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate" (click)="reinstate()"><i class="fas fa-undo-alt"></i> <span class="d-none d-sm-inline"> {{"item.edit.bitstreams.reinstate-button" | translate}}</span> </button> <button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting" + [attr.aria-label]="'item.edit.bitstreams.save-button' | translate" (click)="submit()"><i class="fas fa-save"></i> <span class="d-none d-sm-inline"> {{"item.edit.bitstreams.save-button" | translate}}</span> </button> <button class="btn btn-danger" *ngIf="!(isReinstatable() | async)" + [attr.aria-label]="'item.edit.bitstreams.discard-button' | translate" [disabled]="!(hasChanges() | async) || submitting" (click)="discard()"><i class="fas fa-times"></i> @@ -49,16 +53,19 @@ <div class="button-row bottom"> <div class="mt-4 float-right space-children-mr ml-gap"> <button class="btn btn-warning" *ngIf="isReinstatable() | async" + [attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate" (click)="reinstate()"><i class="fas fa-undo-alt"></i> <span class="d-none d-sm-inline"> {{"item.edit.bitstreams.reinstate-button" | translate}}</span> </button> <button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting" + [attr.aria-label]="'item.edit.bitstreams.save-button' | translate" (click)="submit()"><i class="fas fa-save"></i> <span class="d-none d-sm-inline"> {{"item.edit.bitstreams.save-button" | translate}}</span> </button> <button class="btn btn-danger" *ngIf="!(isReinstatable() | async)" + [attr.aria-label]="'item.edit.bitstreams.discard-button' | translate" [disabled]="!(hasChanges() | async) || submitting" (click)="discard()"><i class="fas fa-times"></i> diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html index 62170235a3a..42b9b9eb647 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html @@ -10,6 +10,7 @@ <div class="btn-group bundle-action-buttons"> <button [routerLink]="[itemPageRoute, 'bitstreams', 'new']" [queryParams]="{bundle: bundle.id}" + [attr.aria-label]="'item.edit.bitstreams.bundle.edit.buttons.upload' | translate" class="btn btn-outline-success btn-sm" title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}"> <i class="fas fa-upload fa-fw"></i> From 9ab30231aad9983cc2d961e639e4a12a22fe1633 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 26 Nov 2023 00:16:50 +0100 Subject: [PATCH 223/282] Replaced uncrawlable links with buttons --- .../admin-sidebar/admin-sidebar.component.html | 13 ++++++------- .../admin-sidebar/admin-sidebar.component.spec.ts | 2 +- src/app/footer/footer.component.html | 7 ++++--- src/app/footer/footer.component.scss | 5 +++-- .../expandable-navbar-section.component.html | 6 +++--- .../expandable-navbar-section.component.scss | 9 +++++++++ .../expandable-navbar-section.component.spec.ts | 8 ++++---- src/app/navbar/navbar.component.scss | 4 ++-- src/themes/dspace/app/navbar/navbar.component.html | 2 +- src/themes/dspace/app/navbar/navbar.component.scss | 4 ++-- 10 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.html b/src/app/admin/admin-sidebar/admin-sidebar.component.html index fe7e5595ab0..ca69501382e 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.html +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.html @@ -34,22 +34,21 @@ <h4 class="section-header-text mb-0">{{ 'menu.header.admin' | translate }}</h4> </div> <div class="navbar-nav"> <div class="sidebar-section" id="sidebar-collapse-toggle"> - <a class="nav-item nav-link sidebar-section d-flex flex-row flex-nowrap" - href="javascript:void(0);" + <button class="nav-item nav-link sidebar-section d-flex flex-row flex-nowrap border-0" type="button" (click)="toggle($event)" (keyup.space)="toggle($event)" > - <div class="shortcut-icon"> + <span class="shortcut-icon"> <i *ngIf="(menuCollapsed | async)" class="fas fa-fw fa-angle-double-right" [title]="'menu.section.icon.pin' | translate"></i> <i *ngIf="!(menuCollapsed | async)" class="fas fa-fw fa-angle-double-left" [title]="'menu.section.icon.unpin' | translate"></i> - </div> - <div class="sidebar-collapsible"> + </span> + <span class="sidebar-collapsible text-left"> <span *ngIf="menuCollapsed | async" class="section-header-text">{{'menu.section.pin' | translate }}</span> <span *ngIf="!(menuCollapsed | async)" class="section-header-text">{{'menu.section.unpin' | translate }}</span> - </div> - </a> + </span> + </button> </div> </div> </nav> diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts index 88efd2a711e..9522be29ce3 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.spec.ts @@ -143,7 +143,7 @@ describe('AdminSidebarComponent', () => { describe('when the collapse link is clicked', () => { beforeEach(() => { spyOn(menuService, 'toggleMenu'); - const sidebarToggler = fixture.debugElement.query(By.css('#sidebar-collapse-toggle > a')); + const sidebarToggler = fixture.debugElement.query(By.css('#sidebar-collapse-toggle > button')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } diff --git a/src/app/footer/footer.component.html b/src/app/footer/footer.component.html index 13d84e6e2e1..d4c0cd1a377 100644 --- a/src/app/footer/footer.component.html +++ b/src/app/footer/footer.component.html @@ -62,10 +62,11 @@ <h5 class="text-uppercase">Footer Content</h5> <a class="text-white" href="https://www.lyrasis.org/">{{ 'footer.link.lyrasis' | translate}}</a> </p> - <ul class="footer-info list-unstyled small d-flex justify-content-center mb-0"> + <ul class="footer-info list-unstyled d-flex justify-content-center mb-0"> <li> - <a class="text-white" href="javascript:void(0);" - (click)="showCookieSettings()">{{ 'footer.link.cookies' | translate}}</a> + <button class="btn btn-link text-white" type="button" (click)="showCookieSettings()"> + {{ 'footer.link.cookies' | translate}} + </button> </li> <li *ngIf="showPrivacyPolicy"> <a class="text-white" diff --git a/src/app/footer/footer.component.scss b/src/app/footer/footer.component.scss index 350295b8704..4dfdc3267ba 100644 --- a/src/app/footer/footer.component.scss +++ b/src/app/footer/footer.component.scss @@ -26,9 +26,10 @@ li { display: inline-flex; - a { + a, .btn-link { padding: 0 calc(var(--bs-spacer) / 2); - color: inherit + color: inherit; + font-size: .875em; } &:not(:last-child) { diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html index 053968834e1..44ca82b61da 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.html @@ -5,13 +5,13 @@ (keydown.space)="$event.preventDefault()" (mouseenter)="activateSection($event)" (mouseleave)="deactivateSection($event)"> - <a href="javascript:void(0);" class="nav-link dropdown-toggle" routerLinkActive="active" + <button class="btn btn-link nav-link dropdown-toggle" routerLinkActive="active" type="button" [class.disabled]="section.model?.disabled" - id="browseDropdown" (click)="toggleSection($event)" + (click)="toggleSection($event)" data-toggle="dropdown"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container> - </a> + </button> <ul @slide *ngIf="(active | async)" (click)="deactivateSection($event)" class="m-0 shadow-none border-top-0 dropdown-menu show"> <li *ngFor="let subSection of (subSections$ | async)"> 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 28db981f115..ff48341b0f7 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 @@ -5,6 +5,15 @@ justify-content: center; } +.btn.nav-link { + text-align: left; + border: none; + + &:active, &:focus { + box-shadow: none !important; + } +} + .dropdown-menu { background-color: var(--ds-expandable-navbar-bg); overflow: hidden; diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts index 488c9ab2518..f4c72e12375 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.spec.ts @@ -152,7 +152,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when a click occurs on the section header', () => { beforeEach(() => { spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > button')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } @@ -195,7 +195,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse enters the section header', () => { beforeEach(() => { spyOn(menuService, 'activateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > button')); sidebarToggler.triggerEventHandler('mouseenter', { preventDefault: () => {/**/ } @@ -210,7 +210,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when the mouse leaves the section header', () => { beforeEach(() => { spyOn(menuService, 'deactivateSection'); - const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > button')); sidebarToggler.triggerEventHandler('mouseleave', { preventDefault: () => {/**/ } @@ -225,7 +225,7 @@ describe('ExpandableNavbarSectionComponent', () => { describe('when a click occurs on the section header link', () => { beforeEach(() => { spyOn(menuService, 'toggleActiveSection'); - const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > a')); + const sidebarToggler = fixture.debugElement.query(By.css('div.nav-item.dropdown > button')); sidebarToggler.triggerEventHandler('click', { preventDefault: () => {/**/ } diff --git a/src/app/navbar/navbar.component.scss b/src/app/navbar/navbar.component.scss index dac8c0927f3..d9a09013747 100644 --- a/src/app/navbar/navbar.component.scss +++ b/src/app/navbar/navbar.component.scss @@ -37,8 +37,8 @@ nav.navbar { } } -.navbar-nav { - ::ng-deep a.nav-link { +.navbar-nav ::ng-deep { + a.nav-link, .btn.nav-link { color: var(--ds-navbar-link-color); &:hover, &:focus { diff --git a/src/themes/dspace/app/navbar/navbar.component.html b/src/themes/dspace/app/navbar/navbar.component.html index f2e231d46ce..9f7e977961e 100644 --- a/src/themes/dspace/app/navbar/navbar.component.html +++ b/src/themes/dspace/app/navbar/navbar.component.html @@ -8,7 +8,7 @@ <div id="collapsingNav" class="w-100 h-100"> <ul class="navbar-nav me-auto mb-2 mb-lg-0 h-100"> <li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)"> - <ds-user-menu [inExpandableNavbar]="true"></ds-user-menu> + <ds-themed-user-menu [inExpandableNavbar]="true"></ds-themed-user-menu> </li> <li *ngFor="let section of (sections | async)"> <ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container> diff --git a/src/themes/dspace/app/navbar/navbar.component.scss b/src/themes/dspace/app/navbar/navbar.component.scss index 28ead2f1def..f1f17d9f768 100644 --- a/src/themes/dspace/app/navbar/navbar.component.scss +++ b/src/themes/dspace/app/navbar/navbar.component.scss @@ -54,8 +54,8 @@ a.navbar-brand img { max-height: var(--ds-header-logo-height); } -.navbar-nav { - ::ng-deep a.nav-link { +.navbar-nav ::ng-deep { + a.nav-link, .btn.nav-link { color: var(--ds-navbar-link-color); &:hover, &:focus { From 8a7bdfe18ffd2a9451f17d4f7280ba5a60336986 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 26 Nov 2023 01:30:20 +0100 Subject: [PATCH 224/282] Added aria-labels & fixed aria-controls on myDSpace page - Added aria-label to the new submission buttons (for repositories with more than 1 entity type) - Fixed aria-controls pointing to non-existing ids --- .../my-dspace-new-external-dropdown.component.html | 5 +++-- .../my-dspace-new-submission-dropdown.component.html | 5 +++-- .../search/search-sidebar/search-sidebar.component.html | 5 +++-- src/app/shared/search/search.component.html | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component.html b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component.html index 7db6db9a8da..392134dbce5 100644 --- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component.html +++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-external-dropdown/my-dspace-new-external-dropdown.component.html @@ -1,5 +1,6 @@ <div class="add" *ngIf="!(moreThanOne$ | async)"> - <button class="btn btn-lg btn-outline-primary mt-1 ml-2" [disabled]="!(initialized$|async)" + <button class="btn btn-lg btn-outline-primary mt-1 ml-2" + [attr.aria-label]="'mydspace.new-submission-external' | translate" [disabled]="!(initialized$|async)" (click)="openPage(singleEntity)" role="button" title="{{'mydspace.new-submission-external' | translate}}"> <i class="fa fa-file-import" aria-hidden="true"></i> @@ -10,7 +11,7 @@ *ngIf="(moreThanOne$ | async)"> <button class="btn btn-lg btn-outline-primary mt-1 ml-2" id="dropdownImport" ngbDropdownToggle type="button" [disabled]="!(initialized$|async)" - attr.aria-label="{{'mydspace.new-submission-external' | translate}}" + [attr.aria-label]="'mydspace.new-submission-external' | translate" [attr.data-test]="'import-dropdown' | dsBrowserOnly" title="{{'mydspace.new-submission-external' | translate}}"> <i class="fa fa-file-import" aria-hidden="true"></i> diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.html b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.html index 84d06492771..73fbeb30c2b 100644 --- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.html +++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.html @@ -1,5 +1,6 @@ <div class="add" *ngIf="!(moreThanOne$ | async)"> - <button class="btn btn-lg btn-primary mt-1 ml-2" [disabled]="!(initialized$|async)" (click)="openDialog(singleEntity)" role="button"> + <button class="btn btn-lg btn-primary mt-1 ml-2" [attr.aria-label]="'mydspace.new-submission' | translate" + [disabled]="!(initialized$|async)" (click)="openDialog(singleEntity)" role="button"> <i class="fa fa-plus-circle" aria-hidden="true"></i> </button> </div> @@ -8,7 +9,7 @@ *ngIf="(moreThanOne$ | async)"> <button class="btn btn-lg btn-primary mt-1 ml-2" id="dropdownSubmission" ngbDropdownToggle type="button" [disabled]="!(initialized$|async)" - attr.aria-label="{{'mydspace.new-submission' | translate}}" + [attr.aria-label]="'mydspace.new-submission' | translate" [attr.data-test]="'submission-dropdown' | dsBrowserOnly" title="{{'mydspace.new-submission' | translate}}"> <i class="fa fa-plus-circle" aria-hidden="true"></i> diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.html b/src/app/shared/search/search-sidebar/search-sidebar.component.html index f489de5d289..529f1de8870 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.html +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.html @@ -2,9 +2,10 @@ <div id="sidebar-options" class="d-block d-md-none search-controls clearfix"> <small class="results">{{resultCount}} {{"search.sidebar.results" | translate}}</small> <button (click)="toggleSidebar.emit()" - aria-controls="#search-body" + [attr.aria-label]="'search.sidebar.close' | translate" + aria-controls="search-content" class="btn btn-outline-primary float-right close-sidebar"><i - class="fas fa-arrow-right" [title]="'search.sidebar.close' | translate"></i> {{"search.sidebar.close" | translate}} + class="fas fa-arrow-right"></i> {{'search.sidebar.close' | translate}} </button> </div> <div id="search-sidebar-content"> diff --git a/src/app/shared/search/search.component.html b/src/app/shared/search/search.component.html index d43f506866f..e7dd02e2863 100644 --- a/src/app/shared/search/search.component.html +++ b/src/app/shared/search/search.component.html @@ -23,7 +23,8 @@ <div id="search-content" class="col-12"> <div class="d-block d-md-none search-controls clearfix"> <ds-view-mode-switch [viewModeList]="viewModeList" [inPlaceSearch]="inPlaceSearch"></ds-view-mode-switch> - <button (click)="openSidebar()" aria-controls="#search-body" + <button [attr.aria-label]="'search.sidebar.open' | translate" (click)="openSidebar()" + aria-controls="search-sidebar-content" class="btn btn-outline-primary float-right open-sidebar"><i class="fas fa-sliders"></i> {{"search.sidebar.open" | translate}} From cc71d60ebb5c696422958fb00a041d9b40175834 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 26 Nov 2023 02:16:56 +0100 Subject: [PATCH 225/282] Fixed duplicate search-navbar-container id & renabled accessibility tests for header --- cypress/e2e/header.cy.ts | 7 +------ .../search-navbar.component.html | 2 +- .../search-navbar.component.spec.ts | 21 ++++++------------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/cypress/e2e/header.cy.ts b/cypress/e2e/header.cy.ts index 1a9b841eb7d..9852216e438 100644 --- a/cypress/e2e/header.cy.ts +++ b/cypress/e2e/header.cy.ts @@ -8,11 +8,6 @@ describe('Header', () => { cy.get('ds-header').should('be.visible'); // Analyze <ds-header> for accessibility - testA11y({ - include: ['ds-header'], - exclude: [ - ['#search-navbar-container'] // search in navbar has duplicative ID. Will be fixed in #1174 - ], - }); + testA11y('ds-header'); }); }); diff --git a/src/app/search-navbar/search-navbar.component.html b/src/app/search-navbar/search-navbar.component.html index 02a98905021..e9b5f285fbc 100644 --- a/src/app/search-navbar/search-navbar.component.html +++ b/src/app/search-navbar/search-navbar.component.html @@ -1,4 +1,4 @@ -<div id="search-navbar-container" [title]="'nav.search' | translate" (dsClickOutside)="collapse()"> +<div [title]="'nav.search' | translate" (dsClickOutside)="collapse()"> <div class="d-inline-block position-relative"> <form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on" class="d-flex"> <input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query" diff --git a/src/app/search-navbar/search-navbar.component.spec.ts b/src/app/search-navbar/search-navbar.component.spec.ts index b67f5f0eb45..7edae293e12 100644 --- a/src/app/search-navbar/search-navbar.component.spec.ts +++ b/src/app/search-navbar/search-navbar.component.spec.ts @@ -8,7 +8,6 @@ import { SearchService } from '../core/shared/search/search.service'; import { TranslateLoaderMock } from '../shared/mocks/translate-loader.mock'; import { SearchNavbarComponent } from './search-navbar.component'; -import { PaginationServiceStub } from '../shared/testing/pagination-service.stub'; import { RouterTestingModule } from '@angular/router/testing'; import { BrowserOnlyMockPipe } from '../shared/testing/browser-only-mock.pipe'; @@ -17,8 +16,6 @@ describe('SearchNavbarComponent', () => { let fixture: ComponentFixture<SearchNavbarComponent>; let mockSearchService: any; let router: Router; - let routerStub; - let paginationService; beforeEach(waitForAsync(() => { mockSearchService = { @@ -27,12 +24,6 @@ describe('SearchNavbarComponent', () => { } }; - routerStub = { - navigate: (commands) => commands - }; - - paginationService = new PaginationServiceStub(); - TestBed.configureTestingModule({ imports: [ FormsModule, @@ -72,7 +63,7 @@ describe('SearchNavbarComponent', () => { spyOn(component, 'expand').and.callThrough(); spyOn(component, 'onSubmit').and.callThrough(); spyOn(router, 'navigate'); - const searchIcon = fixture.debugElement.query(By.css('#search-navbar-container form .submit-icon')); + const searchIcon = fixture.debugElement.query(By.css('form .submit-icon')); searchIcon.triggerEventHandler('click', { preventDefault: () => {/**/ } @@ -88,7 +79,7 @@ describe('SearchNavbarComponent', () => { describe('empty query', () => { describe('press submit button', () => { beforeEach(fakeAsync(() => { - const searchIcon = fixture.debugElement.query(By.css('#search-navbar-container form .submit-icon')); + const searchIcon = fixture.debugElement.query(By.css('form .submit-icon')); searchIcon.triggerEventHandler('click', { preventDefault: () => {/**/ } @@ -97,7 +88,7 @@ describe('SearchNavbarComponent', () => { fixture.detectChanges(); })); it('to search page with empty query', () => { - const extras: NavigationExtras = {queryParams: { query: '' }, queryParamsHandling: 'merge'}; + const extras: NavigationExtras = { queryParams: { query: '' }, queryParamsHandling: 'merge' }; expect(component.onSubmit).toHaveBeenCalledWith({ query: '' }); expect(router.navigate).toHaveBeenCalledWith(['search'], extras); }); @@ -109,20 +100,20 @@ describe('SearchNavbarComponent', () => { beforeEach(async () => { await fixture.whenStable(); fixture.detectChanges(); - searchInput = fixture.debugElement.query(By.css('#search-navbar-container form input')); + searchInput = fixture.debugElement.query(By.css('form input')); searchInput.nativeElement.value = 'test'; searchInput.nativeElement.dispatchEvent(new Event('input')); fixture.detectChanges(); }); describe('press submit button', () => { beforeEach(fakeAsync(() => { - const searchIcon = fixture.debugElement.query(By.css('#search-navbar-container form .submit-icon')); + const searchIcon = fixture.debugElement.query(By.css('form .submit-icon')); searchIcon.triggerEventHandler('click', null); tick(); fixture.detectChanges(); })); it('to search page with query', async () => { - const extras: NavigationExtras = { queryParams: { query: 'test' }, queryParamsHandling: 'merge'}; + const extras: NavigationExtras = { queryParams: { query: 'test' }, queryParamsHandling: 'merge' }; expect(component.onSubmit).toHaveBeenCalledWith({ query: 'test' }); expect(router.navigate).toHaveBeenCalledWith(['search'], extras); From fce5cdcc7295eeb2882465dad3fe9ba2a28e427f Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 28 Nov 2023 16:04:50 -0600 Subject: [PATCH 226/282] Refactor to simply use the reusable-docker-build.yml from DSpace/DSpace. --- .github/workflows/docker.yml | 305 ++++------------------------------- 1 file changed, 30 insertions(+), 275 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a581b63e7b0..ece1f880c0a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -3,6 +3,9 @@ name: Docker images # Run this Build for all pushes to 'main' or maintenance branches, or tagged releases. # Also run for PRs to ensure PR doesn't break Docker build process +# NOTE: uses "reusable-docker-build.yml" in DSpace/DSpace to actually build each of the Docker images +# https://github.com/DSpace/DSpace/blob/main/.github/workflows/reusable-docker-build.yml +# on: push: branches: @@ -17,7 +20,6 @@ permissions: env: - REGISTRY_IMAGE: dspace/dspace-angular # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. # For a new commit on other branches, use the branch name as the tag for Docker image. @@ -34,287 +36,40 @@ env: jobs: ############################################################# - # Build/Push the '${{ env.REGISTRY_IMAGE }}' image + # Build/Push the 'dspace/dspace-angular' image ############################################################# dspace-angular: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' if: github.repository == 'dspace/dspace-angular' - - strategy: - matrix: - # Architectures / Platforms for which we will build Docker images - arch: ['linux/amd64', 'linux/arm64'] - os: [ubuntu-latest] - isPr: - - ${{ github.event_name == 'pull_request' }} - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # The below exclude therefore ensures we do NOT build ARM64 for PRs. - exclude: - - isPr: true - os: ubuntu-latest - arch: linux/arm64 - - runs-on: ${{ matrix.os }} - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: ${{ ! matrix.isPr }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # https://github.com/docker/metadata-action - # Get Metadata for docker_build step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular' image - id: meta_build - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY_IMAGE }} - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - # https://github.com/docker/build-push-action - - name: Build and push 'dspace-angular' image - id: docker_build - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - platforms: ${{ matrix.arch }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ ! matrix.isPr }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build.outputs.tags }} - labels: ${{ steps.meta_build.outputs.labels }} - - # Export the digest of Docker build locally (for non PRs only) - - name: Export digest - if: ${{ ! matrix.isPr }} - run: | - mkdir -p /tmp/digests - digest="${{ steps.docker_build.outputs.digest }}" - touch "/tmp/digests/${digest#sha256:}" - - # Upload digest to an artifact, so that it can be used in manifest below - - name: Upload digest - if: ${{ ! matrix.isPr }} - uses: actions/upload-artifact@v3 - with: - name: digests - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - # Merge digests into a manifest. - # This runs after all Docker builds complete above, and it tells hub.docker.com - # that these builds should be all included in the manifest for this tag. - # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image) - # Borrowed from https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners - dspace-angular_manifest: - if: ${{ github.event_name != 'pull_request' }} - runs-on: ubuntu-latest - needs: - - dspace-angular - steps: - - name: Download digests - uses: actions/download-artifact@v3 - with: - name: digests - path: /tmp/digests - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Add Docker metadata for image - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY_IMAGE }} - tags: ${{ env.IMAGE_TAGS }} - flavor: ${{ env.TAGS_FLAVOR }} - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - - name: Create manifest list from digests and push - working-directory: /tmp/digests - run: | - docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) - - - name: Inspect image - run: | - docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} + # Use the reusable-docker-build.yml script from DSpace/DSpace repo to build our Docker image + uses: DSpace/DSpace/.github/workflows/reusable-docker-build.yml@main + with: + build_id: dspace-angular + image_name: dspace/dspace-angular + dockerfile_path: ./Dockerfile + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} ############################################################# - # Build/Push the '${{ env.REGISTRY_IMAGE }}' image ('-dist' tag) + # Build/Push the 'dspace/dspace-angular' image ('-dist' tag) ############################################################# dspace-angular-dist: # Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular' if: github.repository == 'dspace/dspace-angular' - - strategy: - matrix: - # Architectures / Platforms for which we will build Docker images - arch: ['linux/amd64', 'linux/arm64'] - os: [ubuntu-latest] - isPr: - - ${{ github.event_name == 'pull_request' }} - # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. - # The below exclude therefore ensures we do NOT build ARM64 for PRs. - exclude: - - isPr: true - os: ubuntu-latest - arch: linux/arm64 - - runs-on: ${{ matrix.os }} - steps: - # https://github.com/actions/checkout - - name: Checkout codebase - uses: actions/checkout@v4 - - # https://github.com/docker/setup-buildx-action - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 - - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU emulation to build for multiple architectures - uses: docker/setup-qemu-action@v3 - - # https://github.com/docker/login-action - - name: Login to DockerHub - # Only login if not a PR, as PRs only trigger a Docker build and not a push - if: ${{ ! matrix.isPr }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - # https://github.com/docker/metadata-action - # Get Metadata for docker_build_dist step below - - name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-angular-dist' image - id: meta_build_dist - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY_IMAGE }} - tags: ${{ env.IMAGE_TAGS }} - # As this is a "dist" image, its tags are all suffixed with "-dist". Otherwise, it uses the same - # tagging logic as the primary '${{ env.REGISTRY_IMAGE }}' image above. - flavor: ${{ env.TAGS_FLAVOR }} - suffix=-dist - - - name: Build and push 'dspace-angular-dist' image - id: docker_build_dist - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile.dist - platforms: ${{ matrix.arch }} - # For pull requests, we run the Docker build (to ensure no PR changes break the build), - # but we ONLY do an image push to DockerHub if it's NOT a PR - push: ${{ ! matrix.isPr }} - # Use tags / labels provided by 'docker/metadata-action' above - tags: ${{ steps.meta_build_dist.outputs.tags }} - labels: ${{ steps.meta_build_dist.outputs.labels }} - - # Export the digest of Docker build locally (for non PRs only) - - name: Export digest - if: ${{ ! matrix.isPr }} - run: | - mkdir -p /tmp/digests - digest="${{ steps.docker_build_dist.outputs.digest }}" - touch "/tmp/digests/${digest#sha256:}" - - # Upload Digest to an artifact, so that it can be used in manifest below - - name: Upload digest - if: ${{ ! matrix.isPr }} - uses: actions/upload-artifact@v3 - with: - # NOTE: It's important that this artifact has a unique name so that two - # image builds don't upload digests to the same artifact. - name: digests-dist - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - # If the 'linux/amd64' -dist image was just updated for the 'main' branch, - # Then redeploy https://sandbox.dspace.org using that updated image. - - name: Redeploy sandbox.dspace.org (based on main branch) - if: ${{ ! matrix.isPr && matrix.arch == 'linux/amd64' && github.ref_name == github.event.repository.default_branch }} - run: | - curl -X POST $REDEPLOY_SANDBOX_URL - env: - REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} - - # If the 'linux/amd64' -dist image was just updated for the maintenance branch, - # Then redeploy https://demo.dspace.org using that updated image. - - name: Redeploy demo.dspace.org (based on maintenace branch) - if: ${{ ! matrix.isPr && matrix.arch == 'linux/amd64' && github.ref_name == 'dspace-7_x' }} - run: | - curl -X POST $REDEPLOY_DEMO_URL - env: - REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} - - # Merge *-dist digests into a manifest. - # This runs after all Docker builds complete above, and it tells hub.docker.com - # that these builds should be all included in the manifest for this tag. - # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image) - dspace-angular-dist_manifest: - if: ${{ github.event_name != 'pull_request' }} - runs-on: ubuntu-latest - needs: - - dspace-angular-dist - steps: - - name: Download digests for -dist builds - uses: actions/download-artifact@v3 - with: - name: digests-dist - path: /tmp/digests - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Add Docker metadata for image - id: meta_dist - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY_IMAGE }} - tags: ${{ env.IMAGE_TAGS }} - # As this is a "dist" image, its tags are all suffixed with "-dist". Otherwise, it uses the same - # tagging logic as the primary '${{ env.REGISTRY_IMAGE }}' image above. - flavor: ${{ env.TAGS_FLAVOR }} - suffix=-dist - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - - name: Create manifest list from digests and push - working-directory: /tmp/digests - run: | - docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) - - - name: Inspect image - run: | - docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta_dist.outputs.version }} + # Use the reusable-docker-build.yml script from DSpace/DSpace repo to build our Docker image + uses: DSpace/DSpace/.github/workflows/reusable-docker-build.yml@main + with: + build_id: dspace-angular-dist + image_name: dspace/dspace-angular + dockerfile_path: ./Dockerfile.dist + # As this is a "dist" image, its tags are all suffixed with "-dist". Otherwise, it uses the same + # tagging logic as the primary 'dspace/dspace-angular' image above. + tags_flavor: suffix=-dist + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }} + # Enable redeploy of sandbox & demo if the branch for this image matches the deployment branch of + # these sites as specified in reusable-docker-build.xml + REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }} + REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }} \ No newline at end of file From b30fd4bb0ba6926c6ef64e88eb597d69b2e594df Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 28 Nov 2023 16:50:55 -0600 Subject: [PATCH 227/282] Remove unused env variables --- .github/workflows/docker.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ece1f880c0a..85a72161131 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,22 +18,6 @@ on: permissions: contents: read # to fetch code (actions/checkout) - -env: - # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action) - # For a new commit on default branch (main), use the literal tag 'latest' on Docker image. - # For a new commit on other branches, use the branch name as the tag for Docker image. - # For a new tag, copy that tag name as the tag for Docker image. - IMAGE_TAGS: | - type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }} - type=ref,event=branch,enable=${{ github.ref_name != github.event.repository.default_branch }} - type=ref,event=tag - # Define default tag "flavor" for docker/metadata-action per - # https://github.com/docker/metadata-action#flavor-input - # We manage the 'latest' tag ourselves to the 'main' branch (see settings above) - TAGS_FLAVOR: | - latest=false - jobs: ############################################################# # Build/Push the 'dspace/dspace-angular' image From 88c39e8b26d4418c370185467e2fee006c3cd811 Mon Sep 17 00:00:00 2001 From: Michael Spalti <mspalti@gmail.com> Date: Wed, 29 Nov 2023 15:42:30 -0800 Subject: [PATCH 228/282] Fix for thumbnail images in items. Revert changes in html template Revert changes in html template Revert changes in html template --- src/app/item-page/media-viewer/media-viewer.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/item-page/media-viewer/media-viewer.component.ts b/src/app/item-page/media-viewer/media-viewer.component.ts index 242e50646e3..5a17c4f01b4 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.ts +++ b/src/app/item-page/media-viewer/media-viewer.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { filter, take } from 'rxjs/operators'; import { BitstreamDataService } from '../../core/data/bitstream-data.service'; @@ -42,6 +42,7 @@ export class MediaViewerComponent implements OnDestroy, OnInit { constructor( protected bitstreamDataService: BitstreamDataService, + protected changeDetectorRef: ChangeDetectorRef ) { } @@ -85,6 +86,7 @@ export class MediaViewerComponent implements OnDestroy, OnInit { })); } this.isLoading = false; + this.changeDetectorRef.detectChanges(); })); } })); From c300123b785a75499d1362cecf2b6102660c4508 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 26 Nov 2023 21:28:12 +0100 Subject: [PATCH 229/282] Fix Bulk Access Management usability issues - Added aria-labels to trash & select bitstream icon - Added aria-labels ui-switch components (had to upgrade ngx-ui-switch to 14.1.0) - Fixed aria-controls pointing to non-existing ids - Fixed bulk-access-browse not having the tab role on it's tabs - Fixed role="tablist" not having direct role="tab" by adding role="presentation" on the li elements - Fixed aria-expanded being set to true when collapsed and backwards for BulkAccessBrowseComponent & BulkAccessSettingsComponent --- package.json | 2 +- .../browse/bulk-access-browse.component.html | 102 +++++++++--------- .../bulk-access-settings.component.html | 12 +-- .../access-control-array-form.component.html | 1 + ...cess-control-form-container.component.html | 8 +- src/assets/i18n/en.json5 | 12 +++ yarn.lock | 8 +- 7 files changed, 82 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index 553962dfeb7..e5347742c8c 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "ngx-infinite-scroll": "^15.0.0", "ngx-pagination": "6.0.3", "ngx-sortablejs": "^11.1.0", - "ngx-ui-switch": "^14.0.3", + "ngx-ui-switch": "^14.1.0", "nouislider": "^15.7.1", "pem": "1.14.7", "prop-types": "^15.8.1", diff --git a/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html b/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html index c716aedb8b3..6e967b53b5e 100644 --- a/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html +++ b/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html @@ -1,15 +1,15 @@ <ngb-accordion #acc="ngbAccordion" [activeIds]="'browse'"> <ngb-panel [id]="'browse'"> <ng-template ngbPanelHeader> - <div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('browse')" + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('browse')" data-test="browse"> <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" - [attr.aria-expanded]="!acc.isExpanded('browse')" - aria-controls="collapsePanels"> + [attr.aria-expanded]="acc.isExpanded('browse')" + aria-controls="bulk-access-browse-panel-content"> {{ 'admin.access-control.bulk-access-browse.header' | translate }} </button> - <div class="text-right d-flex"> - <div class="ml-3 d-inline-block"> + <div class="text-right d-flex gap-2"> + <div class="d-flex my-auto"> <span *ngIf="acc.isExpanded('browse')" class="fas fa-chevron-up fa-fw"></span> <span *ngIf="!acc.isExpanded('browse')" class="fas fa-chevron-down fa-fw"></span> </div> @@ -17,51 +17,53 @@ </div> </ng-template> <ng-template ngbPanelContent> - <ul ngbNav #nav="ngbNav" [(activeId)]="activateId" class="nav-pills"> - <li [ngbNavItem]="'search'"> - <a ngbNavLink>{{'admin.access-control.bulk-access-browse.search.header' | translate}}</a> - <ng-template ngbNavContent> - <div class="mx-n3"> - <ds-themed-search [configuration]="'administrativeBulkAccess'" - [selectable]="true" - [selectionConfig]="{ repeatable: true, listId: listId }" - [showThumbnails]="false"></ds-themed-search> - </div> - </ng-template> - </li> - <li [ngbNavItem]="'selected'"> - <a ngbNavLink> - {{'admin.access-control.bulk-access-browse.selected.header' | translate: {number: ((objectsSelected$ | async)?.payload?.totalElements) ? (objectsSelected$ | async)?.payload?.totalElements : '0'} }} - </a> - <ng-template ngbNavContent> - <ds-pagination - [paginationOptions]="(paginationOptions$ | async)" - [pageInfoState]="(objectsSelected$|async)?.payload.pageInfo" - [collectionSize]="(objectsSelected$|async)?.payload?.totalElements" - [objects]="(objectsSelected$|async)" - [showPaginator]="false" - (prev)="pagePrev()" - (next)="pageNext()"> - <ul *ngIf="(objectsSelected$|async)?.hasSucceeded" class="list-unstyled ml-4"> - <li *ngFor='let object of (objectsSelected$|async)?.payload?.page | paginate: { itemsPerPage: (paginationOptions$ | async).pageSize, - currentPage: (paginationOptions$ | async).currentPage, totalItems: (objectsSelected$|async)?.payload?.page.length }; let i = index; let last = last ' - class="mt-4 mb-4 d-flex" - [attr.data-test]="'list-object' | dsBrowserOnly"> - <ds-selectable-list-item-control [index]="i" - [object]="object" - [selectionConfig]="{ repeatable: true, listId: listId }"></ds-selectable-list-item-control> - <ds-listable-object-component-loader [listID]="listId" - [index]="i" - [object]="object" - [showThumbnails]="false" - [viewMode]="'list'"></ds-listable-object-component-loader> - </li> - </ul> - </ds-pagination> - </ng-template> - </li> - </ul> - <div [ngbNavOutlet]="nav" class="mt-5"></div> + <div id="bulk-access-browse-panel-content"> + <ul ngbNav #nav="ngbNav" [(activeId)]="activateId" class="nav-pills"> + <li [ngbNavItem]="'search'" role="presentation"> + <a ngbNavLink>{{'admin.access-control.bulk-access-browse.search.header' | translate}}</a> + <ng-template ngbNavContent> + <div class="mx-n3"> + <ds-themed-search [configuration]="'administrativeBulkAccess'" + [selectable]="true" + [selectionConfig]="{ repeatable: true, listId: listId }" + [showThumbnails]="false"></ds-themed-search> + </div> + </ng-template> + </li> + <li [ngbNavItem]="'selected'" role="presentation"> + <a ngbNavLink> + {{'admin.access-control.bulk-access-browse.selected.header' | translate: {number: ((objectsSelected$ | async)?.payload?.totalElements) ? (objectsSelected$ | async)?.payload?.totalElements : '0'} }} + </a> + <ng-template ngbNavContent> + <ds-pagination + [paginationOptions]="(paginationOptions$ | async)" + [pageInfoState]="(objectsSelected$|async)?.payload.pageInfo" + [collectionSize]="(objectsSelected$|async)?.payload?.totalElements" + [objects]="(objectsSelected$|async)" + [showPaginator]="false" + (prev)="pagePrev()" + (next)="pageNext()"> + <ul *ngIf="(objectsSelected$|async)?.hasSucceeded" class="list-unstyled ml-4"> + <li *ngFor='let object of (objectsSelected$|async)?.payload?.page | paginate: { itemsPerPage: (paginationOptions$ | async).pageSize, + currentPage: (paginationOptions$ | async).currentPage, totalItems: (objectsSelected$|async)?.payload?.page.length }; let i = index; let last = last ' + class="mt-4 mb-4 d-flex" + [attr.data-test]="'list-object' | dsBrowserOnly"> + <ds-selectable-list-item-control [index]="i" + [object]="object" + [selectionConfig]="{ repeatable: true, listId: listId }"></ds-selectable-list-item-control> + <ds-listable-object-component-loader [listID]="listId" + [index]="i" + [object]="object" + [showThumbnails]="false" + [viewMode]="'list'"></ds-listable-object-component-loader> + </li> + </ul> + </ds-pagination> + </ng-template> + </li> + </ul> + <div [ngbNavOutlet]="nav" class="mt-5"></div> + </div> </ng-template> </ngb-panel> </ngb-accordion> diff --git a/src/app/access-control/bulk-access/settings/bulk-access-settings.component.html b/src/app/access-control/bulk-access/settings/bulk-access-settings.component.html index 01f36ef03f4..c41053874e7 100644 --- a/src/app/access-control/bulk-access/settings/bulk-access-settings.component.html +++ b/src/app/access-control/bulk-access/settings/bulk-access-settings.component.html @@ -1,13 +1,13 @@ <ngb-accordion #acc="ngbAccordion" [activeIds]="'settings'"> <ngb-panel [id]="'settings'"> <ng-template ngbPanelHeader> - <div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('settings')" data-test="settings"> - <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="!acc.isExpanded('browse')" - aria-controls="collapsePanels"> + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('settings')" data-test="settings"> + <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded('settings')" + aria-controls="bulk-access-settings-panel-content"> {{ 'admin.access-control.bulk-access-settings.header' | translate }} </button> - <div class="text-right d-flex"> - <div class="ml-3 d-inline-block"> + <div class="text-right d-flex gap-2"> + <div class="d-flex my-auto"> <span *ngIf="acc.isExpanded('settings')" class="fas fa-chevron-up fa-fw"></span> <span *ngIf="!acc.isExpanded('settings')" class="fas fa-chevron-down fa-fw"></span> </div> @@ -15,7 +15,7 @@ </div> </ng-template> <ng-template ngbPanelContent> - <ds-access-control-form-container #dsAccessControlForm [showSubmit]="false"></ds-access-control-form-container> + <ds-access-control-form-container id="bulk-access-settings-panel-content" #dsAccessControlForm [showSubmit]="false"></ds-access-control-form-container> </ng-template> </ngb-panel> </ngb-accordion> diff --git a/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html b/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html index cd56904bd7f..e6ebabd707b 100644 --- a/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html +++ b/src/app/shared/access-control-form-container/access-control-array-form/access-control-array-form.component.html @@ -92,6 +92,7 @@ <div class="input-group"> <button type="button" class="btn btn-outline-danger" + [attr.aria-label]="'access-control-remove' | translate" [disabled]="ngForm.disabled || form.accessControls.length === 1" (click)="removeAccessControlItem(control.id)"> <i class="fas fa-trash"></i> diff --git a/src/app/shared/access-control-form-container/access-control-form-container.component.html b/src/app/shared/access-control-form-container/access-control-form-container.component.html index a5173d10d7d..263bf60ac7b 100644 --- a/src/app/shared/access-control-form-container/access-control-form-container.component.html +++ b/src/app/shared/access-control-form-container/access-control-form-container.component.html @@ -4,10 +4,11 @@ <ds-alert *ngIf="titleMessage" [type]="AlertType.Info" - [content]="titleMessage"> + [content]="titleMessage" + class="d-block pb-3"> </ds-alert> - <div class="row mt-5"> + <div class="row"> <div class="col-12 col-md-6 border-right d-flex flex-column justify-content-between"> <div> @@ -16,6 +17,7 @@ <h4 class="mb-0 mr-4"> {{ 'access-control-item-header-toggle' | translate }} </h4> <ui-switch + [ariaLabel]="(state.bitstream.toggleStatus ? 'access-control-item-toggle.disable' : 'access-control-item-toggle.enable') | translate" [(ngModel)]="state.item.toggleStatus" (ngModelChange)="handleStatusChange('item', $event)"> </ui-switch> @@ -69,6 +71,7 @@ <h4 class="mb-0 mr-4"> {{'access-control-bitstream-header-toggle' | translate}} </h4> <ui-switch + [ariaLabel]="(state.bitstream.toggleStatus ? 'access-control-bitstream-toggle.disable' : 'access-control-bitstream-toggle.enable') | translate" [(ngModel)]="state.bitstream.toggleStatus" (ngModelChange)="handleStatusChange('bitstream', $event)"> </ui-switch> @@ -99,6 +102,7 @@ <h4 class="mb-0 mr-4"> <button *ngIf="itemRD" + [attr.aria-label]="'access-control-bitstreams-select' | translate" [disabled]="!state.bitstream.toggleStatus || state.bitstream.changesLimit !== 'selected'" (click)="openSelectBitstreamsModal(itemRD.payload)" class="btn btn-outline-dark border-0" type="button"> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6dee5d54e66..ebe515921d4 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -5190,8 +5190,16 @@ "access-control-item-header-toggle": "Item's Metadata", + "access-control-item-toggle.enable": "Enable option to perform changes on the item's metadata", + + "access-control-item-toggle.disable": "Disable option to perform changes on the item's metadata", + "access-control-bitstream-header-toggle": "Bitstreams", + "access-control-bitstream-toggle.enable": "Enable option to perform changes on the bitstreams", + + "access-control-bitstream-toggle.disable": "Disable option to perform changes on the bitstreams", + "access-control-mode": "Mode", "access-control-access-conditions": "Access conditions", @@ -5208,12 +5216,16 @@ "access-control-bitstreams-selected": "bitstreams selected", + "access-control-bitstreams-select": "Select bitstreams", + "access-control-cancel": "Cancel", "access-control-execute": "Execute", "access-control-add-more": "Add more", + "access-control-remove": "Remove access condition", + "access-control-select-bitstreams-modal.title": "Select bitstreams", "access-control-select-bitstreams-modal.no-items": "No items to show.", diff --git a/yarn.lock b/yarn.lock index 27307aefa2f..6e04ab27b2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8369,10 +8369,10 @@ ngx-sortablejs@^11.1.0: dependencies: tslib "^2.0.0" -ngx-ui-switch@^14.0.3: - version "14.0.3" - resolved "https://registry.npmjs.org/ngx-ui-switch/-/ngx-ui-switch-14.0.3.tgz" - integrity sha512-SZ8ZnTCuNJgNWuY3/mOG3TdsRUNPCX3vGdCKKx1ZHVMTUynerJQlTWck2JrYlnrexNnd7wy4P10jDvdtDwoYeg== +ngx-ui-switch@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/ngx-ui-switch/-/ngx-ui-switch-14.1.0.tgz#32248361a684257c5ae64cfde61b95de920b901c" + integrity sha512-uGGLppBP1FXjyD+x7f8Pm6I3JQTMmsBqPtwERAX27jSZxDWFp/sewnl75fuDvu75qFofJd/BIOtV4xHxzgZOvw== dependencies: tslib "^2.3.0" From 3628c84844aeccafa0bc91a44c6710596ba6a3f7 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 26 Nov 2023 23:53:44 +0100 Subject: [PATCH 230/282] Fix Health Panel usability issues - Fixed aria-controls on HealthComponentComponent, HealthInfoComponent, HealthInfoComponentComponent, HealthPanelComponent pointing to non-existing id - Fixed the tabs not having the role tab on its tabs - Fixed aria-expanded being set to true when collapsed and backwards for HealthPanelComponent & HealthInfoComponent - Fixed role="tablist" not having direct role="tab" by adding role="presentation" on the li elements - Fixed minor alignment issues --- .../health-info-component.component.html | 8 +++---- .../health-info/health-info.component.html | 15 ++++++------- .../health-page/health-page.component.html | 6 +++--- src/app/health-page/health-page.component.ts | 3 +++ .../health-component.component.html | 8 +++---- .../health-panel/health-panel.component.html | 21 +++++++++++-------- .../health-status.component.html | 6 +++--- .../health-status.component.scss | 3 +++ 8 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/app/health-page/health-info/health-info-component/health-info-component.component.html b/src/app/health-page/health-info/health-info-component/health-info-component.component.html index dbaaa7a6b6e..84cba4d92f3 100644 --- a/src/app/health-page/health-info/health-info-component/health-info-component.component.html +++ b/src/app/health-page/health-info/health-info-component/health-info-component.component.html @@ -1,16 +1,16 @@ <div *ngFor="let entry of healthInfoComponent | dsObjNgFor" data-test="collapse"> <div *ngIf="entry && !isPlainProperty(entry.value)" class="mb-3 border-bottom"> - <div class="w-100 d-flex justify-content-between collapse-toggle" (click)="collapse.toggle()"> + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" (click)="collapse.toggle()"> <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="!collapse.collapsed" - aria-controls="collapseExample"> + [attr.aria-controls]="'health-info-component-' + entry.key + '-content'"> {{ entry.key | titlecase }} </button> - <div class="d-inline-block"> + <div class="d-flex my-auto"> <span *ngIf="collapse.collapsed" class="fas fa-chevron-down"></span> <span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span> </div> </div> - <div #collapse="ngbCollapse" [ngbCollapse]="isCollapsed"> + <div #collapse="ngbCollapse" [id]="'health-info-component-' + entry.key + '-content'" [ngbCollapse]="isCollapsed"> <div class="card border-0"> <div class="card-body"> <ds-health-info-component [healthInfoComponent]="entry.value" diff --git a/src/app/health-page/health-info/health-info.component.html b/src/app/health-page/health-info/health-info.component.html index 4bafcaa2d8a..b590695b0b0 100644 --- a/src/app/health-page/health-info/health-info.component.html +++ b/src/app/health-page/health-info/health-info.component.html @@ -2,14 +2,14 @@ <ngb-accordion #acc="ngbAccordion" [activeIds]="activeId"> <ngb-panel [id]="entry.key" *ngFor="let entry of healthInfoResponse | dsObjNgFor"> <ng-template ngbPanelHeader> - <div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="info-component"> - <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="!acc.isExpanded(entry.key)" - aria-controls="collapsePanels"> + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="info-component"> + <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded(entry.key)" + [attr.aria-controls]="'health-info-' + entry.key + '-content'"> {{ getPanelLabel(entry.key) | titlecase }} </button> - <div class="text-right d-flex"> + <div class="text-right d-flex gap-2"> <ds-health-status [status]="entry.value?.status"></ds-health-status> - <div class="ml-3 d-inline-block"> + <div class="d-flex my-auto"> <span *ngIf="acc.isExpanded(entry.key)" class="fas fa-chevron-up fa-fw"></span> <span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span> </div> @@ -17,8 +17,9 @@ </div> </ng-template> <ng-template ngbPanelContent> - <ds-health-info-component [healthInfoComponentName]="entry.key" - [healthInfoComponent]="entry.value"></ds-health-info-component> + <ds-health-info-component [healthInfoComponentName]="entry.key" [healthInfoComponent]="entry.value" + [id]="'health-info-' + entry.key + '-content'"> + </ds-health-info-component> </ng-template> </ngb-panel> </ngb-accordion> diff --git a/src/app/health-page/health-page.component.html b/src/app/health-page/health-page.component.html index 8083389e1b4..15a87878941 100644 --- a/src/app/health-page/health-page.component.html +++ b/src/app/health-page/health-page.component.html @@ -2,7 +2,7 @@ <h2>{{'health-page.heading' | translate}}</h2> <div *ngIf="(healthResponse | async) && (healthInfoResponse | async)"> <ul ngbNav #nav="ngbNav" [activeId]="'status'" class="nav-tabs"> - <li [ngbNavItem]="'status'"> + <li [ngbNavItem]="'status'" role="presentation"> <a ngbNavLink>{{'health-page.status-tab' | translate}}</a> <ng-template ngbNavContent> <div id="status"> @@ -10,7 +10,7 @@ <h2>{{'health-page.heading' | translate}}</h2> </div> </ng-template> </li> - <li [ngbNavItem]="'info'"> + <li [ngbNavItem]="'info'" role="presentation"> <a ngbNavLink>{{'health-page.info-tab' | translate}}</a> <ng-template ngbNavContent> <div id="info"> @@ -21,7 +21,7 @@ <h2>{{'health-page.heading' | translate}}</h2> </ul> <div [ngbNavOutlet]="nav" class="mt-2"></div> </div> - <ds-alert *ngIf="!(healthResponse | async) || !(healthInfoResponse | async)" [type]="'alert-danger'" [content]="'health-page.error.msg'"></ds-alert> + <ds-alert *ngIf="!(healthResponse | async) || !(healthInfoResponse | async)" [type]="AlertType.Error" [content]="'health-page.error.msg'"></ds-alert> </div> diff --git a/src/app/health-page/health-page.component.ts b/src/app/health-page/health-page.component.ts index aa7bd7cba46..5c3c7ed70e2 100644 --- a/src/app/health-page/health-page.component.ts +++ b/src/app/health-page/health-page.component.ts @@ -5,6 +5,7 @@ import { take } from 'rxjs/operators'; import { HealthService } from './health.service'; import { HealthInfoResponse, HealthResponse } from './models/health-component.model'; +import { AlertType } from '../shared/alert/alert-type'; @Component({ selector: 'ds-health-page', @@ -33,6 +34,8 @@ export class HealthPageComponent implements OnInit { */ healthInfoResponseInitialised: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); + readonly AlertType = AlertType; + constructor(private healthDataService: HealthService) { } diff --git a/src/app/health-page/health-panel/health-component/health-component.component.html b/src/app/health-page/health-panel/health-component/health-component.component.html index 1f29c8c9fcc..f962e66052e 100644 --- a/src/app/health-page/health-panel/health-component/health-component.component.html +++ b/src/app/health-page/health-panel/health-component/health-component.component.html @@ -1,16 +1,16 @@ <ng-container *ngIf="healthComponent?.components"> <div *ngFor="let entry of healthComponent?.components | dsObjNgFor" class="mb-3 border-bottom" data-test="collapse"> - <div class="w-100 d-flex justify-content-between collapse-toggle" (click)="collapse.toggle()"> + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" (click)="collapse.toggle()"> <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="!collapse.collapsed" - aria-controls="collapseExample"> + [attr.aria-controls]="'health-component-' + entry.key + 'content'"> {{ entry.key | titlecase }} </button> - <div class="d-inline-block"> + <div class="d-flex my-auto"> <span *ngIf="collapse.collapsed" class="fas fa-chevron-down"></span> <span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span> </div> </div> - <div #collapse="ngbCollapse" [ngbCollapse]="isCollapsed"> + <div #collapse="ngbCollapse" [id]="'health-component-' + entry.key + 'content'" [ngbCollapse]="isCollapsed"> <div class="card border-0"> <div class="card-body"> <ds-health-component [healthComponent]="entry.value" diff --git a/src/app/health-page/health-panel/health-panel.component.html b/src/app/health-page/health-panel/health-panel.component.html index 2d67fa537b6..ec2a27ce408 100644 --- a/src/app/health-page/health-panel/health-panel.component.html +++ b/src/app/health-page/health-panel/health-panel.component.html @@ -1,15 +1,18 @@ -<p class="h4">{{'health-page.status' | translate}} : <ds-health-status [status]="healthResponse.status"></ds-health-status></p> +<p class="h4"> + {{'health-page.status' | translate}}: + <ds-health-status [status]="healthResponse.status" class="d-inline-flex"></ds-health-status> +</p> <ngb-accordion #acc="ngbAccordion" [activeIds]="activeId"> <ngb-panel [id]="entry.key" *ngFor="let entry of healthResponse.components | dsObjNgFor"> <ng-template ngbPanelHeader> - <div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="component"> - <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="!acc.isExpanded(entry.key)" - aria-controls="collapsePanels"> + <div class="w-100 d-flex gap-3 justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="component"> + <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded(entry.key)" + [attr.aria-controls]="'health-panel-' + entry.key + '-content'"> {{ getPanelLabel(entry.key) | titlecase }} </button> - <div class="text-right d-flex"> + <div class="text-right d-flex gap-2"> <ds-health-status [status]="entry.value?.status"></ds-health-status> - <div class="ml-3 d-inline-block"> + <div class="d-flex my-auto"> <span *ngIf="acc.isExpanded(entry.key)" class="fas fa-chevron-up fa-fw"></span> <span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span> </div> @@ -17,9 +20,9 @@ </div> </ng-template> <ng-template ngbPanelContent> - <ds-health-component [healthComponent]="entry.value" [healthComponentName]="entry.key"></ds-health-component> + <ds-health-component [healthComponent]="entry.value" [healthComponentName]="entry.key" + [id]="'health-panel-' + entry.key + '-content'" role="presentation"> + </ds-health-component> </ng-template> </ngb-panel> </ngb-accordion> - - diff --git a/src/app/health-page/health-panel/health-status/health-status.component.html b/src/app/health-page/health-panel/health-status/health-status.component.html index 38a6f726018..e8710a07600 100644 --- a/src/app/health-page/health-panel/health-status/health-status.component.html +++ b/src/app/health-page/health-panel/health-status/health-status.component.html @@ -1,12 +1,12 @@ <ng-container [ngSwitch]="status"> <i *ngSwitchCase="HealthStatus.UP" - class="fa fa-check-circle text-success ml-2 mt-1" + class="fa fa-check-circle text-success my-auto" ngbTooltip="{{'health-page.status.ok.info' | translate}}" container="body" ></i> <i *ngSwitchCase="HealthStatus.UP_WITH_ISSUES" - class="fa fa-exclamation-triangle text-warning ml-2 mt-1" + class="fa fa-exclamation-triangle text-warning my-auto" ngbTooltip="{{'health-page.status.warning.info' | translate}}" container="body"></i> <i *ngSwitchCase="HealthStatus.DOWN" - class="fa fa-times-circle text-danger ml-2 mt-1" + class="fa fa-times-circle text-danger my-auto" ngbTooltip="{{'health-page.status.error.info' | translate}}" container="body"></i> </ng-container> diff --git a/src/app/health-page/health-panel/health-status/health-status.component.scss b/src/app/health-page/health-panel/health-status/health-status.component.scss index e69de29bb2d..79ff2d52696 100644 --- a/src/app/health-page/health-panel/health-status/health-status.component.scss +++ b/src/app/health-page/health-panel/health-status/health-status.component.scss @@ -0,0 +1,3 @@ +:host { + display: flex; +} From 3bdfc386e9d40321794c118dae55fd672bb06f76 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 27 Nov 2023 23:03:05 +0100 Subject: [PATCH 231/282] Fix System-wide Alert accessibility issues - Added missing aria-label to buttons --- .../alert-form/system-wide-alert-form.component.html | 6 ++++-- src/assets/i18n/en.json5 | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html index 169081e2777..d1de00bea6e 100644 --- a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html +++ b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html @@ -30,6 +30,7 @@ <h2 id="header">{{'system-wide-alert.form.header' | translate}}</h2> <div class="row"> <div class="col mb-2 d-flex align-items-end"> <ui-switch size="small" + [ariaLabel]="'system-wide-alert.form.label.countdownTo.enable' | translate" [checked]="counterEnabled$ |async" (change)="setCounterEnabled($event)"></ui-switch> <span class="ml-2">{{ 'system-wide-alert.form.label.countdownTo.enable' | translate }}</span> @@ -49,8 +50,9 @@ <h2 id="header">{{'system-wide-alert.form.header' | translate}}</h2> #d="ngbDatepicker" (ngModelChange)="updatePreviewTime()" /> - <button class="btn btn-outline-secondary fas fa-calendar" (click)="d.toggle()" - type="button"></button> + <button [attr.aria-label]="'system-wide-alert-form.select-date-by-calendar' | translate" + (click)="d.toggle()" class="btn btn-outline-secondary fas fa-calendar" type="button"> + </button> </div> </div> <div class="col-12 d-md-none"> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index ebe515921d4..7392b3da7ac 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -5168,6 +5168,8 @@ "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.select-date-by-calendar": "Select date using calendar", + "system-wide-alert.form.label.preview": "System-wide alert preview", "system-wide-alert.form.update.success": "The system-wide alert was successfully updated", From 4ea487cc0d9df74bee2ca286f5b4f1745bb31a1f Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Mon, 27 Nov 2023 23:18:56 +0100 Subject: [PATCH 232/282] Fix Processes Overview accessibility issues - Added missing aria-label to delete button --- .../process-page/overview/process-overview.component.html | 8 +++++--- src/assets/i18n/en.json5 | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/process-page/overview/process-overview.component.html b/src/app/process-page/overview/process-overview.component.html index 5bf5fee79f2..dcad265490a 100644 --- a/src/app/process-page/overview/process-overview.component.html +++ b/src/app/process-page/overview/process-overview.component.html @@ -44,9 +44,11 @@ <h2 class="flex-grow-1">{{'process.overview.title' | translate}}</h2> <td>{{process.endTime | date:dateFormat:'UTC'}}</td> <td>{{process.processStatus}}</td> <td> - <button class="btn btn-outline-danger" - (click)="processBulkDeleteService.toggleDelete(process.processId)"><i - class="fas fa-trash"></i></button> + <button [attr.aria-label]="'process.overview.delete-process' | translate" + (click)="processBulkDeleteService.toggleDelete(process.processId)" + class="btn btn-outline-danger"> + <i class="fas fa-trash"></i> + </button> </td> </tr> </tbody> 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 <alexandre@atmire.com> Date: Tue, 28 Nov 2023 00:20:35 +0100 Subject: [PATCH 233/282] 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 @@ <h2 class="col-12"> {{headerKey | translate}} </h2> - <div class="col-12 col-md-6"> + <div class="col-12 col-md-6 mb-2"> <form #form="ngForm" (ngSubmit)="submitForm(form)"> <ds-scripts-select [script]="selectedScript" (select)="selectedScript = $event; parameters = undefined"></ds-scripts-select> <ds-process-parameters [initialParams]="parameters" [script]="selectedScript" (updateParameters)="parameters = $event"></ds-process-parameters> - <button [routerLink]="['/processes']" class="btn btn-light float-left">{{ 'process.new.cancel' | translate }}</button> - <button type="submit" class="btn btn-light float-right">{{ 'process.new.submit' | translate }}</button> + <a [routerLink]="['/processes']" class="btn btn-danger float-left">{{ 'process.new.cancel' | translate }}</a> + <button type="submit" class="btn btn-primary float-right">{{ 'process.new.submit' | translate }}</button> </form> </div> <div class="col-12 col-md-6"> 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 @@ -<div class="form-row mb-2 mx-0"> +<div class="form-row gap-2 mb-2 mx-0"> <select id="process-parameters" class="form-control col" name="parameter-{{index}}" + [attr.aria-label]="'process.new.select-parameter' | translate" [(ngModel)]="selectedParameter" #param="ngModel"> - <option [ngValue]="undefined">Add a parameter...</option> + <option [ngValue]="undefined">{{ 'process.new.add-parameter' | translate }}</option> <option *ngFor="let param of parameters" [ngValue]="param.name"> {{param.nameLong || param.name}} </option> </select> - <ds-parameter-value-input [initialValue]="parameterValue.value" [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" class="d-block col" [index]="index"></ds-parameter-value-input> - <button *ngIf="removable" class="btn btn-light col-1 remove-button" (click)="removeParameter.emit(parameterValue);"><span class="fas fa-trash"></span></button> + <ds-parameter-value-input [initialValue]="parameterValue.value" [parameter]="selectedScriptParameter" (updateValue)="selectedParameterValue = $event" class="d-block col px-0" [index]="index"></ds-parameter-value-input> + <button *ngIf="removable" [attr.aria-label]="'process.new.delete-parameter' | translate" + (click)="removeParameter.emit(parameterValue);" class="btn btn-danger col-1 remove-button"> + <i class="fas fa-trash"></i> + </button> <span *ngIf="!removable" class="col-1"></span> </div> 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 @@ -<input type="hidden" value="true" name="boolean-value-{{index}}" id="boolean-value-{{index}}"/> +<input [attr.aria-label]="'process.new.parameter.label' | translate" type="hidden" value="true" name="boolean-value-{{index}}" id="boolean-value-{{index}}"/> 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 @@ -<input required #string="ngModel" type="text" class="form-control" name="date-value-{{index}}" id="date-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/> +<input [attr.aria-label]="'process.new.parameter.label' | translate" required #string="ngModel" type="text" class="form-control" name="date-value-{{index}}" id="date-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/> <div *ngIf="string.invalid && (string.dirty || string.touched)" - class="alert alert-danger validation-error"> + class="alert alert-danger validation-error mb-0"> <div *ngIf="string.errors.required"> {{'process.new.parameter.string.required' | translate}} </div> 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 @@ <label for="file-upload-{{index}}" class="d-flex align-items-center m-0"> - <span class="btn btn-light"> + <span class="btn btn-primary"> {{'process.new.parameter.file.upload-button' | translate}} </span> <span class="file-name ml-1">{{fileObject?.name}}</span> diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html b/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html index 246c62a0f61..bf60f9f0249 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html +++ b/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.html @@ -1,6 +1,6 @@ -<input required #string="ngModel" type="text" name="string-value-{{index}}" class="form-control" id="string-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/> +<input [attr.aria-label]="'process.new.parameter.label' | translate" required #string="ngModel" type="text" name="string-value-{{index}}" class="form-control" id="string-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/> <div *ngIf="string.invalid && (string.dirty || string.touched)" - class="alert alert-danger validation-error"> + class="alert alert-danger validation-error mb-0"> <div *ngIf="string.errors.required"> {{'process.new.parameter.string.required' | translate}} </div> diff --git a/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.scss b/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.scss index e69de29bb2d..8c6325f95a1 100644 --- a/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.scss +++ b/src/app/process-page/form/process-parameters/parameter-value-input/string-value-input/string-value-input.component.scss @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + gap: calc(var(--bs-spacer) / 2); +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index f6630d594db..133d63feb50 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3136,6 +3136,14 @@ "process.new.select-parameters": "Parameters", + "process.new.select-parameter": "Select parameter", + + "process.new.add-parameter": "Add a parameter...", + + "process.new.delete-parameter": "Delete parameter", + + "process.new.parameter.label": "Parameter value", + "process.new.cancel": "Cancel", "process.new.submit": "Save", From 120835cfcde75162e26ba7c52574327513e725d3 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 28 Nov 2023 00:36:16 +0100 Subject: [PATCH 234/282] Fix Process detail accessibility issues - Made Process Output keyboard accessible --- .../process-detail-field/process-detail-field.component.spec.ts | 2 +- src/app/process-page/detail/process-detail.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/process-page/detail/process-detail-field/process-detail-field.component.spec.ts b/src/app/process-page/detail/process-detail-field/process-detail-field.component.spec.ts index 57b596b8b60..ba0c946bfdf 100644 --- a/src/app/process-page/detail/process-detail-field/process-detail-field.component.spec.ts +++ b/src/app/process-page/detail/process-detail-field/process-detail-field.component.spec.ts @@ -32,7 +32,7 @@ describe('ProcessDetailFieldComponent', () => { }); it('should display the given title', () => { - const header = fixture.debugElement.query(By.css('h4')).nativeElement; + const header = fixture.debugElement.query(By.css('h2')).nativeElement; expect(header.textContent).toContain(title); }); }); diff --git a/src/app/process-page/detail/process-detail.component.html b/src/app/process-page/detail/process-detail.component.html index 5f905cbfff3..c52ef3827d8 100644 --- a/src/app/process-page/detail/process-detail.component.html +++ b/src/app/process-page/detail/process-detail.component.html @@ -53,7 +53,7 @@ <h2 class="flex-grow-1"> </button> <ds-themed-loading *ngIf="retrievingOutputLogs$ | async" class="ds-themed-loading" message="{{ 'process.detail.logs.loading' | translate }}"></ds-themed-loading> - <pre class="font-weight-bold text-secondary bg-light p-3" + <pre class="font-weight-bold text-secondary bg-light p-3" tabindex="0" *ngIf="showOutputLogs && (outputLogs$ | async)?.length > 0">{{ (outputLogs$ | async) }}</pre> <p id="no-output-logs-message" *ngIf="(!(retrievingOutputLogs$ | async) && showOutputLogs) && !(outputLogs$ | async) || (outputLogs$ | async)?.length == 0 || !process._links.output"> From 57cc34cdd1ee23c36f87d4ef7a621482ee16a049 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Tue, 28 Nov 2023 01:03:17 +0100 Subject: [PATCH 235/282] Fix Bitstream format accessibility issues - Added missing aria-labels to input checkboxes - Fixed minor css alignment --- .../add-bitstream-format/add-bitstream-format.component.html | 4 ++-- .../bitstream-formats/bitstream-formats.component.html | 5 +++-- .../edit-bitstream-format.component.html | 4 ++-- src/assets/i18n/en.json5 | 2 ++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html b/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html index 2b65b369b29..24c97051c55 100644 --- a/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html +++ b/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html @@ -2,10 +2,10 @@ <div class="row"> <div class="col-12 mb-4"> <h2 id="sub-header" - class="border-bottom mb-2">{{ 'admin.registries.bitstream-formats.create.new' | translate }}</h2> + class="border-bottom pb-2">{{ 'admin.registries.bitstream-formats.create.new' | translate }}</h2> <ds-bitstream-format-form (updatedFormat)="createBitstreamFormat($event)"></ds-bitstream-format-form> </div> </div> -</div> \ No newline at end of file +</div> 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 @@ <div class="bitstream-formats row"> <div class="col-12"> - <h2 id="header" class="border-bottom pb-2 ">{{'admin.registries.bitstream-formats.head' | translate}}</h2> + <h2 id="header" class="border-bottom pb-2">{{'admin.registries.bitstream-formats.head' | translate}}</h2> <p id="description">{{'admin.registries.bitstream-formats.description' | translate}}</p> <p id="create-new" class="mb-2"><a [routerLink]="'add'" class="btn btn-success">{{'admin.registries.bitstream-formats.create.new' | translate}}</a></p> @@ -19,7 +19,7 @@ <h2 id="header" class="border-bottom pb-2 ">{{'admin.registries.bitstream-format <table id="formats" class="table table-striped table-hover"> <thead> <tr> - <th scope="col"></th> + <th scope="col" [attr.aria-label]="'admin.registries.bitstream-formats.select' | translate"></th> <th scope="col">{{'admin.registries.bitstream-formats.table.id' | translate}}</th> <th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th> <th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th> @@ -31,6 +31,7 @@ <h2 id="header" class="border-bottom pb-2 ">{{'admin.registries.bitstream-format <td> <label class="mb-0"> <input type="checkbox" + [attr.aria-label]="'admin.registries.bitstream-formats.select' | translate" [checked]="isSelected(bitstreamFormat) | async" (change)="selectBitStreamFormat(bitstreamFormat, $event)" > diff --git a/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html b/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html index f57ec9cd382..43bfbd0de01 100644 --- a/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html +++ b/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html @@ -2,10 +2,10 @@ <div class="row"> <div class="col-12 mb-4"> <h2 id="sub-header" - class="border-bottom mb-2">{{'admin.registries.bitstream-formats.edit.head' | translate:{format: (bitstreamFormatRD$ | async)?.payload.shortDescription} }}</h2> + class="border-bottom pb-2">{{'admin.registries.bitstream-formats.edit.head' | translate:{format: (bitstreamFormatRD$ | async)?.payload.shortDescription} }}</h2> <ds-bitstream-format-form [bitstreamFormat]="(bitstreamFormatRD$ | async)?.payload" (updatedFormat)="updateFormat($event)"></ds-bitstream-format-form> </div> </div> -</div> \ No newline at end of file +</div> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 133d63feb50..dbf32bb7074 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -142,6 +142,8 @@ "admin.registries.bitstream-formats.title": "Bitstream Format Registry", + "admin.registries.bitstream-formats.select": "Select bitstream format", + "admin.registries.metadata.breadcrumbs": "Metadata registry", "admin.registries.metadata.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.", From 09bf8af03cbb9fccba459bc9bcb8a7b70716f3c5 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 05:15:04 +0100 Subject: [PATCH 236/282] Fix resource policy accessibility issues --- .../entry/resource-policy-entry.component.html | 4 +++- .../resource-policies/resource-policies.component.html | 6 ++++-- src/assets/i18n/en.json5 | 8 ++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/app/shared/resource-policies/entry/resource-policy-entry.component.html b/src/app/shared/resource-policies/entry/resource-policy-entry.component.html index 5a9494fe00b..a14dde366e6 100644 --- a/src/app/shared/resource-policies/entry/resource-policy-entry.component.html +++ b/src/app/shared/resource-policies/entry/resource-policy-entry.component.html @@ -5,7 +5,9 @@ [id]="entry.id" [ngModel]="entry.checked" (ngModelChange)="this.toggleCheckbox.emit($event);"> - <label class="custom-control-label" [for]="entry.id"></label> + <label class="custom-control-label" [for]="entry.id" + [attr.aria-label]="(entry.checked ? 'resource-policies.table.headers.deselect' : 'resource-policies.table.headers.select') | translate"> + </label> </div> </td> <th scope="row"> 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 @@ <tr *ngIf="(getResourcePolicies() | async)?.length > 0" class="text-center"> <th> <div class="custom-control custom-checkbox"> - <input type="checkbox" + <input #selectAllBtn type="checkbox" class="custom-control-input" [id]="'selectAll_' + resourceUUID" (change)="selectAllCheckbox($event)"> - <label class="custom-control-label" [for]="'selectAll_' + resourceUUID"></label> + <label class="custom-control-label" [for]="'selectAll_' + resourceUUID" + [attr.aria-label]="(selectAllBtn.checked ? 'resource-policies.table.headers.deselect-all' : 'resource-policies.table.headers.select-all') | translate"> + </label> </div> </th> <th>{{'resource-policies.table.headers.id' | translate}}</th> 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 <alexandre@atmire.com> Date: Sun, 3 Dec 2023 15:15:52 +0100 Subject: [PATCH 237/282] 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 @@ <h2>{{'collection.edit.item-mapper.head' | translate}}</h2> <p>{{'collection.edit.item-mapper.description' | translate}}</p> <ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> - <li [ngbNavItem]="'browseTab'"> + <li [ngbNavItem]="'browseTab'" role="presentation"> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.browse' | translate}}</a> <ng-template ngbNavContent> <div class="mt-2"> @@ -23,7 +23,7 @@ <h2>{{'collection.edit.item-mapper.head' | translate}}</h2> </div> </ng-template> </li> - <li [ngbNavItem]="'mapTab'"> + <li [ngbNavItem]="'mapTab'" role="presentation"> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.map' | translate}}</a> <ng-template ngbNavContent> <div class="row mt-2"> diff --git a/src/app/shared/object-select/item-select/item-select.component.html b/src/app/shared/object-select/item-select/item-select.component.html index 7f8ff943a37..8cdc8ffb2d3 100644 --- a/src/app/shared/object-select/item-select/item-select.component.html +++ b/src/app/shared/object-select/item-select/item-select.component.html @@ -11,7 +11,7 @@ <table id="item-select" class="table table-striped table-hover"> <thead> <tr> - <th></th> + <th aria-hidden="true"></th> <th *ngIf="!hideCollection" scope="col">{{'item.select.table.collection' | translate}}</th> <th scope="col">{{'item.select.table.author' | translate}}</th> <th scope="col">{{'item.select.table.title' | translate}}</th> @@ -19,7 +19,7 @@ </thead> <tbody> <tr *ngFor="let item of itemsRD?.payload?.page"> - <td><input [disabled]="!(canSelect(item) | async)" class="item-checkbox" [ngModel]="getSelected(item.id) | async" (change)="switch(item.id)" type="checkbox" name="{{item.id}}"></td> + <td><input #selectItemBtn [attr.aria-label]="(selectItemBtn.checked ? 'item.select.table.deselect' : 'item.select.table.select') | translate" [disabled]="!(canSelect(item) | async)" class="item-checkbox" [ngModel]="getSelected(item.id) | async" (change)="switch(item.id)" type="checkbox" name="{{item.id}}"></td> <td *ngIf="!hideCollection"> <span *ngVar="(item.owningCollection | async)?.payload as collection"> <a *ngIf="collection" [routerLink]="['/collections', collection?.id]"> 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 <alexandre@atmire.com> Date: Sun, 3 Dec 2023 15:42:13 +0100 Subject: [PATCH 238/282] 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 @@ <h2 class="border-bottom">{{'item.edit.head' | translate}}</h2> <div class="pt-2"> <ul class="nav nav-tabs justify-content-start" role="tablist"> - <li *ngFor="let page of pages" class="nav-item" [attr.aria-selected]="page.page === currentPage" role="tab"> + <li *ngFor="let page of pages" class="nav-item" role="presentation"> <a *ngIf="(page.enabled | async)" + [attr.aria-selected]="page.page === currentPage" class="nav-link" [ngClass]="{'active' : page.page === currentPage}" - [routerLink]="['./' + page.page]"> + [routerLink]="['./' + page.page]" + role="tab"> {{'item.edit.tabs.' + page.page + '.head' | translate}} </a> <span [ngbTooltip]="'item.edit.tabs.disabled.tooltip' | translate"> diff --git a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html index c522b8a9c53..1d025f65141 100644 --- a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html +++ b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html @@ -6,7 +6,7 @@ <h2>{{'item.edit.item-mapper.head' | translate}}</h2> <p>{{'item.edit.item-mapper.description' | translate}}</p> <ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> - <li [ngbNavItem]="'browseTab'"> + <li [ngbNavItem]="'browseTab'" role="presentation"> <a ngbNavLink>{{'item.edit.item-mapper.tabs.browse' | translate}}</a> <ng-template ngbNavContent> <div class="mt-2"> @@ -22,7 +22,7 @@ <h2>{{'item.edit.item-mapper.head' | translate}}</h2> </div> </ng-template> </li> - <li [ngbNavItem]="'mapTab'"> + <li [ngbNavItem]="'mapTab'" role="presentation"> <a ngbNavLink>{{'item.edit.item-mapper.tabs.map' | translate}}</a> <ng-template ngbNavContent> <div class="row mt-2"> diff --git a/src/app/shared/object-select/collection-select/collection-select.component.html b/src/app/shared/object-select/collection-select/collection-select.component.html index 9b87f69c040..7d4dadb2e32 100644 --- a/src/app/shared/object-select/collection-select/collection-select.component.html +++ b/src/app/shared/object-select/collection-select/collection-select.component.html @@ -11,13 +11,13 @@ <table id="collection-select" class="table table-striped table-hover"> <thead> <tr> - <th></th> + <th aria-hidden="true"></th> <th scope="col">{{'collection.select.table.title' | translate}}</th> </tr> </thead> <tbody> <tr *ngFor="let collection of collectionsRD?.payload?.page"> - <td><input class="collection-checkbox" [ngModel]="getSelected(collection.id) | async" (change)="switch(collection.id)" type="checkbox" name="{{collection.id}}"></td> + <td><input #selectCollectionBtn [attr.aria-label]="(selectCollectionBtn.checked ? 'collection.select.table.deselect' : 'collection.select.table.select') | translate" class="collection-checkbox" [ngModel]="getSelected(collection.id) | async" (change)="switch(collection.id)" type="checkbox" name="{{collection.id}}"></td> <td><a [routerLink]="['/collections', collection.id]">{{ dsoNameService.getName(collection) }}</a></td> </tr> </tbody> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 3fa71678b86..b71bb6df145 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1092,6 +1092,10 @@ "collection.select.empty": "No collections to show", + "collection.select.table.select": "Select collection", + + "collection.select.table.deselect": "Deselect collection", + "collection.select.table.title": "Title", "collection.source.controls.head": "Harvest Controls", From 8ba17c991e76199fe03aed872ac9974309a7702f Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 16:37:08 +0100 Subject: [PATCH 239/282] Fixed item page accessibility issues --- .../bitstream-download-page.component.html | 2 +- .../dso-edit-metadata-value.component.html | 2 ++ .../bitstreams/upload/upload-bitstream.component.html | 2 +- .../file-section/full-file-section.component.html | 4 ++-- .../tabbed-related-entities-search.component.html | 2 +- .../item-page/versions/item-versions.component.html | 7 ++++--- .../file-download-link.component.html | 2 +- .../file-download-link.component.spec.ts | 4 ++++ .../dynamic-lookup-relation-modal.component.html | 6 +++--- .../form/resource-policy-form.component.html | 4 ++-- src/assets/i18n/en.json5 | 10 ++++++++++ 11 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html b/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html index af3afe98f87..1467ffb0cc8 100644 --- a/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html +++ b/src/app/bitstream-page/bitstream-download-page/bitstream-download-page.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h3>{{'bitstream.download.page' | translate:{ bitstream: dsoNameService.getName((bitstream$ | async)) } }}</h3> + <h1 class="h2">{{'bitstream.download.page' | translate:{ bitstream: dsoNameService.getName((bitstream$ | async)) } }}</h1> <div class="pt-3"> <button (click)="back()" class="btn btn-outline-secondary"> <i class="fas fa-arrow-left"></i> {{'bitstream.download.page.back' | translate}} diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index 525b42610b4..2701ee24ab3 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -4,6 +4,7 @@ <div class="flex-grow-1 ds-flex-cell ds-value-cell d-flex align-items-center" *ngVar="(mdRepresentation$ | async) as mdRepresentation" role="cell"> <div class="dont-break-out preserve-line-breaks" *ngIf="!mdValue.editing && !mdRepresentation">{{ mdValue.newValue.value }}</div> <textarea class="form-control" rows="5" *ngIf="mdValue.editing && !mdRepresentation" [(ngModel)]="mdValue.newValue.value" + [attr.aria-label]="(dsoType + '.edit.metadata.edit.value') | translate" [dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea> <div class="d-flex" *ngIf="mdRepresentation"> <a class="mr-2" target="_blank" [routerLink]="mdRepresentationItemRoute$ | async">{{ mdRepresentationName$ | async }}</a> @@ -13,6 +14,7 @@ <div class="ds-flex-cell ds-lang-cell" role="cell"> <div class="dont-break-out preserve-line-breaks" *ngIf="!mdValue.editing">{{ mdValue.newValue.language }}</div> <input class="form-control" type="text" *ngIf="mdValue.editing" [(ngModel)]="mdValue.newValue.language" + [attr.aria-label]="(dsoType + '.edit.metadata.edit.language') | translate" [dsDebounce]="300" (onDebounce)="confirm.emit(false)" /> </div> <div class="text-center ds-flex-cell ds-edit-cell" role="cell"> diff --git a/src/app/item-page/bitstreams/upload/upload-bitstream.component.html b/src/app/item-page/bitstreams/upload/upload-bitstream.component.html index 1732da1235f..530471135c0 100644 --- a/src/app/item-page/bitstreams/upload/upload-bitstream.component.html +++ b/src/app/item-page/bitstreams/upload/upload-bitstream.component.html @@ -2,7 +2,7 @@ <ng-container *ngIf="bundles"> <div class="row"> <div class="col-12 mb-2"> - <h2>{{'item.bitstreams.upload.title' | translate}}</h2> + <h1>{{'item.bitstreams.upload.title' | translate}}</h1> <ng-container *ngVar="(itemRD$ | async)?.payload as item"> <div *ngIf="item"> <span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span> diff --git a/src/app/item-page/full/field-components/file-section/full-file-section.component.html b/src/app/item-page/full/field-components/file-section/full-file-section.component.html index 8b8603011d5..77747540794 100644 --- a/src/app/item-page/full/field-components/file-section/full-file-section.component.html +++ b/src/app/item-page/full/field-components/file-section/full-file-section.component.html @@ -1,7 +1,7 @@ <ds-metadata-field-wrapper [label]="label | translate"> <div *ngVar="(originals$ | async)?.payload as originals"> <div *ngIf="hasValuesInBundle(originals)"> - <h5 class="simple-view-element-header">{{"item.page.filesection.original.bundle" | translate}}</h5> + <h3 class="h5 simple-view-element-header">{{"item.page.filesection.original.bundle" | translate}}</h3> <ds-pagination *ngIf="originals?.page?.length > 0" [hideGear]="true" [hidePagerWhenSinglePage]="true" @@ -44,7 +44,7 @@ <h5 class="simple-view-element-header">{{"item.page.filesection.original.bundle" </div> <div *ngVar="(licenses$ | async)?.payload as licenses"> <div *ngIf="hasValuesInBundle(licenses)"> - <h5 class="simple-view-element-header">{{"item.page.filesection.license.bundle" | translate}}</h5> + <h3 class="h5 simple-view-element-header">{{"item.page.filesection.license.bundle" | translate}}</h3> <ds-pagination *ngIf="licenses?.page?.length > 0" [hideGear]="true" [hidePagerWhenSinglePage]="true" diff --git a/src/app/item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.html b/src/app/item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.html index 223d4a6ed0c..1b6cc273df7 100644 --- a/src/app/item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.html +++ b/src/app/item-page/simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component.html @@ -1,6 +1,6 @@ <ng-container *ngIf="relationTypes.length > 1"> <ul ngbNav #tabs="ngbNav" [destroyOnHide]="true" [activeId]="activeTab$ | async" (navChange)="onTabChange($event)" class="nav-tabs"> - <li *ngFor="let relationType of relationTypes" [ngbNavItem]="relationType.filter"> + <li *ngFor="let relationType of relationTypes" [ngbNavItem]="relationType.filter" rel="presentation"> <a ngbNavLink>{{'item.page.relationships.' + relationType.label | translate}}</a> <ng-template ngbNavContent> <div class="mt-4"> diff --git a/src/app/item-page/versions/item-versions.component.html b/src/app/item-page/versions/item-versions.component.html index 176c1f0cde6..0722878f2e0 100644 --- a/src/app/item-page/versions/item-versions.component.html +++ b/src/app/item-page/versions/item-versions.component.html @@ -1,7 +1,7 @@ <div *ngVar="(versionsRD$ | async)?.payload as versions"> <div *ngVar="(versionRD$ | async)?.payload as itemVersion"> <div class="mb-2" *ngIf="versions?.page?.length > 0 || displayWhenEmpty"> - <h2 *ngIf="displayTitle">{{"item.version.history.head" | translate}}</h2> + <h2 *ngIf="displayTitle" class="h4">{{"item.version.history.head" | translate}}</h2> <ds-alert [type]="AlertTypeEnum.Info" *ngIf="itemVersion"> {{ "item.version.history.selected.alert" | translate : {version: itemVersion.version} }} </ds-alert> @@ -98,8 +98,9 @@ <h2 *ngIf="displayTitle">{{"item.version.history.head" | translate}}</h2> <ng-container *ngIf="isThisBeingEdited(version); then editSummary else showSummary"></ng-container> <ng-template #showSummary>{{version?.summary}}</ng-template> <ng-template #editSummary> - <input class="form-control" type="text" [(ngModel)]="versionBeingEditedSummary" - (keyup.enter)="onSummarySubmit()"/> + <input [attr.aria-label]="'item.version.history.table.action.editSummary' | translate" + [(ngModel)]="versionBeingEditedSummary" (keyup.enter)="onSummarySubmit()" + class="form-control" type="text"/> </ng-template> </div> diff --git a/src/app/shared/file-download-link/file-download-link.component.html b/src/app/shared/file-download-link/file-download-link.component.html index 8ebe622a5ba..7a5729cc2da 100644 --- a/src/app/shared/file-download-link/file-download-link.component.html +++ b/src/app/shared/file-download-link/file-download-link.component.html @@ -1,5 +1,5 @@ <a [routerLink]="(bitstreamPath$| async)?.routerLink" class="dont-break-out" [queryParams]="(bitstreamPath$| async)?.queryParams" [target]="isBlank ? '_blank': '_self'" [ngClass]="cssClasses"> - <span *ngIf="!(canDownload$ |async)" class="pr-1"><i class="fas fa-lock"></i></span> + <span *ngIf="!(canDownload$ |async)" [attr.aria-label]="'file-download-link.restricted' | translate" class="pr-1"><i class="fas fa-lock"></i></span> <ng-container *ngTemplateOutlet="content"></ng-container> </a> diff --git a/src/app/shared/file-download-link/file-download-link.component.spec.ts b/src/app/shared/file-download-link/file-download-link.component.spec.ts index 61e9ecb4aad..21e1cdae192 100644 --- a/src/app/shared/file-download-link/file-download-link.component.spec.ts +++ b/src/app/shared/file-download-link/file-download-link.component.spec.ts @@ -10,6 +10,7 @@ import { FeatureID } from '../../core/data/feature-authorization/feature-id'; import { Item } from '../../core/shared/item.model'; import { getItemModuleRoute } from '../../item-page/item-page-routing-paths'; import { RouterLinkDirectiveStub } from '../testing/router-link-directive.stub'; +import { TranslateModule } from '@ngx-translate/core'; describe('FileDownloadLinkComponent', () => { let component: FileDownloadLinkComponent; @@ -41,6 +42,9 @@ describe('FileDownloadLinkComponent', () => { function initTestbed() { TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot(), + ], declarations: [FileDownloadLinkComponent, RouterLinkDirectiveStub], providers: [ {provide: AuthorizationDataService, useValue: authorizationService}, 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 f7f07152067..6d249a9b1e5 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 @@ -9,7 +9,7 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat <ds-themed-loading *ngIf="!item || !collection"></ds-themed-loading> <ng-container *ngIf="item && collection"> <ul ngbNav #nav="ngbNav" class="nav-tabs"> - <li ngbNavItem> + <li ngbNavItem role="presentation"> <a ngbNavLink>{{'submission.sections.describe.relationship-lookup.search-tab.tab-title.' + relationshipOptions.relationshipType | translate : { count: (totalInternal$ | async)} }}</a> <ng-template ngbNavContent> <ds-themed-dynamic-lookup-relation-search-tab @@ -31,7 +31,7 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat </ds-themed-dynamic-lookup-relation-search-tab> </ng-template> </li> - <li ngbNavItem *ngFor="let source of (externalSourcesRD$ | async); let idx = index"> + <li ngbNavItem *ngFor="let source of (externalSourcesRD$ | async); let idx = index" role="presentation"> <a ngbNavLink>{{'submission.sections.describe.relationship-lookup.search-tab.tab-title.' + source.id | translate : { count: (totalExternal$ | async)[idx] } }}</a> <ng-template ngbNavContent> <ds-themed-dynamic-lookup-relation-external-source-tab @@ -49,7 +49,7 @@ <h4 class="modal-title" id="modal-title">{{ ('submission.sections.describe.relat </ds-themed-dynamic-lookup-relation-external-source-tab> </ng-template> </li> - <li ngbNavItem *ngIf="!isEditRelationship"> + <li ngbNavItem *ngIf="!isEditRelationship" role="presentation"> <a ngbNavLink>{{'submission.sections.describe.relationship-lookup.selection-tab.tab-title' | translate : { count: (selection$ | async)?.length } }}</a> <ng-template ngbNavContent> <ds-dynamic-lookup-relation-selection-tab diff --git a/src/app/shared/resource-policies/form/resource-policy-form.component.html b/src/app/shared/resource-policies/form/resource-policy-form.component.html index 66c1fc400e9..283ff4d753f 100644 --- a/src/app/shared/resource-policies/form/resource-policy-form.component.html +++ b/src/app/shared/resource-policies/form/resource-policy-form.component.html @@ -9,13 +9,13 @@ <label for="ResourcePolicyObject">{{'resource-policies.form.eperson-group-list.label' | translate}}</label> <input id="ResourcePolicyObject" class="form-control mb-3" type="text" [value]="resourcePolicyTargetName$ | async"> <ul ngbNav #nav="ngbNav" class="nav-pills" [(activeId)]="navActiveId" (navChange)="onNavChange($event)"> - <li [ngbNavItem]="'eperson'"> + <li [ngbNavItem]="'eperson'" role="presentation"> <a ngbNavLink>{{'resource-policies.form.eperson-group-list.tab.eperson' | translate}}</a> <ng-template ngbNavContent> <ds-eperson-group-list (select)="updateObjectSelected($event, true)"></ds-eperson-group-list> </ng-template> </li> - <li [ngbNavItem]="'group'"> + <li [ngbNavItem]="'group'" role="presentation"> <a ngbNavLink>{{'resource-policies.form.eperson-group-list.tab.group' | translate}}</a> <ng-template ngbNavContent> <ds-eperson-group-list [isListOfEPerson]="false" diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index b71bb6df145..250465fad95 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1622,6 +1622,8 @@ "feed.description": "Syndication feed", + "file-download-link.restricted": "Restricted bitstream", + "file-section.error.header": "Error obtaining files for this item", "footer.copyright": "copyright © 2002-{{ year }}", @@ -2096,6 +2098,10 @@ "item.edit.metadata.discard-button": "Discard", + "item.edit.metadata.edit.language": "Edit language", + + "item.edit.metadata.edit.value": "Edit value", + "item.edit.metadata.edit.buttons.confirm": "Confirm", "item.edit.metadata.edit.buttons.drag": "Drag to reorder", @@ -2616,6 +2622,10 @@ "itemtemplate.edit.metadata.discard-button": "Discard", + "itemtemplate.edit.metadata.edit.language": "Edit language", + + "itemtemplate.edit.metadata.edit.value": "Edit value", + "itemtemplate.edit.metadata.edit.buttons.confirm": "Confirm", "itemtemplate.edit.metadata.edit.buttons.drag": "Drag to reorder", From 30fe424cc5e079759398ac4ec8706acde476b2aa Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 17:42:19 +0100 Subject: [PATCH 240/282] Fixed browse by vocabulary treeview accessibility issues --- .../vocabulary-treeview.component.html | 22 +++++++++---------- .../vocabulary-treeview.component.scss | 4 ---- .../vocabulary-treeview.component.ts | 3 +++ src/assets/i18n/en.json5 | 2 ++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index db3dc31948f..432098b4637 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -1,8 +1,9 @@ -<ds-alert [content]="'vocabulary-treeview.info' | translate" [type]="'alert-info'"></ds-alert> -<div class="treeview-header row"> +<ds-alert [content]="'vocabulary-treeview.info' | translate" [type]="AlertType.Info"></ds-alert> +<div class="treeview-header row mb-1"> <div class="col-12"> <div class="input-group"> - <input type="text" class="form-control" [(ngModel)]="searchText" (keyup.enter)="search()"> + <input type="text" class="form-control" [(ngModel)]="searchText" (keyup.enter)="search()" + [placeholder]="'vocabulary-treeview.search.form.search-placeholder' | translate"> <div class="input-group-append" id="button-addon4"> <button class="btn btn-outline-primary" type="button" (click)="search()" [disabled]="!isSearchEnabled()"> {{'vocabulary-treeview.search.form.search' | translate}} @@ -19,15 +20,15 @@ </div> <div class="treeview-container"> <ds-themed-loading *ngIf="loading | async" [showMessage]="false"></ds-themed-loading> - <h4 *ngIf="!(loading | async) && dataSource.data.length === 0" class="text-center text-muted mt-4" > + <h2 *ngIf="!(loading | async) && dataSource.data.length === 0" class="h4 text-center text-muted mt-4" > <span>{{'vocabulary-treeview.search.no-result' | translate}}</span> - </h4> + </h2> <cdk-tree [dataSource]="dataSource" [treeControl]="treeControl"> <!-- Leaf node --> <cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="d-flex"> - <button type="button" class="btn btn-default" cdkTreeNodeToggle> - <span class="fas fa-fw fa-angle-right invisible" aria-hidden="true"></span> - </button> + <span aria-hidden="true" type="button" class="btn btn-default px-2 mr-1" cdkTreeNodeToggle> + <i class="fas fa-fw fa-angle-right invisible"></i> + </span> <label *ngIf="multiSelect" class="d-flex align-items-center m-0 p-0 form-check" [class.text-success]="node.isSelected" [ngbTooltip]="node.item?.otherInformation?.note" @@ -55,11 +56,10 @@ <h4 *ngIf="!(loading | async) && dataSource.data.length === 0" class="text-cente <!-- expandable node --> <cdk-tree-node *cdkTreeNodeDef="let node; when: hasChildren" cdkTreeNodePadding class="d-flex"> - <button type="button" class="btn btn-default" cdkTreeNodeToggle + <button type="button" class="btn btn-default px-2 mr-1" cdkTreeNodeToggle [attr.aria-label]="'toggle ' + node.name" (click)="loadChildren(node)"> - <span class="fas fa-fw {{treeControl.isExpanded(node) ? 'fa-angle-down' : 'fa-angle-right'}}" - aria-hidden="true"></span> + <i class="fas fa-fw {{treeControl.isExpanded(node) ? 'fa-angle-down' : 'fa-angle-right'}}"></i> </button> <label *ngIf="multiSelect" class="d-flex align-items-center m-0 p-0 form-check" diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss index 3f0cea10d25..3d32acac5bb 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.scss @@ -2,10 +2,6 @@ text-align:left; } -cdk-tree .btn:focus { - box-shadow: none !important; -} - label { cursor: pointer; } diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts index d5a5dee1f5e..b1edda461e5 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.ts @@ -17,6 +17,7 @@ import { VocabularyTreeFlatDataSource } from './vocabulary-tree-flat-data-source import { CoreState } from '../../../core/core-state.model'; import { VocabularyService } from '../../../core/submission/vocabularies/vocabulary.service'; import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; +import { AlertType } from '../../alert/alert-type'; /** * Component that shows a hierarchical vocabulary in a tree view @@ -105,6 +106,8 @@ export class VocabularyTreeviewComponent implements OnDestroy, OnInit, OnChanges */ private subs: Subscription[] = []; + readonly AlertType = AlertType; + /** * Initialize instance variables * diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 250465fad95..432a0b33b40 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -4790,6 +4790,8 @@ "vocabulary-treeview.search.form.search": "Search", + "vocabulary-treeview.search.form.search-placeholder": "Filter results by typing the first few letters", + "vocabulary-treeview.search.no-result": "There were no items to show", "vocabulary-treeview.tree.description.nsi": "The Norwegian Science Index", From 5566c99625d86af3222cfd3f58614bbcc3c8b23b Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 17:43:16 +0100 Subject: [PATCH 241/282] Fixed accessibility issues about header ordering --- .../epeople-registry.component.html | 8 ++++---- .../eperson-form/eperson-form.component.html | 6 +++--- .../group-form/group-form.component.html | 11 +++++----- .../members-list/members-list.component.html | 8 ++++---- .../groups-registry.component.html | 4 ++-- .../admin-curation-tasks.component.html | 2 +- .../metadata-import-page.component.html | 2 +- .../add-bitstream-format.component.html | 4 ++-- .../bitstream-formats.component.html | 2 +- .../edit-bitstream-format.component.html | 4 ++-- .../edit-bitstream-page.component.html | 2 +- .../browse-by-taxonomy-page.component.html | 1 + .../delete-collection-page.component.html | 2 +- .../collection-curate.component.html | 2 +- .../collection-source.component.html | 2 +- .../edit-item-template-page.component.html | 2 +- .../delete-community-page.component.html | 2 +- .../community-curate.component.html | 2 +- .../feedback-form.component.html | 2 +- ...tstream-request-a-copy-page.component.html | 2 +- .../edit-item-page.component.html | 2 +- .../item-curate/item-curate.component.html | 2 +- .../item-delete/item-delete.component.html | 2 +- .../item-delete/item-delete.component.spec.ts | 2 +- .../item-move/item-move.component.html | 2 +- .../item-private.component.spec.ts | 2 +- .../item-public/item-public.component.spec.ts | 2 +- .../item-reinstate.component.spec.ts | 2 +- .../edit-relationship-list.component.html | 4 ++-- .../item-withdraw.component.spec.ts | 2 +- ...abstract-simple-item-action.component.html | 2 +- ...tract-simple-item-action.component.spec.ts | 2 +- .../orcid-auth/orcid-auth.component.html | 2 +- .../orcid-page/orcid-page.component.html | 20 +++++++++---------- .../process-detail-field.component.html | 2 +- .../detail/process-detail.component.html | 4 ++-- .../form/process-form.component.html | 6 +++--- .../script-help/script-help.component.html | 2 +- .../overview/process-overview.component.html | 2 +- .../profile-page/profile-page.component.html | 6 +++--- .../register-email-form.component.html | 2 +- ...cess-control-form-container.component.html | 12 +++++------ .../shared/browse-by/browse-by.component.html | 2 +- .../comcol-role/comcol-role.component.html | 4 ++-- .../edit-comcol-page.component.html | 4 ++-- .../comcol-page-handle.component.html | 8 ++++---- .../comcol-page-handle.component.scss | 5 ----- .../edit/resource-policy-edit.component.html | 2 +- ...search-switch-configuration.component.html | 2 +- .../statistics-page.component.html | 4 ++-- .../statistics-table.component.html | 4 ++-- .../submission-import-external.component.html | 10 +++++----- .../submission-import-external.component.ts | 3 +++ .../subscriptions-page.component.html | 4 ++-- .../subscriptions-page.component.ts | 3 +++ .../system-wide-alert-form.component.html | 2 +- src/assets/i18n/en.json5 | 2 ++ src/styles/_bootstrap_variables.scss | 8 ++++++++ 58 files changed, 116 insertions(+), 105 deletions(-) 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 4979f858193..bf7b9a2060d 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -2,7 +2,7 @@ <div class="epeople-registry row"> <div class="col-12"> <div class="d-flex justify-content-between border-bottom mb-3"> - <h2 id="header" class="pb-2">{{labelPrefix + 'head' | translate}}</h2> + <h1 id="header" class="pb-2">{{labelPrefix + 'head' | translate}}</h1> <div> <button class="mr-auto btn btn-success addEPerson-button" @@ -13,9 +13,9 @@ <h2 id="header" class="pb-2">{{labelPrefix + 'head' | translate}}</h2> </div> </div> - <h3 id="search" class="border-bottom pb-2">{{labelPrefix + 'search.head' | translate}} - - </h3> + <h2 id="search" class="border-bottom pb-2"> + {{labelPrefix + 'search.head' | translate}} + </h2> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> <div> <select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope"> 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 6a7b8b931ff..747d30bb897 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 @@ -5,11 +5,11 @@ <div *ngIf="epersonService.getActiveEPerson() | async; then editHeader; else createHeader"></div> <ng-template #createHeader> - <h2 class="border-bottom pb-2">{{messagePrefix + '.create' | translate}}</h2> + <h1 class="border-bottom pb-2">{{messagePrefix + '.create' | translate}}</h1> </ng-template> <ng-template #editHeader> - <h2 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h2> + <h1 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h1> </ng-template> <ds-form [formId]="formId" @@ -45,7 +45,7 @@ <h2 class="border-bottom pb-2">{{messagePrefix + '.edit' | translate}}</h2> <ds-themed-loading [showMessage]="false" *ngIf="!formGroup"></ds-themed-loading> <div *ngIf="epersonService.getActiveEPerson() | async"> - <h5>{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}</h5> + <h2>{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}</h2> <ds-themed-loading [showMessage]="false" *ngIf="!(groups | async)"></ds-themed-loading> 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 f31de0db1b5..491762a4370 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 @@ -5,11 +5,11 @@ <div *ngIf="groupDataService.getActiveGroup() | async; then editHeader; else createHeader"></div> <ng-template #createHeader> - <h2 class="border-bottom pb-2">{{messagePrefix + '.head.create' | translate}}</h2> + <h1 class="border-bottom pb-2">{{messagePrefix + '.head.create' | translate}}</h1> </ng-template> <ng-template #editHeader> - <h2 class="border-bottom pb-2"> + <h1 class="border-bottom pb-2"> <span *dsContextHelp="{ content: 'admin.access-control.groups.form.tooltip.editGroupPage', @@ -20,7 +20,7 @@ <h2 class="border-bottom pb-2"> > {{messagePrefix + '.head.edit' | translate}} </span> - </h2> + </h1> </ng-template> <ds-alert *ngIf="groupBeingEdited?.permanent" [type]="AlertTypeEnum.Warning" @@ -39,9 +39,8 @@ <h2 class="border-bottom pb-2"> <button (click)="onCancel()" type="button" class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> </div> - <div after *ngIf="(canEdit$ | async) && !groupBeingEdited.permanent" class="btn-group"> - <button class="btn btn-danger delete-button" [disabled]="!(canEdit$ | async) || groupBeingEdited.permanent" - (click)="delete()" type="button"> + <div after *ngIf="(canEdit$ | async) && !groupBeingEdited?.permanent" class="btn-group"> + <button (click)="delete()" class="btn btn-danger delete-button" type="button"> <i class="fa fa-trash"></i> {{ messagePrefix + '.actions.delete' | translate}} </button> </div> 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 c0c77f44ebc..7f01e1b720e 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 @@ -1,7 +1,7 @@ <ng-container> - <h3 class="border-bottom pb-2">{{messagePrefix + '.head' | translate}}</h3> + <h2 class="border-bottom pb-2">{{messagePrefix + '.head' | translate}}</h2> - <h4>{{messagePrefix + '.headMembers' | translate}}</h4> + <h3>{{messagePrefix + '.headMembers' | translate}}</h3> <ds-pagination *ngIf="(ePeopleMembersOfGroup | async)?.totalElements > 0" [paginationOptions]="config" @@ -55,7 +55,7 @@ <h4>{{messagePrefix + '.headMembers' | translate}}</h4> {{messagePrefix + '.no-members-yet' | translate}} </div> - <h4 id="search" class="border-bottom pb-2"> + <h3 id="search" class="border-bottom pb-2"> <span *dsContextHelp="{ content: 'admin.access-control.groups.form.tooltip.editGroup.addEpeople', @@ -66,7 +66,7 @@ <h4 id="search" class="border-bottom pb-2"> > {{messagePrefix + '.search.head' | translate}} </span> - </h4> + </h3> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> <div class="flex-grow-1 mr-3"> diff --git a/src/app/access-control/group-registry/groups-registry.component.html b/src/app/access-control/group-registry/groups-registry.component.html index 27cec262c44..bd39cbe94fb 100644 --- a/src/app/access-control/group-registry/groups-registry.component.html +++ b/src/app/access-control/group-registry/groups-registry.component.html @@ -2,7 +2,7 @@ <div class="groups-registry row"> <div class="col-12"> <div class="d-flex justify-content-between border-bottom mb-3"> - <h2 id="header" class="pb-2">{{messagePrefix + 'head' | translate}}</h2> + <h1 id="header" class="pb-2">{{messagePrefix + 'head' | translate}}</h1> <div> <button class="mr-auto btn btn-success" [routerLink]="'create'"> @@ -12,7 +12,7 @@ <h2 id="header" class="pb-2">{{messagePrefix + 'head' | translate}}</h2> </div> </div> - <h3 id="search" class="border-bottom pb-2">{{messagePrefix + 'search.head' | translate}}</h3> + <h2 id="search" class="border-bottom pb-2">{{messagePrefix + 'search.head' | translate}}</h2> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> <div class="flex-grow-1 mr-3"> <div class="form-group input-group"> diff --git a/src/app/admin/admin-curation-tasks/admin-curation-tasks.component.html b/src/app/admin/admin-curation-tasks/admin-curation-tasks.component.html index a702a7e6b09..ba3a6f45d7b 100644 --- a/src/app/admin/admin-curation-tasks/admin-curation-tasks.component.html +++ b/src/app/admin/admin-curation-tasks/admin-curation-tasks.component.html @@ -1,4 +1,4 @@ <div class="container"> - <h2>{{'admin.curation-tasks.header' |translate }}</h2> + <h1>{{'admin.curation-tasks.header' |translate }}</h1> <ds-curation-form></ds-curation-form> </div> diff --git a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html index 24901cc11d3..73e69737ca8 100644 --- a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html +++ b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h2 id="header">{{'admin.metadata-import.page.header' | translate}}</h2> + <h1 id="header">{{'admin.metadata-import.page.header' | translate}}</h1> <p>{{'admin.metadata-import.page.help' | translate}}</p> <div class="form-group"> <div class="form-check"> diff --git a/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html b/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html index 24c97051c55..d1be68633f3 100644 --- a/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html +++ b/src/app/admin/admin-registries/bitstream-formats/add-bitstream-format/add-bitstream-format.component.html @@ -1,8 +1,8 @@ <div class="container"> <div class="row"> <div class="col-12 mb-4"> - <h2 id="sub-header" - class="border-bottom pb-2">{{ 'admin.registries.bitstream-formats.create.new' | translate }}</h2> + <h1 id="sub-header" + class="border-bottom pb-2">{{ 'admin.registries.bitstream-formats.create.new' | translate }}</h1> <ds-bitstream-format-form (updatedFormat)="createBitstreamFormat($event)"></ds-bitstream-format-form> 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 45d8ed5d11c..37323d41d0e 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 @@ <div class="bitstream-formats row"> <div class="col-12"> - <h2 id="header" class="border-bottom pb-2">{{'admin.registries.bitstream-formats.head' | translate}}</h2> + <h1 id="header" class="border-bottom pb-2">{{'admin.registries.bitstream-formats.head' | translate}}</h1> <p id="description">{{'admin.registries.bitstream-formats.description' | translate}}</p> <p id="create-new" class="mb-2"><a [routerLink]="'add'" class="btn btn-success">{{'admin.registries.bitstream-formats.create.new' | translate}}</a></p> diff --git a/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html b/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html index 43bfbd0de01..efcced2a87c 100644 --- a/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html +++ b/src/app/admin/admin-registries/bitstream-formats/edit-bitstream-format/edit-bitstream-format.component.html @@ -1,8 +1,8 @@ <div class="container"> <div class="row"> <div class="col-12 mb-4"> - <h2 id="sub-header" - class="border-bottom pb-2">{{'admin.registries.bitstream-formats.edit.head' | translate:{format: (bitstreamFormatRD$ | async)?.payload.shortDescription} }}</h2> + <h1 id="sub-header" + class="border-bottom pb-2">{{'admin.registries.bitstream-formats.edit.head' | translate:{format: (bitstreamFormatRD$ | async)?.payload.shortDescription} }}</h1> <ds-bitstream-format-form [bitstreamFormat]="(bitstreamFormatRD$ | async)?.payload" (updatedFormat)="updateFormat($event)"></ds-bitstream-format-form> diff --git a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html index 11aa3bfe75e..b306eb27214 100644 --- a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html +++ b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html @@ -8,7 +8,7 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h3>{{dsoNameService.getName(bitstreamRD?.payload)}} <span class="text-muted">({{bitstreamRD?.payload?.sizeBytes | dsFileSize}})</span></h3> + <h1 class="h2">{{dsoNameService.getName(bitstreamRD?.payload)}} <span class="text-muted">({{bitstreamRD?.payload?.sizeBytes | dsFileSize}})</span></h1> </div> </div> </div> diff --git a/src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.html b/src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.html index 0ae3da6847b..c24ca934032 100644 --- a/src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.html +++ b/src/app/browse-by/browse-by-taxonomy-page/browse-by-taxonomy-page.component.html @@ -1,4 +1,5 @@ <div class="container"> + <h1>{{ ('browse.taxonomy_' + vocabularyName + '.title') | translate }}</h1> <div class="mb-3"> <ds-vocabulary-treeview [vocabularyOptions]=vocabularyOptions [multiSelect]="true" diff --git a/src/app/collection-page/delete-collection-page/delete-collection-page.component.html b/src/app/collection-page/delete-collection-page/delete-collection-page.component.html index ba54bbabd59..d878d225899 100644 --- a/src/app/collection-page/delete-collection-page/delete-collection-page.component.html +++ b/src/app/collection-page/delete-collection-page/delete-collection-page.component.html @@ -2,7 +2,7 @@ <div class="row"> <ng-container *ngVar="(dsoRD$ | async)?.payload as dso"> <div class="col-12 pb-4"> - <h2 id="header" class="border-bottom pb-2">{{ 'collection.delete.head' | translate}}</h2> + <h1 id="header" class="border-bottom pb-2">{{ 'collection.delete.head' | translate}}</h1> <p class="pb-2">{{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p> <div class="form-group row"> <div class="col text-right space-children-mr"> diff --git a/src/app/collection-page/edit-collection-page/collection-curate/collection-curate.component.html b/src/app/collection-page/edit-collection-page/collection-curate/collection-curate.component.html index 38c9d22f4ed..4fbe60d6b17 100644 --- a/src/app/collection-page/edit-collection-page/collection-curate/collection-curate.component.html +++ b/src/app/collection-page/edit-collection-page/collection-curate/collection-curate.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h3>{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}</h3> + <h2>{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}</h2> <ds-curation-form [dsoHandle]="(dsoRD$|async)?.payload.handle" ></ds-curation-form> diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html index d7b0d0c475e..41e66610a85 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -18,7 +18,7 @@ <span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span> </button> </div> - <h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4> + <h2>{{ 'collection.edit.tabs.source.head' | translate }}</h2> <div *ngIf="contentSource" class="form-check mb-4"> <input type="checkbox" class="form-check-input" id="externalSourceCheck" [checked]="(contentSource?.harvestType !== harvestTypeNone)" (change)="changeExternalSource()"> diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html index 20afd701ffc..8d095dd2296 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html @@ -2,7 +2,7 @@ <div class="row"> <div class="col-12" *ngVar="(itemRD$ | async) as itemRD"> <ng-container *ngIf="itemRD?.hasSucceeded"> - <h2 class="border-bottom">{{ 'collection.edit.template.head' | translate:{ collection: dsoNameService.getName(collection) } }}</h2> + <h1 class="border-bottom">{{ 'collection.edit.template.head' | translate:{ collection: dsoNameService.getName(collection) } }}</h1> <ds-themed-dso-edit-metadata [updateDataService]="itemTemplateService" [dso]="itemRD?.payload"></ds-themed-dso-edit-metadata> <button [routerLink]="getCollectionEditUrl(collection)" class="btn btn-outline-secondary">{{ 'collection.edit.template.cancel' | translate }}</button> </ng-container> diff --git a/src/app/community-page/delete-community-page/delete-community-page.component.html b/src/app/community-page/delete-community-page/delete-community-page.component.html index 6bb8460bc95..ef5fdade73b 100644 --- a/src/app/community-page/delete-community-page/delete-community-page.component.html +++ b/src/app/community-page/delete-community-page/delete-community-page.component.html @@ -2,7 +2,7 @@ <div class="row"> <ng-container *ngVar="(dsoRD$ | async)?.payload as dso"> <div class="col-12 pb-4"> - <h2 id="header" class="border-bottom pb-2">{{ 'community.delete.head' | translate}}</h2> + <h1 id="header" class="border-bottom pb-2">{{ 'community.delete.head' | translate}}</h1> <p class="pb-2">{{ 'community.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p> <div class="form-group row"> <div class="col text-right space-children-mr"> diff --git a/src/app/community-page/edit-community-page/community-curate/community-curate.component.html b/src/app/community-page/edit-community-page/community-curate/community-curate.component.html index 6c041d17253..5e11fdfbcea 100644 --- a/src/app/community-page/edit-community-page/community-curate/community-curate.component.html +++ b/src/app/community-page/edit-community-page/community-curate/community-curate.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h3>{{'community.curate.header' |translate:{community: (communityName$ |async)} }}</h3> + <h2>{{'community.curate.header' |translate:{community: (communityName$ |async)} }}</h2> <ds-curation-form [dsoHandle]="(dsoRD$|async)?.payload.handle" ></ds-curation-form> diff --git a/src/app/info/feedback/feedback-form/feedback-form.component.html b/src/app/info/feedback/feedback-form/feedback-form.component.html index a3bab3a6a38..25be4ba4458 100644 --- a/src/app/info/feedback/feedback-form/feedback-form.component.html +++ b/src/app/info/feedback/feedback-form/feedback-form.component.html @@ -1,7 +1,7 @@ <div class="row row-offcanvas row-offcanvas-right"> <div class="col-xs-12 col-sm-12 col-md-9"> <form class="primary" [formGroup]="feedbackForm" (ngSubmit)="createFeedback()"> - <h2>{{ 'info.feedback.head' | translate }}</h2> + <h1>{{ 'info.feedback.head' | translate }}</h1> <p>{{ 'info.feedback.info' | translate }}</p> <fieldset class="col p-0"> <div class="row"> diff --git a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html index 1fae737fdb9..2d4ac89fcc3 100644 --- a/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html +++ b/src/app/item-page/bitstreams/request-a-copy/bitstream-request-a-copy-page.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h3 class="mb-4">{{'bitstream-request-a-copy.header' | translate}}</h3> + <h1 class="mb-4">{{'bitstream-request-a-copy.header' | translate}}</h1> <div *ngIf="canDownload$|async" class="alert alert-success"> <span>{{'bitstream-request-a-copy.alert.canDownload1' | translate}}</span> <a [routerLink]="getBitstreamLink()">{{'bitstream-request-a-copy.alert.canDownload2'| translate}}</a> 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 4aa4c9af161..1da10106f4f 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 @@ -1,7 +1,7 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2 class="border-bottom">{{'item.edit.head' | translate}}</h2> + <h1 class="border-bottom">{{'item.edit.head' | translate}}</h1> <div class="pt-2"> <ul class="nav nav-tabs justify-content-start" role="tablist"> <li *ngFor="let page of pages" class="nav-item" role="presentation"> diff --git a/src/app/item-page/edit-item-page/item-curate/item-curate.component.html b/src/app/item-page/edit-item-page/item-curate/item-curate.component.html index 7c7ed41bd96..22b10b28b66 100644 --- a/src/app/item-page/edit-item-page/item-curate/item-curate.component.html +++ b/src/app/item-page/edit-item-page/item-curate/item-curate.component.html @@ -1,5 +1,5 @@ <div class="container mt-3"> - <h3>{{'item.edit.curate.title' |translate:{item: (itemName$ |async)} }}</h3> + <h2>{{'item.edit.curate.title' |translate:{item: (itemName$ |async)} }}</h2> <ds-curation-form *ngIf="dsoRD$ | async as dsoRD" [dsoHandle]="dsoRD?.payload.handle" diff --git a/src/app/item-page/edit-item-page/item-delete/item-delete.component.html b/src/app/item-page/edit-item-page/item-delete/item-delete.component.html index 7b1953d8922..5191e705d0b 100644 --- a/src/app/item-page/edit-item-page/item-delete/item-delete.component.html +++ b/src/app/item-page/edit-item-page/item-delete/item-delete.component.html @@ -2,7 +2,7 @@ <div class="row"> <div class="col-12"> - <h2>{{headerMessage | translate: {id: item.handle} }}</h2> + <h1>{{headerMessage | translate: {id: item.handle} }}</h1> <p>{{descriptionMessage | translate}}</p> <ds-modify-item-overview [item]="item"></ds-modify-item-overview> diff --git a/src/app/item-page/edit-item-page/item-delete/item-delete.component.spec.ts b/src/app/item-page/edit-item-page/item-delete/item-delete.component.spec.ts index 2a9f7fae525..d406293828e 100644 --- a/src/app/item-page/edit-item-page/item-delete/item-delete.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-delete/item-delete.component.spec.ts @@ -171,7 +171,7 @@ describe('ItemDeleteComponent', () => { }); it('should render a page with messages based on the \'delete\' messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.delete.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; expect(description.innerHTML).toContain('item.edit.delete.description'); 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 c1a4a5b9a94..d136f003f4e 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 @@ -1,7 +1,7 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2>{{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle} }}</h2> + <h1>{{'item.edit.move.head' | translate: {id: (itemRD$ | async)?.payload?.handle} }}</h1> <p>{{'item.edit.move.description' | translate}}</p> <div class="row"> <div class="col-12"> diff --git a/src/app/item-page/edit-item-page/item-private/item-private.component.spec.ts b/src/app/item-page/edit-item-page/item-private/item-private.component.spec.ts index 323255e3d7b..24a4aacc997 100644 --- a/src/app/item-page/edit-item-page/item-private/item-private.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-private/item-private.component.spec.ts @@ -80,7 +80,7 @@ describe('ItemPrivateComponent', () => { }); it('should render a page with messages based on the \'private\' messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.private.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; expect(description.innerHTML).toContain('item.edit.private.description'); diff --git a/src/app/item-page/edit-item-page/item-public/item-public.component.spec.ts b/src/app/item-page/edit-item-page/item-public/item-public.component.spec.ts index 1f741fcc59b..0174e6a6b0e 100644 --- a/src/app/item-page/edit-item-page/item-public/item-public.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-public/item-public.component.spec.ts @@ -74,7 +74,7 @@ describe('ItemPublicComponent', () => { }); it('should render a page with messages based on the \'public\' messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.public.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; expect(description.innerHTML).toContain('item.edit.public.description'); diff --git a/src/app/item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts b/src/app/item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts index 594e7b806a7..4e2b00e4e6e 100644 --- a/src/app/item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-reinstate/item-reinstate.component.spec.ts @@ -76,7 +76,7 @@ describe('ItemReinstateComponent', () => { }); it('should render a page with messages based on the \'reinstate\' messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.reinstate.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; expect(description.innerHTML).toContain('item.edit.reinstate.description'); diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html index 7cdc903f240..d5f7901b3fb 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html @@ -1,10 +1,10 @@ -<h5> +<h2 class="h4"> {{getRelationshipMessageKey() | async | translate}} <button class="ml-2 btn btn-success" [disabled]="(hasChanges | async)" (click)="openLookup()"> <i class="fas fa-plus"></i> <span class="d-none d-sm-inline"> {{"item.edit.relationships.edit.buttons.add" | translate}}</span> </button> -</h5> +</h2> <ng-container *ngVar="updates$ | async as updates"> <ng-container *ngIf="updates && !(loading$ | async)"> <ng-container *ngVar="updates | dsObjectValues as updateValues"> diff --git a/src/app/item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts b/src/app/item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts index 3397742f5b0..1b7bff30e8b 100644 --- a/src/app/item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts +++ b/src/app/item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts @@ -74,7 +74,7 @@ describe('ItemWithdrawComponent', () => { }); it('should render a page with messages based on the \'withdraw\' messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.withdraw.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; expect(description.innerHTML).toContain('item.edit.withdraw.description'); diff --git a/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.html b/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.html index b5757d1859a..67249b085ad 100644 --- a/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.html +++ b/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.html @@ -1,7 +1,7 @@ <div class="container"> <div class="row"> <div class="col-12"> - <h2>{{headerMessage | translate: {id: item.handle} }}</h2> + <h1>{{headerMessage | translate: {id: item.handle} }}</h1> <p>{{descriptionMessage | translate}}</p> <ds-modify-item-overview [item]="item"></ds-modify-item-overview> <div class="space-children-mr"> diff --git a/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts b/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts index 9a19837665c..b7d64787264 100644 --- a/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts +++ b/src/app/item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts @@ -111,7 +111,7 @@ describe('AbstractSimpleItemActionComponent', () => { }); it('should render a page with messages based on the provided messageKey', () => { - const header = fixture.debugElement.query(By.css('h2')).nativeElement; + const header = fixture.debugElement.query(By.css('h1')).nativeElement; expect(header.innerHTML).toContain('item.edit.myEditAction.header'); const description = fixture.debugElement.query(By.css('p')).nativeElement; diff --git a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.html b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.html index e57ce330089..fdc966bd3b8 100644 --- a/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.html +++ b/src/app/item-page/orcid-page/orcid-auth/orcid-auth.component.html @@ -1,5 +1,5 @@ <div class="container mb-5"> - <h2>{{'person.orcid.registry.auth' | translate}}</h2> + <h1>{{'person.orcid.registry.auth' | translate}}</h1> <ng-container *ngIf="(isLinkedToOrcid() | async); then orcidLinked; else orcidNotLinked"></ng-container> </div> diff --git a/src/app/item-page/orcid-page/orcid-page.component.html b/src/app/item-page/orcid-page/orcid-page.component.html index 33c3125d676..6c30fbe1114 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.html +++ b/src/app/item-page/orcid-page/orcid-page.component.html @@ -1,13 +1,3 @@ -<div *ngIf="!(processingConnection | async) && (item | async)" class="container"> - <div class="button-row bottom mb-3"> - <div class="text-right"> - <a [routerLink]="getItemPage()" role="button" class="btn btn-outline-secondary" data-test="back-button"> - <i class="fas fa-arrow-left"></i> {{'item.orcid.return' | translate}} - </a> - </div> - </div> -</div> - <ds-loading *ngIf="(processingConnection | async)" [message]="'person.page.orcid.link.processing' | translate"></ds-loading> <div class="container" *ngIf="!(processingConnection | async) && !(connectionStatus | async)" data-test="error-box"> <ds-alert [type]="'alert-danger'">{{'person.page.orcid.link.error.message' | translate}}</ds-alert> @@ -17,3 +7,13 @@ <ds-orcid-sync-setting *ngIf="isLinkedToOrcid()" [item]="(item | async)" (settingsUpdated)="updateItem()" data-test="orcid-sync-setting"></ds-orcid-sync-setting> <ds-orcid-queue *ngIf="isLinkedToOrcid()" [item]="(item | async)"></ds-orcid-queue> </ng-container> + +<div *ngIf="!(processingConnection | async) && (item | async)" class="container"> + <div class="button-row bottom mb-3"> + <div class="text-right"> + <a [routerLink]="getItemPage()" role="button" class="btn btn-outline-secondary" data-test="back-button"> + <i class="fas fa-arrow-left"></i> {{'item.orcid.return' | translate}} + </a> + </div> + </div> +</div> diff --git a/src/app/process-page/detail/process-detail-field/process-detail-field.component.html b/src/app/process-page/detail/process-detail-field/process-detail-field.component.html index ce26008c28d..2558b6cf7ac 100644 --- a/src/app/process-page/detail/process-detail-field/process-detail-field.component.html +++ b/src/app/process-page/detail/process-detail-field/process-detail-field.component.html @@ -1,2 +1,2 @@ -<h4 class="mt-4">{{title | translate}}</h4> +<h2 class="h3 mt-4">{{title | translate}}</h2> <ng-content></ng-content> diff --git a/src/app/process-page/detail/process-detail.component.html b/src/app/process-page/detail/process-detail.component.html index c52ef3827d8..4daee064dff 100644 --- a/src/app/process-page/detail/process-detail.component.html +++ b/src/app/process-page/detail/process-detail.component.html @@ -1,9 +1,9 @@ <div class="container" *ngIf="(processRD$ | async)?.payload as process"> <div class="row"> <div class="col-10"> - <h2 class="flex-grow-1"> + <h1 class="flex-grow-1"> {{ 'process.detail.title' | translate:{ id: process?.processId, name: process?.scriptName } }} - </h2> + </h1> </div> <div *ngIf="refreshCounter$ | async as seconds" class="col-2 refresh-counter"> Refreshing in {{ seconds }}s <i class="fas fa-sync-alt fa-spin"></i> diff --git a/src/app/process-page/form/process-form.component.html b/src/app/process-page/form/process-form.component.html index c55592f3e77..211129489e5 100644 --- a/src/app/process-page/form/process-form.component.html +++ b/src/app/process-page/form/process-form.component.html @@ -1,8 +1,8 @@ <div class="container"> <div class="row"> - <h2 class="col-12"> + <h1 class="col-12"> {{headerKey | translate}} - </h2> + </h1> <div class="col-12 col-md-6 mb-2"> <form #form="ngForm" (ngSubmit)="submitForm(form)"> <ds-scripts-select [script]="selectedScript" (select)="selectedScript = $event; parameters = undefined"></ds-scripts-select> @@ -12,7 +12,7 @@ <h2 class="col-12"> </form> </div> <div class="col-12 col-md-6"> - <ds-script-help [script]="selectedScript"></ds-script-help> + <ds-script-help *ngIf="selectedScript" [script]="selectedScript"></ds-script-help> </div> </div> diff --git a/src/app/process-page/form/script-help/script-help.component.html b/src/app/process-page/form/script-help/script-help.component.html index f52ae4b6b99..7615edcfd49 100644 --- a/src/app/process-page/form/script-help/script-help.component.html +++ b/src/app/process-page/form/script-help/script-help.component.html @@ -1,5 +1,5 @@ <div class="text-secondary"> - <h3>{{script?.name}}</h3> + <h2>{{script?.name}}</h2> <span>{{script?.description}}</span> <table class="table-borderless mt-3"> diff --git a/src/app/process-page/overview/process-overview.component.html b/src/app/process-page/overview/process-overview.component.html index dcad265490a..3f0e1e841f4 100644 --- a/src/app/process-page/overview/process-overview.component.html +++ b/src/app/process-page/overview/process-overview.component.html @@ -1,6 +1,6 @@ <div class="container"> <div class="d-flex"> - <h2 class="flex-grow-1">{{'process.overview.title' | translate}}</h2> + <h1 class="flex-grow-1">{{'process.overview.title' | translate}}</h1> </div> <div class="d-flex justify-content-end"> <button *ngIf="processBulkDeleteService.hasSelected()" class="btn btn-primary mr-2" diff --git a/src/app/profile-page/profile-page.component.html b/src/app/profile-page/profile-page.component.html index 44783da84e8..187096b3912 100644 --- a/src/app/profile-page/profile-page.component.html +++ b/src/app/profile-page/profile-page.component.html @@ -1,7 +1,7 @@ <ng-container *ngVar="(user$ | async) as user"> <div class="container" *ngIf="user"> <ng-container *ngIf="isResearcherProfileEnabled() | async"> - <h3 class="mb-4">{{'profile.head' | translate}}</h3> + <h2 class="mb-4">{{'profile.head' | translate}}</h2> <div class="card mb-4"> <div class="card-header">{{'profile.card.researcher' | translate}}</div> <div class="card-body"> @@ -34,7 +34,7 @@ <h3 class="mb-4">{{'profile.head' | translate}}</h3> <ng-container *ngVar="(groupsRD$ | async)?.payload?.page as groups"> <div *ngIf="groups?.length > 0"> - <h3 class="mt-4">{{'profile.groups.head' | translate}}</h3> + <h2 class="mt-4">{{'profile.groups.head' | translate}}</h2> <ul class="list-group list-group-flush"> <li *ngFor="let group of groups" class="list-group-item">{{ dsoNameService.getName(group) }}</li> </ul> @@ -43,7 +43,7 @@ <h3 class="mt-4">{{'profile.groups.head' | translate}}</h3> <ng-container *ngVar="(specialGroupsRD$ | async)?.payload?.page as specialGroups"> <div *ngIf="specialGroups?.length > 0" data-test="specialGroups"> - <h3 class="mt-4">{{'profile.special.groups.head' | translate}}</h3> + <h2 class="mt-4">{{'profile.special.groups.head' | translate}}</h2> <ul class="list-group list-group-flush"> <li *ngFor="let specialGroup of specialGroups" class="list-group-item"> {{ dsoNameService.getName(specialGroup) }} diff --git a/src/app/register-email-form/register-email-form.component.html b/src/app/register-email-form/register-email-form.component.html index ed79b1d2d17..d4cf75b5630 100644 --- a/src/app/register-email-form/register-email-form.component.html +++ b/src/app/register-email-form/register-email-form.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h2>{{MESSAGE_PREFIX + '.header'|translate}}</h2> + <h1>{{MESSAGE_PREFIX + '.header'|translate}}</h1> <p>{{MESSAGE_PREFIX + '.info' | translate}}</p> <p *ngIf="validMailDomains.length != 0 && typeRequest === TYPE_REQUEST_REGISTER"> diff --git a/src/app/shared/access-control-form-container/access-control-form-container.component.html b/src/app/shared/access-control-form-container/access-control-form-container.component.html index 263bf60ac7b..23c62abc6ca 100644 --- a/src/app/shared/access-control-form-container/access-control-form-container.component.html +++ b/src/app/shared/access-control-form-container/access-control-form-container.component.html @@ -13,9 +13,9 @@ <div> <div class="d-flex align-items-center"> - <h4 class="mb-0 mr-4"> + <h2 class="h3 mb-0 mr-4"> {{ 'access-control-item-header-toggle' | translate }} - </h4> + </h2> <ui-switch [ariaLabel]="(state.bitstream.toggleStatus ? 'access-control-item-toggle.disable' : 'access-control-item-toggle.enable') | translate" [(ngModel)]="state.item.toggleStatus" @@ -51,7 +51,7 @@ <h4 class="mb-0 mr-4"> </div> <div> - <h5 class="mt-3">{{'access-control-access-conditions' | translate}}</h5> + <h3 class="h4 mt-3">{{'access-control-access-conditions' | translate}}</h3> <ds-access-control-array-form #itemAccessCmp @@ -67,9 +67,9 @@ <h5 class="mt-3">{{'access-control-access-conditions' | translate}}</h5> <div> <div class="d-flex align-items-center"> - <h4 class="mb-0 mr-4"> + <h2 class="h3 mb-0 mr-4"> {{'access-control-bitstream-header-toggle' | translate}} - </h4> + </h2> <ui-switch [ariaLabel]="(state.bitstream.toggleStatus ? 'access-control-bitstream-toggle.disable' : 'access-control-bitstream-toggle.enable') | translate" [(ngModel)]="state.bitstream.toggleStatus" @@ -142,7 +142,7 @@ <h4 class="mb-0 mr-4"> </div> <div> - <h5 class="mt-3">{{'access-control-access-conditions' | translate}}</h5> + <h3 class="h4 mt-3">{{'access-control-access-conditions' | translate}}</h3> <ds-access-control-array-form #bitstreamAccessCmp diff --git a/src/app/shared/browse-by/browse-by.component.html b/src/app/shared/browse-by/browse-by.component.html index d6a00051739..37799e805ff 100644 --- a/src/app/shared/browse-by/browse-by.component.html +++ b/src/app/shared/browse-by/browse-by.component.html @@ -1,5 +1,5 @@ <ng-container *ngVar="(objects$ | async) as objects"> - <h3 [ngClass]="{'sr-only': parentname }">{{title | translate}}</h3> + <h1 [ngClass]="{'sr-only': parentname }">{{title | translate}}</h1> <ng-container *ngComponentOutlet="getStartsWithComponent(); injector: objectInjector;"></ng-container> <div *ngIf="objects?.hasSucceeded && !objects?.isLoading && objects?.payload?.page.length > 0" @fadeIn> <div *ngIf="shouldDisplayResetButton$ |async" class="mb-2 reset"> diff --git a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html index 1e1f3d82093..b6d598d562c 100644 --- a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html @@ -3,9 +3,9 @@ <div class="card-body d-flex flex-column" *ngVar="group$ | async as group"> - <h5 class="w-100"> + <h2 class="h4 w-100"> {{ roleName$ | async }} - </h5> + </h2> <div class="mt-2 mb-2"> <ds-alert [type]="'alert-info'" >{{'comcol-role.edit.' + (comcolRole$ | async)?.name + '.description' | translate}}</ds-alert> diff --git a/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html index 819d080f895..c397966fba1 100644 --- a/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html @@ -2,8 +2,8 @@ <div class="row"> <div class="col-12"> <div class="d-flex justify-content-between border-bottom"> - <h2>{{ type + '.edit.head' | translate }}</h2> - <div> + <h1>{{ type + '.edit.head' | translate }}</h1> + <div class="my-auto"> <a class="btn btn-danger" [routerLink]="((type === 'community') ? '/communities/' : '/collections/') + (dsoRD$ | async)?.payload.uuid + '/delete'"> <i class="fas fa-trash"></i> {{type + '.edit.delete' | translate}}</a> diff --git a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html index 552854a0c02..01a71ab142b 100644 --- a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html +++ b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.html @@ -1,4 +1,4 @@ -<div *ngIf="content" class="content-with-optional-title mb-2"> - <h2 class="d-inline-block h6" *ngIf="title">{{ title | translate }}</h2> - <div class="d-inline-block px-2"><a href="{{getHandle()}}">{{getHandle()}}</a></div> -</div> +<p *ngIf="content" class="d-flex flex-wrap gapx-2 text-break"> + <span class="mb-0" *ngIf="title">{{ title | translate }}</span> + <a [href]="getHandle()">{{getHandle()}}</a> +</p> diff --git a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss index 5d7bac26c7f..e69de29bb2d 100644 --- a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss +++ b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.scss @@ -1,5 +0,0 @@ -div { - word-break: break-word; - word-wrap: break-word; - overflow-wrap: break-word; -} diff --git a/src/app/shared/resource-policies/edit/resource-policy-edit.component.html b/src/app/shared/resource-policies/edit/resource-policy-edit.component.html index 0f285c49489..a820fa481a5 100644 --- a/src/app/shared/resource-policies/edit/resource-policy-edit.component.html +++ b/src/app/shared/resource-policies/edit/resource-policy-edit.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h4 class="mb-3">{{'resource-policies.edit.page.heading' | translate}} {{resourcePolicy.id}}</h4> + <h1 class="mb-3">{{'resource-policies.edit.page.heading' | translate}} {{resourcePolicy.id}}</h1> <ds-resource-policy-form [resourcePolicy]="resourcePolicy" [isProcessing]="isProcessing()" diff --git a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html index f63bf9fa844..64c0cd50085 100644 --- a/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html +++ b/src/app/shared/search/search-switch-configuration/search-switch-configuration.component.html @@ -1,5 +1,5 @@ <div *ngIf="configurationList?.length > 1" class="search-switch-configuration"> - <h5 id="configuration-switch">{{ 'search.switch-configuration.title' | translate}}</h5> + <h3 id="configuration-switch">{{ 'search.switch-configuration.title' | translate}}</h3> <select class="form-control" aria-labelledby="configuration-switch" diff --git a/src/app/statistics-page/statistics-page/statistics-page.component.html b/src/app/statistics-page/statistics-page/statistics-page.component.html index c6938c7582b..047bf52e7c3 100644 --- a/src/app/statistics-page/statistics-page/statistics-page.component.html +++ b/src/app/statistics-page/statistics-page/statistics-page.component.html @@ -1,11 +1,11 @@ <div class="container"> <ng-container *ngVar="(scope$ | async) as scope"> - <h2 *ngIf="scope" + <h1 *ngIf="scope" class="header" id="{{ scope.id }}"> {{ 'statistics.header' | translate: { scope: getName(scope) } }} - </h2> + </h1> </ng-container> <ng-container *ngVar="reports$ | async as reports"> diff --git a/src/app/statistics-page/statistics-table/statistics-table.component.html b/src/app/statistics-page/statistics-table/statistics-table.component.html index 5a333b96586..efa9ce43d99 100644 --- a/src/app/statistics-page/statistics-table/statistics-table.component.html +++ b/src/app/statistics-page/statistics-table/statistics-table.component.html @@ -1,9 +1,9 @@ <div *ngIf="hasData" class="m-1"> - <h3 class="m-1"> + <h2 class="m-1"> {{ 'statistics.table.title.' + report.reportType | translate }} - </h3> + </h2> <table class="table table-striped" [attr.data-test]="report.reportType"> diff --git a/src/app/submission/import-external/submission-import-external.component.html b/src/app/submission/import-external/submission-import-external.component.html index dc46e6758fd..8d13b1785a0 100644 --- a/src/app/submission/import-external/submission-import-external.component.html +++ b/src/app/submission/import-external/submission-import-external.component.html @@ -1,7 +1,7 @@ <div class="container"> <div class="row"> <div class="col-md-12"> - <h2 id="header" class="pb-2">{{'submission.import-external.title' + ((label) ? '.' + label : '') | translate}}</h2> + <h1 id="header" class="pb-2">{{'submission.import-external.title' + ((label) ? '.' + label : '') | translate}}</h1> <ds-submission-import-external-searchbar [initExternalSourceData]="reload$.value" (externalSourceData) = "getExternalSourceData($event)"> @@ -11,7 +11,7 @@ <h2 id="header" class="pb-2">{{'submission.import-external.title' + ((label) ? ' <div class="row" *ngIf="reload$.value.entity"> <div *ngIf="reload$.value.sourceId !== ''" class="col-md-12"> <ng-container *ngVar="(entriesRD$ | async) as entriesRD"> - <h3 *ngIf="entriesRD && entriesRD?.payload?.page?.length !== 0">{{ 'submission.sections.describe.relationship-lookup.selection-tab.title' | translate}}</h3> + <h2 *ngIf="entriesRD && entriesRD?.payload?.page?.length !== 0">{{ 'submission.sections.describe.relationship-lookup.selection-tab.title' | translate}}</h2> <ds-viewable-collection *ngIf="entriesRD?.hasSucceeded && !(isLoading$ | async) && entriesRD?.payload?.page?.length > 0" @fadeIn [objects]="entriesRD" [selectionConfig]="{ repeatable: repeatable, listId: listId }" @@ -25,15 +25,15 @@ <h3 *ngIf="entriesRD && entriesRD?.payload?.page?.length !== 0">{{ 'submission.s <ds-themed-loading *ngIf="(isLoading$ | async)" message="{{'loading.search-results' | translate}}"></ds-themed-loading> <div *ngIf="!(isLoading$ | async) && entriesRD?.payload?.page?.length === 0" data-test="empty-external-entry-list"> - <ds-alert [type]="'alert-info'">{{ 'search.results.empty' | translate }}</ds-alert> + <ds-alert [type]="AlertType.Info">{{ 'search.results.empty' | translate }}</ds-alert> </div> <div *ngIf="!(isLoading$ | async) && entriesRD.statusCode === 500" data-test="empty-external-error-500"> - <ds-alert [type]="'alert-info'">{{ 'search.results.response.500' | translate }}</ds-alert> + <ds-alert [type]="AlertType.Info">{{ 'search.results.response.500' | translate }}</ds-alert> </div> </ng-container> </div> <div *ngIf="reload$.value.sourceId === ''" class="col-md-12"> - <ds-alert [type]="'alert-info'"> + <ds-alert [type]="AlertType.Info"> <p class="lead mb-0">{{'submission.import-external.page.hint' | translate}}</p> </ds-alert> </div> diff --git a/src/app/submission/import-external/submission-import-external.component.ts b/src/app/submission/import-external/submission-import-external.component.ts index 25b1d5d1aa2..b4aacd4e63b 100644 --- a/src/app/submission/import-external/submission-import-external.component.ts +++ b/src/app/submission/import-external/submission-import-external.component.ts @@ -23,6 +23,7 @@ import { PageInfo } from '../../core/shared/page-info.model'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { getFinishedRemoteData } from '../../core/shared/operators'; import { NONE_ENTITY_TYPE } from '../../core/shared/item-relationships/item-type.resource-type'; +import { AlertType } from 'src/app/shared/alert/alert-type'; /** * This component allows to submit a new workspaceitem importing the data from an external source. @@ -92,6 +93,8 @@ export class SubmissionImportExternalComponent implements OnInit, OnDestroy { private retrieveExternalSourcesSub: Subscription; + public readonly AlertType = AlertType; + /** * Initialize the component variables. * @param {SearchConfigurationService} searchConfigService diff --git a/src/app/subscriptions-page/subscriptions-page.component.html b/src/app/subscriptions-page/subscriptions-page.component.html index ed31e16759b..4d204df93c4 100644 --- a/src/app/subscriptions-page/subscriptions-page.component.html +++ b/src/app/subscriptions-page/subscriptions-page.component.html @@ -1,7 +1,7 @@ <div class="container"> <div class="row"> <div class="col-md-12 m-40"> - <h2>{{'subscriptions.title' | translate}}</h2> + <h1>{{'subscriptions.title' | translate}}</h1> <div class="row"> <div class="col-md-12 m-40"> <ds-themed-loading *ngIf="loading$ | async"></ds-themed-loading> @@ -34,7 +34,7 @@ <h2>{{'subscriptions.title' | translate}}</h2> </div> </ds-pagination> - <ds-alert *ngIf="subscriptions?.pageInfo?.totalElements == 0 && !(loading$ | async)" [type]="'alert-info'" data-test="empty-alert"> + <ds-alert *ngIf="subscriptions?.pageInfo?.totalElements == 0 && !(loading$ | async)" [type]="AlertType.Info" data-test="empty-alert"> {{ 'subscriptions.table.empty.message' | translate }} </ds-alert> diff --git a/src/app/subscriptions-page/subscriptions-page.component.ts b/src/app/subscriptions-page/subscriptions-page.component.ts index 05c587ba12c..35278d5dc2e 100644 --- a/src/app/subscriptions-page/subscriptions-page.component.ts +++ b/src/app/subscriptions-page/subscriptions-page.component.ts @@ -14,6 +14,7 @@ import { EPerson } from '../core/eperson/models/eperson.model'; import { getAllCompletedRemoteData } from '../core/shared/operators'; import { RemoteData } from '../core/data/remote-data'; import { hasValue } from '../shared/empty.util'; +import { AlertType } from '../shared/alert/alert-type'; @Component({ selector: 'ds-subscriptions-page', @@ -54,6 +55,8 @@ export class SubscriptionsPageComponent implements OnInit, OnDestroy { */ sub: rxjsSubscription = null; + readonly AlertType = AlertType; + constructor( private paginationService: PaginationService, private authService: AuthService, diff --git a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html index d1de00bea6e..95c7a694489 100644 --- a/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html +++ b/src/app/system-wide-alert/alert-form/system-wide-alert-form.component.html @@ -1,5 +1,5 @@ <div class="container"> - <h2 id="header">{{'system-wide-alert.form.header' | translate}}</h2> + <h1 id="header">{{'system-wide-alert.form.header' | translate}}</h1> <div [formGroup]="alertForm" [class]="'ng-invalid'"> <div class="form-group"> <div class="row mb-2"> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 432a0b33b40..12312612dd5 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -864,6 +864,8 @@ "browse.startsWith.input": "Filter", + "browse.taxonomy_srsc.title": "Browsing by Subject Category", + "browse.taxonomy.button": "Browse", "browse.title": "Browsing {{ collection }} by {{ field }}{{ startsWith }} {{ value }}", diff --git a/src/styles/_bootstrap_variables.scss b/src/styles/_bootstrap_variables.scss index 5dfc03fbd36..69b288905a1 100644 --- a/src/styles/_bootstrap_variables.scss +++ b/src/styles/_bootstrap_variables.scss @@ -12,6 +12,14 @@ $fa-font-path: "^assets/fonts" !default; /* Images */ $image-path: "../assets/images" !default; +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$h1-font-size: $font-size-base * 2.125 !default; +$h2-font-size: $font-size-base * 1.75 !default; +$h3-font-size: $font-size-base * 1.5 !default; +$h4-font-size: $font-size-base * 1.25 !default; +$h5-font-size: $font-size-base * 1.125 !default; +$h6-font-size: $font-size-base !default; + // enable-responsive-font-sizes allows text to scale more naturally across device and viewport sizes $enable-responsive-font-sizes: true; From 9a5ad0bc9fab596c7a229a94fa06e92b80d1b607 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 23:11:50 +0100 Subject: [PATCH 242/282] Fixed accessibility issues on search page --- .../selectable-list-item-control.component.html | 4 +++- .../selectable-list-item-control.component.spec.ts | 6 +++++- .../search-filter/search-filter.component.html | 13 +++++++------ .../search-label/search-label.component.html | 3 ++- .../view-mode-switch.component.html | 8 ++++++-- src/assets/i18n/en.json5 | 6 ++++++ 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.html b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.html index 56a83913a76..a90f375c6a1 100644 --- a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.html +++ b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.html @@ -1,10 +1,12 @@ <ng-container *ngVar="selectionService?.isObjectSelected(selectionConfig?.listId, object) | async as checked"> - <input *ngIf="selectionConfig.repeatable" class="form-check-input" type="checkbox" + <input #selectListItemCheckbox *ngIf="selectionConfig.repeatable" class="form-check-input" type="checkbox" + [attr.aria-label]="(selectListItemCheckbox.checked ? 'selectable-list-item-control.deselect' : 'selectable-list-item-control.select') | translate" [name]="'checkbox' + index" [id]="'object' + index" [ngModel]="selected$ | async" (ngModelChange)="selectCheckbox($event)"> <input *ngIf="!selectionConfig.repeatable" class="form-check-input mt-2" type="radio" + [attr.aria-label]="'selectable-list-item-control.select' | translate" [name]="'radio' + index" [id]="'object' + index" [checked]="selected$ | async" diff --git a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.spec.ts b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.spec.ts index c8756567b86..73d70bfa7a9 100644 --- a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.spec.ts +++ b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.spec.ts @@ -7,6 +7,7 @@ import { FormsModule } from '@angular/forms'; import { VarDirective } from '../../../utils/var.directive'; import { of as observableOf } from 'rxjs'; import { ListableObject } from '../listable-object.model'; +import { TranslateModule } from '@ngx-translate/core'; describe('SelectableListItemControlComponent', () => { let comp: SelectableListItemControlComponent; @@ -45,7 +46,10 @@ describe('SelectableListItemControlComponent', () => { init(); TestBed.configureTestingModule({ declarations: [SelectableListItemControlComponent, VarDirective], - imports: [FormsModule], + imports: [ + FormsModule, + TranslateModule.forRoot(), + ], providers: [ { provide: SelectableListService, diff --git a/src/app/shared/search/search-filters/search-filter/search-filter.component.html b/src/app/shared/search/search-filters/search-filter/search-filter.component.html index 25c218166ef..a352c5587b3 100644 --- a/src/app/shared/search/search-filters/search-filter/search-filter.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-filter.component.html @@ -2,17 +2,18 @@ [id]="regionId" [attr.aria-labelledby]="toggleId" [ngClass]="{ 'focus': focusBox }" role="region"> <button (click)="toggle()" (focusin)="focusBox = true" (focusout)="focusBox = false" class="filter-name d-flex" [attr.aria-controls]="regionId" [id]="toggleId" - [attr.aria-expanded]="false" + [attr.aria-expanded]="!(collapsed$ | async)" [attr.aria-label]="(((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate) + ' ' + (('search.filters.filter.' + filter.name + '.head') | translate | lowercase)" [attr.data-test]="'filter-toggle' | dsBrowserOnly" > - <h4 class="d-inline-block text-left mt-auto mb-auto"> + <span class="h4 d-inline-block text-left mt-auto mb-auto"> {{'search.filters.filter.' + filter.name + '.head'| translate}} - </h4> - <span class="filter-toggle flex-grow-1 fas p-auto" - [ngClass]="(collapsed$ | async) ? 'fa-plus' : 'fa-minus'" - [title]="((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate"> </span> + <i class="filter-toggle flex-grow-1 fas p-auto" + aria-hidden="true" + [ngClass]="(collapsed$ | async) ? 'fa-plus' : 'fa-minus'" + [title]="((collapsed$ | async) ? 'search.filters.filter.expand' : 'search.filters.filter.collapse') | translate"> + </i> </button> <div [@slide]="(collapsed$ | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" 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 17c5a487181..2269771de1f 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,6 +1,7 @@ <a class="badge badge-primary mr-1 mb-1" + [attr.aria-label]="'search.filters.remove' | translate:{ type: ('search.filters.applied.' + key) | translate, value: normalizeFilterValue(value) }" [routerLink]="searchLink" [queryParams]="(removeParameters | async)" queryParamsHandling="merge"> {{('search.filters.applied.' + key) | translate}}: {{'search.filters.' + filterName + '.' + value | translate: {default: normalizeFilterValue(value)} }} - <span> ×</span> + <span aria-hidden="true"> ×</span> </a> diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.html b/src/app/shared/view-mode-switch/view-mode-switch.component.html index 45d219eb916..5d29562a766 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.html +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.html @@ -1,5 +1,7 @@ <div class="btn-group" data-toggle="buttons"> <button *ngIf="isToShow(viewModeEnum.ListElement)" + [attr.aria-current]="currentMode === viewModeEnum.ListElement" + [attr.aria-label]="'search.view-switch.show-list' | translate" routerLink="." [queryParams]="{view: 'list'}" queryParamsHandling="merge" @@ -8,9 +10,11 @@ [class.active]="currentMode === viewModeEnum.ListElement" class="btn btn-secondary" [attr.data-test]="'list-view' | dsBrowserOnly"> - <span class="fas fa-list"></span><span class="sr-only">{{'search.view-switch.show-list' | translate}}</span> + <i class="fas fa-list"></i> </button> <button *ngIf="isToShow(viewModeEnum.GridElement)" + [attr.aria-current]="currentMode === viewModeEnum.GridElement" + [attr.aria-label]="'search.view-switch.show-grid' | translate" routerLink="." [queryParams]="{view: 'grid'}" queryParamsHandling="merge" @@ -19,7 +23,7 @@ [class.active]="currentMode === viewModeEnum.GridElement" class="btn btn-secondary" [attr.data-test]="'grid-view' | dsBrowserOnly"> - <span class="fas fa-th-large"></span><span class="sr-only">{{'search.view-switch.show-grid' | translate}}</span> + <i class="fas fa-th-large"></i> </button> <button *ngIf="isToShow(viewModeEnum.DetailedListElement)" routerLink="." diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 12312612dd5..21c608d4c51 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3666,6 +3666,8 @@ "search.search-form.placeholder": "Search the repository ...", + "search.filters.remove": "Remove filter of type {{ type }} with value {{ value }}", + "search.filters.applied.f.author": "Author", "search.filters.applied.f.dateIssued.max": "End date", @@ -3920,6 +3922,10 @@ "search.view-switch.show-list": "Show as list", + "selectable-list-item-control.deselect": "Deselect item", + + "selectable-list-item-control.select": "Select item", + "sorting.ASC": "Ascending", "sorting.DESC": "Descending", From e96d3cd2e9f799dc46f827af6d7d7bf587b68eee Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Sun, 3 Dec 2023 23:28:19 +0100 Subject: [PATCH 243/282] Fixed DSONameService getName & getHitHighlights returning empty string for OrgUnits without organization.legalName field --- src/app/core/breadcrumbs/dso-name.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/core/breadcrumbs/dso-name.service.ts b/src/app/core/breadcrumbs/dso-name.service.ts index ddd97705b01..8e4fb771c64 100644 --- a/src/app/core/breadcrumbs/dso-name.service.ts +++ b/src/app/core/breadcrumbs/dso-name.service.ts @@ -50,7 +50,7 @@ export class DSONameService { } }, OrgUnit: (dso: DSpaceObject): string => { - return dso.firstMetadataValue('organization.legalName'); + return dso.firstMetadataValue('organization.legalName') || this.translateService.instant('dso.name.untitled'); }, Default: (dso: DSpaceObject): string => { // If object doesn't have dc.title metadata use name property @@ -106,7 +106,7 @@ export class DSONameService { } return `${familyName}, ${givenName}`; } else if (entityType === 'OrgUnit') { - return this.firstMetadataValue(object, dso, 'organization.legalName'); + return this.firstMetadataValue(object, dso, 'organization.legalName') || this.translateService.instant('dso.name.untitled'); } return this.firstMetadataValue(object, dso, 'dc.title') || dso.name || this.translateService.instant('dso.name.untitled'); } From 2592f87356d1caa4f7d396f8e7f9188393e5efb7 Mon Sep 17 00:00:00 2001 From: Michael Spalti <mspalti@gmail.com> Date: Mon, 4 Dec 2023 11:37:14 -0800 Subject: [PATCH 244/282] Updated bitstream read description in en.json5 --- src/assets/i18n/en.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 6dee5d54e66..c39106ff1bd 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1258,7 +1258,7 @@ "comcol-role.edit.bitstream_read.name": "Default bitstream read access", - "comcol-role.edit.bitstream_read.description": "Community administrators can create sub-communities or collections, and manage or assign management for those sub-communities or collections. In addition, they decide who can submit items to any sub-collections, edit item metadata (after submission), and add (map) existing items from other collections (subject to authorization).", + "comcol-role.edit.bitstream_read.description": "E-People and Groups that can read new bitstreams submitted to this collection. Changes to this role are not retroactive. Existing bitstreams in the system will still be viewable by those who had read access at the time of their addition.", "comcol-role.edit.bitstream_read.anonymous-group": "Default read for incoming bitstreams is currently set to Anonymous.", From 09fc44a539477df9e67809921d9ddf1b22198adc Mon Sep 17 00:00:00 2001 From: Thomas Misilo <tmisilo@ksu.edu> Date: Tue, 5 Dec 2023 10:02:17 -0600 Subject: [PATCH 245/282] Decrease min-height for Login Dropdown Menu Fixes #2690 This is noticable when you have disabled local authentication, and only have a singular remote authentication such as Shibboleth or Orcid. --- src/app/shared/auth-nav-menu/auth-nav-menu.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss b/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss index 40e9113b009..3f6b2b009c2 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss @@ -4,7 +4,7 @@ } .loginDropdownMenu { - min-height: 260px; + min-height: 75px; } .dropdown-item.active, .dropdown-item:active, From ff6dff72d8db680c00b159496beecf87517fec98 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 6 Dec 2023 01:08:00 +0100 Subject: [PATCH 246/282] Fixed Edit Item Bitstream showing empty buttons when css is turned off --- .../item-edit-bitstream.component.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html index a3e29ac10c2..f0671d3d300 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.html @@ -26,21 +26,25 @@ <div class="text-center w-100"> <div class="btn-group relationship-action-buttons"> <a *ngIf="bitstreamDownloadUrl != null" [routerLink]="bitstreamDownloadUrl" - class="btn btn-outline-primary btn-sm" - title="{{'item.edit.bitstreams.edit.buttons.download' | translate}}" - [attr.data-test]="'download-button' | dsBrowserOnly"> + [attr.aria-label]="'item.edit.bitstreams.edit.buttons.download' | translate" + class="btn btn-outline-primary btn-sm" + title="{{'item.edit.bitstreams.edit.buttons.download' | translate}}" + [attr.data-test]="'download-button' | dsBrowserOnly"> <i class="fas fa-download fa-fw"></i> </a> <button [routerLink]="['/bitstreams/', bitstream.id, 'edit']" class="btn btn-outline-primary btn-sm" + [attr.aria-label]="'item.edit.bitstreams.edit.buttons.edit' | translate" title="{{'item.edit.bitstreams.edit.buttons.edit' | translate}}"> <i class="fas fa-edit fa-fw"></i> </button> <button [disabled]="!canRemove()" (click)="remove()" + [attr.aria-label]="'item.edit.bitstreams.edit.buttons.remove' | translate" class="btn btn-outline-danger btn-sm" title="{{'item.edit.bitstreams.edit.buttons.remove' | translate}}"> <i class="fas fa-trash-alt fa-fw"></i> </button> <button [disabled]="!canUndo()" (click)="undo()" + [attr.aria-label]="'item.edit.bitstreams.edit.buttons.undo' | translate" class="btn btn-outline-warning btn-sm" title="{{'item.edit.bitstreams.edit.buttons.undo' | translate}}"> <i class="fas fa-undo-alt fa-fw"></i> From 4545b5354dcc1994b28435ccad95d64f9c328ed5 Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem <alexandre@atmire.com> Date: Wed, 6 Dec 2023 02:03:44 +0100 Subject: [PATCH 247/282] Fixed Edit Item Bitstream showing empty buttons when css is turned off & replaced authentication dropdown menu link with button - Also fixed box-shadows not working the same way for all footer buttons/links --- src/app/footer/footer.component.html | 6 +++--- src/app/footer/footer.component.scss | 9 +++++++++ .../shared/auth-nav-menu/auth-nav-menu.component.html | 11 +++++++---- .../shared/auth-nav-menu/auth-nav-menu.component.scss | 9 +++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/app/footer/footer.component.html b/src/app/footer/footer.component.html index d4c0cd1a377..ac903929f6f 100644 --- a/src/app/footer/footer.component.html +++ b/src/app/footer/footer.component.html @@ -69,15 +69,15 @@ <h5 class="text-uppercase">Footer Content</h5> </button> </li> <li *ngIf="showPrivacyPolicy"> - <a class="text-white" + <a class="btn text-white" routerLink="info/privacy">{{ 'footer.link.privacy-policy' | translate}}</a> </li> <li *ngIf="showEndUserAgreement"> - <a class="text-white" + <a class="btn text-white" routerLink="info/end-user-agreement">{{ 'footer.link.end-user-agreement' | translate}}</a> </li> <li *ngIf="showSendFeedback$ | async"> - <a class="text-white" + <a class="btn text-white" routerLink="info/feedback">{{ 'footer.link.feedback' | translate}}</a> </li> </ul> diff --git a/src/app/footer/footer.component.scss b/src/app/footer/footer.component.scss index 4dfdc3267ba..f1a872c0994 100644 --- a/src/app/footer/footer.component.scss +++ b/src/app/footer/footer.component.scss @@ -30,6 +30,15 @@ padding: 0 calc(var(--bs-spacer) / 2); color: inherit; font-size: .875em; + + &:focus { + box-shadow: none; + text-decoration: underline; + } + + &:focus-visible { + box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.5); + } } &:not(:last-child) { 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 eba37fa4160..a0623bdd90d 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,9 +2,11 @@ <li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item" (click)="$event.stopPropagation();"> <div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut> - <a href="javascript:void(0);" class="dropdownLogin px-0.5" [attr.aria-label]="'nav.login' |translate" + <button class="btn btn-link dropdownLogin px-0.5" [attr.aria-label]="'nav.login' |translate" (click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly" - ngbDropdownToggle>{{ 'nav.login' | translate }}</a> + ngbDropdownToggle> + {{ 'nav.login' | translate }} + </button> <div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu [attr.aria-label]="'nav.login' | translate"> <ds-themed-log-in @@ -19,8 +21,9 @@ </li> <li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"> <div ngbDropdown display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut> - <a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="dropdownLogout px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle> - <i class="fas fa-user-circle fa-lg fa-fw"></i></a> + <button role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="btn btn-link dropdownLogout px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle> + <i class="fas fa-user-circle fa-lg fa-fw"></i> + </button> <div class="logoutDropdownMenu" ngbDropdownMenu [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate"> <ds-themed-user-menu></ds-themed-user-menu> </div> diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss b/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss index 40e9113b009..ea64f7e74b9 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.scss @@ -19,3 +19,12 @@ color: var(--ds-header-icon-color-hover); } } + +.dropdownLogin, .dropdownLogout { + &:not(:focus-visible).active, + &:not(:focus-visible):active, + &:not(:focus-visible).active:focus, + &:not(:focus-visible):active:focus { + box-shadow: unset; + } +} From 2339a559e91f7ee36f87946d0c2bb6d1e02d3ded Mon Sep 17 00:00:00 2001 From: reetagithub <51482276+reetagithub@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:39:38 +0200 Subject: [PATCH 248/282] Update fi.json5 Corrected a typo in search.view.switch.show-grid --- src/assets/i18n/fi.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/fi.json5 b/src/assets/i18n/fi.json5 index ede41ffb0c2..423099b956f 100644 --- a/src/assets/i18n/fi.json5 +++ b/src/assets/i18n/fi.json5 @@ -5746,7 +5746,7 @@ "search.view-switch.show-detail": "Näytä lisätiedot", // "search.view-switch.show-grid": "Show as grid", - "search.view-switch.show-grid": "Näydä ruudukkona", + "search.view-switch.show-grid": "Näytä ruudukkona", // "search.view-switch.show-list": "Show as list", "search.view-switch.show-list": "Näytä luettelona", From eed98960623927cd6f15ae18ac457e1858e6751f Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Mon, 11 Dec 2023 09:39:52 +0100 Subject: [PATCH 249/282] add qa breadcrumb --- .../breadcrumbs/qa-breadcrumbs.resolver.ts | 20 +++++++++++++++++++ .../breadcrumbs/qa-breadcrumbs.service.ts | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts create mode 100644 src/app/core/breadcrumbs/qa-breadcrumbs.service.ts diff --git a/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts b/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts new file mode 100644 index 00000000000..a59619d5b7b --- /dev/null +++ b/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { ItemDataService } from '../data/item-data.service'; +import {QABreadcrumbsService} from "./qa-breadcrumbs.service"; +import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from "@angular/router"; +import {BreadcrumbConfig} from "../../breadcrumbs/breadcrumb/breadcrumb-config.model"; +import {currentPathFromSnapshot} from "../../shared/utils/route.utils"; + +@Injectable({ + providedIn: 'root' +}) +export class QABreadcrumbResolver implements Resolve<BreadcrumbConfig<string>> { + constructor(protected breadcrumbService: QABreadcrumbsService, protected dataService: ItemDataService) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> { + const key = "testKey"; + const fullPath = currentPathFromSnapshot(route); + console.log(key, fullPath) + return { provider: this.breadcrumbService, key: key, url: fullPath }; + } +} diff --git a/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts b/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts new file mode 100644 index 00000000000..38601c36df1 --- /dev/null +++ b/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts @@ -0,0 +1,18 @@ +import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; +import { BreadcrumbsProviderService } from './breadcrumbsProviderService'; +import { Observable, of as observableOf } from 'rxjs'; +import { Injectable } from '@angular/core'; + + +/** + * Service to calculate QA breadcrumbs for a single part of the route + */ +@Injectable({ + providedIn: 'root' +}) +export class QABreadcrumbsService implements BreadcrumbsProviderService<string> { + + getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> { + return observableOf([new Breadcrumb(key + "test", url)]); + } +} From b9085d530613a37143577fe10b7bfdacfb74b1f7 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Mon, 11 Dec 2023 15:11:17 +0100 Subject: [PATCH 250/282] add QA breadcrumb resolver and service --- .../breadcrumbs/qa-breadcrumbs.resolver.ts | 20 ------- .../breadcrumbs/qa-breadcrumbs.service.ts | 18 ------- ...lity-assurance-breadcrumb.resolver.spec.ts | 31 +++++++++++ .../quality-assurance-breadcrumb.resolver.ts | 28 ++++++++++ ...ality-assurance-breadcrumb.service.spec.ts | 38 ++++++++++++++ .../quality-assurance-breadcrumb.service.ts | 52 +++++++++++++++++++ 6 files changed, 149 insertions(+), 38 deletions(-) delete mode 100644 src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts delete mode 100644 src/app/core/breadcrumbs/qa-breadcrumbs.service.ts create mode 100644 src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts create mode 100644 src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts create mode 100644 src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts create mode 100644 src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts diff --git a/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts b/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts deleted file mode 100644 index a59619d5b7b..00000000000 --- a/src/app/core/breadcrumbs/qa-breadcrumbs.resolver.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ItemDataService } from '../data/item-data.service'; -import {QABreadcrumbsService} from "./qa-breadcrumbs.service"; -import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from "@angular/router"; -import {BreadcrumbConfig} from "../../breadcrumbs/breadcrumb/breadcrumb-config.model"; -import {currentPathFromSnapshot} from "../../shared/utils/route.utils"; - -@Injectable({ - providedIn: 'root' -}) -export class QABreadcrumbResolver implements Resolve<BreadcrumbConfig<string>> { - constructor(protected breadcrumbService: QABreadcrumbsService, protected dataService: ItemDataService) {} - - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> { - const key = "testKey"; - const fullPath = currentPathFromSnapshot(route); - console.log(key, fullPath) - return { provider: this.breadcrumbService, key: key, url: fullPath }; - } -} diff --git a/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts b/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts deleted file mode 100644 index 38601c36df1..00000000000 --- a/src/app/core/breadcrumbs/qa-breadcrumbs.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; -import { BreadcrumbsProviderService } from './breadcrumbsProviderService'; -import { Observable, of as observableOf } from 'rxjs'; -import { Injectable } from '@angular/core'; - - -/** - * Service to calculate QA breadcrumbs for a single part of the route - */ -@Injectable({ - providedIn: 'root' -}) -export class QABreadcrumbsService implements BreadcrumbsProviderService<string> { - - getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> { - return observableOf([new Breadcrumb(key + "test", url)]); - } -} diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts new file mode 100644 index 00000000000..22f8aca7000 --- /dev/null +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts @@ -0,0 +1,31 @@ +import {QualityAssuranceBreadcrumbResolver} from './quality-assurance-breadcrumb.resolver'; + +describe('QualityAssuranceBreadcrumbResolver', () => { + describe('resolve', () => { + let resolver: QualityAssuranceBreadcrumbResolver; + let qualityAssuranceBreadcrumbService: any; + let route: any; + const fullPath = '/test/quality-assurance/'; + const expectedKey = 'testSourceId:testTopicId'; + + beforeEach(() => { + route = { + paramMap: { + get: function () { + return this; + }, + sourceId: 'testSourceId', + topicId: 'testSourceId:testTopicId' + } + }; + qualityAssuranceBreadcrumbService = {}; + resolver = new QualityAssuranceBreadcrumbResolver(qualityAssuranceBreadcrumbService); + }); + + it('should resolve the breadcrumb config', () => { + const resolvedConfig = resolver.resolve(route, {url: fullPath} as any); + const expectedConfig = { provider: qualityAssuranceBreadcrumbService, key: expectedKey, url: fullPath }; + expect(resolvedConfig).toEqual(expectedConfig); + }); + }); +}); diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts new file mode 100644 index 00000000000..fe7fb1eeb31 --- /dev/null +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import {QualityAssuranceBreadcrumbService} from './quality-assurance-breadcrumb.service'; +import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router'; +import {BreadcrumbConfig} from '../../breadcrumbs/breadcrumb/breadcrumb-config.model'; + +@Injectable({ + providedIn: 'root' +}) +export class QualityAssuranceBreadcrumbResolver implements Resolve<BreadcrumbConfig<string>> { + constructor(protected breadcrumbService: QualityAssuranceBreadcrumbService) {} + + /** + * Method that resolve QA item into a breadcrumb + * The parameter are retrieved by the url since part of the QA route config + * @param {ActivatedRouteSnapshot} route The current ActivatedRouteSnapshot + * @param {RouterStateSnapshot} state The current RouterStateSnapshot + * @returns BreadcrumbConfig object + */ + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> { + const sourceId = route.paramMap.get('sourceId'); + const topicId = route.paramMap.get('topicId'); + const key = topicId ?? sourceId; + const fullPath = state.url; + const url = fullPath.substr(0, fullPath.indexOf(sourceId)); + + return { provider: this.breadcrumbService, key, url }; + } +} diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts new file mode 100644 index 00000000000..2423de2bb0b --- /dev/null +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts @@ -0,0 +1,38 @@ +import { TestBed, waitForAsync } from '@angular/core/testing'; +import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; +import { getTestScheduler } from 'jasmine-marbles'; +import {QualityAssuranceBreadcrumbService} from './quality-assurance-breadcrumb.service'; + +describe('QualityAssuranceBreadcrumbService', () => { + let service: QualityAssuranceBreadcrumbService; + let dataService: any; + let translateService: any; + + let exampleString; + let exampleURL; + let exampleQaKey; + + function init() { + exampleString = 'sourceId'; + exampleURL = '/test/quality-assurance/'; + exampleQaKey = 'admin.quality-assurance.breadcrumbs'; + } + + beforeEach(waitForAsync(() => { + init(); + TestBed.configureTestingModule({}).compileComponents(); + })); + + beforeEach(() => { + service = new QualityAssuranceBreadcrumbService(dataService,translateService); + }); + + describe('getBreadcrumbs', () => { + it('should return a breadcrumb based on a string', () => { + const breadcrumbs = service.getBreadcrumbs(exampleString, exampleURL); + getTestScheduler().expectObservable(breadcrumbs).toBe('(a|)', { a: [new Breadcrumb(exampleQaKey, exampleURL), + new Breadcrumb(exampleString, exampleURL + exampleString)] + }); + }); + }); +}); diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts new file mode 100644 index 00000000000..514d28067ac --- /dev/null +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts @@ -0,0 +1,52 @@ +import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; +import { BreadcrumbsProviderService } from './breadcrumbsProviderService'; +import { Observable, of as observableOf } from 'rxjs'; +import { Injectable } from '@angular/core'; +import {map} from 'rxjs/operators'; +import {getFirstCompletedRemoteData} from '../shared/operators'; +import {TranslateService} from '@ngx-translate/core'; +import {QualityAssuranceTopicRestService} from "../notifications/qa/topics/quality-assurance-topic-rest.service"; + + +/** + * Service to calculate QA breadcrumbs for a single part of the route + */ +@Injectable({ + providedIn: 'root' +}) +export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderService<string> { + + private QUALITY_ASSURANCE_BREADCRUMB_KEY = 'admin.quality-assurance.breadcrumbs'; + constructor( + protected qualityAssuranceService: QualityAssuranceTopicRestService, + private translationService: TranslateService, + ) { + + } + + + /** + * Method to calculate the breadcrumbs + * @param key The key used to resolve the breadcrumb + * @param url The url to use as a link for this breadcrumb + */ + getBreadcrumbs(key: string, url: string): Observable<Breadcrumb[]> { + const sourceId = key.split(':')[0]; + const topicId = key.split(':')[1]; + + if (topicId) { + return this.qualityAssuranceService.getTopic(`${sourceId}:${topicId}`).pipe( + getFirstCompletedRemoteData(), + map((topic) => { + return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url), + new Breadcrumb(sourceId, `${url}${sourceId}`), + new Breadcrumb(topic.payload.name, undefined)]; + }) + ); + } else { + return observableOf([new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url), + new Breadcrumb(sourceId, `${url}${sourceId}`)]); + } + + } +} From b9af731d5aa4b8d47bc6d44836c065d1350f809f Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Tue, 12 Dec 2023 17:17:23 +0100 Subject: [PATCH 251/282] rename data service --- .../breadcrumbs/quality-assurance-breadcrumb.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts index 514d28067ac..9a26578f6e8 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts @@ -5,7 +5,9 @@ import { Injectable } from '@angular/core'; import {map} from 'rxjs/operators'; import {getFirstCompletedRemoteData} from '../shared/operators'; import {TranslateService} from '@ngx-translate/core'; -import {QualityAssuranceTopicRestService} from "../notifications/qa/topics/quality-assurance-topic-rest.service"; +import { + QualityAssuranceTopicDataService +} from "../suggestion-notifications/qa/topics/quality-assurance-topic-data.service"; /** @@ -18,7 +20,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer private QUALITY_ASSURANCE_BREADCRUMB_KEY = 'admin.quality-assurance.breadcrumbs'; constructor( - protected qualityAssuranceService: QualityAssuranceTopicRestService, + protected qualityAssuranceService: QualityAssuranceTopicDataService, private translationService: TranslateService, ) { From 53329cd92f2633b8a0c9aa57978b78227a04e6cf Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Wed, 13 Dec 2023 10:34:20 +0100 Subject: [PATCH 252/282] align to branch, update test --- .../admin-notifications-routing.module.ts | 10 +++++++--- .../quality-assurance-breadcrumb.resolver.spec.ts | 8 ++++---- .../quality-assurance-breadcrumb.resolver.ts | 6 +++++- .../quality-assurance-breadcrumb.service.spec.ts | 4 +++- .../quality-assurance-breadcrumb.service.ts | 4 ++-- .../qa/events/quality-assurance-events.component.html | 4 ---- 6 files changed, 21 insertions(+), 15 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 dc0d82c1d99..596780bac21 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -12,6 +12,8 @@ import { AdminQualityAssuranceEventsPageResolver } from './admin-quality-assuran 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'; +import {QualityAssuranceBreadcrumbResolver} from '../../core/breadcrumbs/quality-assurance-breadcrumb.resolver'; +import {QualityAssuranceBreadcrumbService} from '../../core/breadcrumbs/quality-assurance-breadcrumb.service'; @NgModule({ imports: [ @@ -22,7 +24,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon component: AdminQualityAssuranceTopicsPageComponent, pathMatch: 'full', resolve: { - breadcrumb: I18nBreadcrumbResolver, + breadcrumb: QualityAssuranceBreadcrumbResolver, openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver }, data: { @@ -53,7 +55,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon component: AdminQualityAssuranceEventsPageComponent, pathMatch: 'full', resolve: { - breadcrumb: I18nBreadcrumbResolver, + breadcrumb: QualityAssuranceBreadcrumbResolver, openaireQualityAssuranceEventsParams: AdminQualityAssuranceEventsPageResolver }, data: { @@ -70,7 +72,9 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon SourceDataResolver, AdminQualityAssuranceTopicsPageResolver, AdminQualityAssuranceEventsPageResolver, - AdminQualityAssuranceSourcePageResolver + AdminQualityAssuranceSourcePageResolver, + QualityAssuranceBreadcrumbResolver, + QualityAssuranceBreadcrumbService ] }) /** diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts index 22f8aca7000..de676f4cc30 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts @@ -11,11 +11,11 @@ describe('QualityAssuranceBreadcrumbResolver', () => { beforeEach(() => { route = { paramMap: { - get: function () { - return this; + get: function (param) { + return this[param] }, sourceId: 'testSourceId', - topicId: 'testSourceId:testTopicId' + topicId: 'testTopicId' } }; qualityAssuranceBreadcrumbService = {}; @@ -23,7 +23,7 @@ describe('QualityAssuranceBreadcrumbResolver', () => { }); it('should resolve the breadcrumb config', () => { - const resolvedConfig = resolver.resolve(route, {url: fullPath} as any); + const resolvedConfig = resolver.resolve(route as any, {url: fullPath + 'testSourceId'} as any); const expectedConfig = { provider: qualityAssuranceBreadcrumbService, key: expectedKey, url: fullPath }; expect(resolvedConfig).toEqual(expectedConfig); }); diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts index fe7fb1eeb31..6eb351ab1ab 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.ts @@ -19,7 +19,11 @@ export class QualityAssuranceBreadcrumbResolver implements Resolve<BreadcrumbCon resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): BreadcrumbConfig<string> { const sourceId = route.paramMap.get('sourceId'); const topicId = route.paramMap.get('topicId'); - const key = topicId ?? sourceId; + let key = sourceId; + + if (topicId) { + key += `:${topicId}`; + } const fullPath = state.url; const url = fullPath.substr(0, fullPath.indexOf(sourceId)); diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts index 2423de2bb0b..4fef7672147 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.spec.ts @@ -6,7 +6,9 @@ import {QualityAssuranceBreadcrumbService} from './quality-assurance-breadcrumb. describe('QualityAssuranceBreadcrumbService', () => { let service: QualityAssuranceBreadcrumbService; let dataService: any; - let translateService: any; + let translateService: any = { + instant: (str) => str, + }; let exampleString; let exampleURL; diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts index 9a26578f6e8..343ccbcc76e 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts @@ -7,7 +7,7 @@ import {getFirstCompletedRemoteData} from '../shared/operators'; import {TranslateService} from '@ngx-translate/core'; import { QualityAssuranceTopicDataService -} from "../suggestion-notifications/qa/topics/quality-assurance-topic-data.service"; +} from '../suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; /** @@ -37,7 +37,7 @@ export class QualityAssuranceBreadcrumbService implements BreadcrumbsProviderSer const topicId = key.split(':')[1]; if (topicId) { - return this.qualityAssuranceService.getTopic(`${sourceId}:${topicId}`).pipe( + return this.qualityAssuranceService.getTopic(topicId).pipe( getFirstCompletedRemoteData(), map((topic) => { return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url), diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html index 7f1b166d24c..9e60f1fd252 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html @@ -4,10 +4,6 @@ <h2 class="border-bottom pb-2"> <div class="d-flex justify-content-between"> {{'notifications.events.title'| translate}} - <a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']"> - <i class="fas fa-angle-double-left"></i> - {{'quality-assurance.events.back' | translate}} - </a> </div> </h2> <ds-alert [type]="'alert-info'" [content]="'quality-assurance.events.description'"></ds-alert> From 78df2362c93cd0960530cdd801b97efd1fd3ae52 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Wed, 13 Dec 2023 10:45:20 +0100 Subject: [PATCH 253/282] add accessibility text --- .../quality-assurance-events.component.html | 24 ++++++++++++++----- src/assets/i18n/en.json5 | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html index 7f1b166d24c..de80baa1c0c 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html @@ -101,13 +101,17 @@ <h4 class="border-bottom pb-2"> <button *ngIf="!eventElement.hasProject" class="btn btn-outline-primary btn-sm" [disabled]="eventElement.isRunning" - (click)="openModalLookup(eventElement); $event.stopPropagation();"> + (click)="openModalLookup(eventElement); $event.stopPropagation();" + [attr.aria-label]="'quality-assurance.event.modal.project.select' | translate" + > <i class="fas fa-search"></i> </button> <button *ngIf="eventElement.hasProject" class="btn btn-outline-danger btn-sm" [disabled]="eventElement.isRunning" - (click)="removeProject(eventElement)"> + (click)="removeProject(eventElement)" + [attr.aria-label]="'quality-assurance.event.modal.project.remove' | translate" + > <i class="fas fa-trash-alt"></i> </button> </div> @@ -120,7 +124,9 @@ <h4 class="border-bottom pb-2"> ngbTooltip="{{'quality-assurance.event.action.import' | translate}}" container="body" [disabled]="eventElement.isRunning" - (click)="modalChoice('ACCEPTED', eventElement, acceptModal)"> + (click)="modalChoice('ACCEPTED', eventElement, acceptModal)" + [attr.aria-label]="'quality-assurance.event.action.import' | translate" + > <i class="fas fa-check"></i> </button> <button *ngIf="showTopic.indexOf('/PROJECT') == -1" @@ -128,21 +134,27 @@ <h4 class="border-bottom pb-2"> ngbTooltip="{{'quality-assurance.event.action.accept' | translate}}" container="body" [disabled]="eventElement.isRunning" - (click)="executeAction('ACCEPTED', eventElement)"> + (click)="executeAction('ACCEPTED', eventElement)" + [attr.aria-label]="'quality-assurance.event.action.accept' | translate" + > <i class="fas fa-check"></i> </button> <button class="btn btn-outline-dark btn-sm button-width" ngbTooltip="{{'quality-assurance.event.action.ignore' | translate}}" container="body" [disabled]="eventElement.isRunning" - (click)="openModal('DISCARDED', eventElement, ignoreModal)"> + (click)="openModal('DISCARDED', eventElement, ignoreModal)" + [attr.aria-label]="'quality-assurance.event.action.ignore' | translate" + > <i class="fas fa-ban"></i> </button> <button class="btn btn-outline-danger btn-sm button-width" ngbTooltip="{{'quality-assurance.event.action.reject' | translate}}" container="body" [disabled]="eventElement.isRunning" - (click)="openModal('REJECTED', eventElement, rejectModal)"> + (click)="openModal('REJECTED', eventElement, rejectModal)" + [attr.aria-label]="'quality-assurance.event.action.reject' | translate" + > <i class="fas fa-trash-alt"></i> </button> </div> diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 4c13ec73d14..ac09fe4167e 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -3206,6 +3206,8 @@ "quality-assurance.event.modal.project.bound": "Bound project", + "quality-assurance.event.modal.project.remove": "Remove", + "quality-assurance.event.modal.project.placeholder": "Enter a project name", "quality-assurance.event.modal.project.notFound": "No project found.", From 922172d9aef30d4a84afa467cb9e2d1c04e772c5 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Wed, 13 Dec 2023 11:55:10 +0100 Subject: [PATCH 254/282] refactor, improve code according to suggestions --- .../admin-notifications-routing.module.ts | 2 +- .../admin-notifications.module.ts | 4 +-- ...quality-assurance-source-data.resolver.ts} | 4 +-- src/app/core/core.module.ts | 6 ++-- ...ality-assurance-event-data.service.spec.ts | 0 .../quality-assurance-event-data.service.ts | 0 ...ty-assurance-event-object.resource-type.ts | 0 .../models/quality-assurance-event.model.ts | 0 ...y-assurance-source-object.resource-type.ts | 0 .../models/quality-assurance-source.model.ts | 0 ...ty-assurance-topic-object.resource-type.ts | 0 .../models/quality-assurance-topic.model.ts | 0 ...lity-assurance-source-data.service.spec.ts | 0 .../quality-assurance-source-data.service.ts | 0 ...ality-assurance-topic-data.service.spec.ts | 0 .../quality-assurance-topic-data.service.ts | 0 .../notifications-effects.ts} | 2 +- .../notifications-state.service.spec.ts} | 30 ++++++++-------- .../notifications-state.service.ts} | 8 ++--- .../notifications.module.ts} | 18 +++++----- .../notifications.reducer.ts} | 0 .../quality-assurance-events.component.html | 7 ++-- .../quality-assurance-events.component.scss | 0 ...quality-assurance-events.component.spec.ts | 4 +-- .../quality-assurance-events.component.ts | 8 +++-- .../project-entry-import-modal.component.html | 4 +-- .../project-entry-import-modal.component.scss | 0 ...oject-entry-import-modal.component.spec.ts | 0 .../project-entry-import-modal.component.ts | 2 +- .../quality-assurance-source.actions.ts | 8 ++--- .../quality-assurance-source.component.html | 0 .../quality-assurance-source.component.scss | 0 ...quality-assurance-source.component.spec.ts | 4 +-- .../quality-assurance-source.component.ts | 8 ++--- .../quality-assurance-source.effects.ts | 4 +-- .../quality-assurance-source.reducer.spec.ts | 0 .../quality-assurance-source.reducer.ts | 2 +- .../quality-assurance-source.service.spec.ts | 2 +- .../quality-assurance-source.service.ts | 4 +-- .../quality-assurance-topics.actions.ts | 8 ++--- .../quality-assurance-topics.component.html | 0 .../quality-assurance-topics.component.scss | 0 ...quality-assurance-topics.component.spec.ts | 4 +-- .../quality-assurance-topics.component.ts | 8 ++--- .../quality-assurance-topics.effects.ts | 4 +-- .../quality-assurance-topics.reducer.spec.ts | 0 .../quality-assurance-topics.reducer.ts | 2 +- .../quality-assurance-topics.service.spec.ts | 2 +- .../quality-assurance-topics.service.ts | 4 +-- .../selectors.ts | 6 ++-- src/app/shared/mocks/notifications.mock.ts | 34 +++++++++---------- 51 files changed, 104 insertions(+), 99 deletions(-) rename src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/{admin-quality-assurance-source-data.reslover.ts => admin-quality-assurance-source-data.resolver.ts} (87%) rename src/app/core/{suggestion-notifications => notifications}/qa/events/quality-assurance-event-data.service.spec.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/events/quality-assurance-event-data.service.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-event-object.resource-type.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-event.model.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-source-object.resource-type.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-source.model.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-topic-object.resource-type.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/models/quality-assurance-topic.model.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/source/quality-assurance-source-data.service.spec.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/source/quality-assurance-source-data.service.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topic-data.service.spec.ts (100%) rename src/app/core/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topic-data.service.ts (100%) rename src/app/{suggestion-notifications/suggestion-notifications-effects.ts => notifications/notifications-effects.ts} (84%) rename src/app/{suggestion-notifications/suggestion-notifications-state.service.spec.ts => notifications/notifications-state.service.spec.ts} (93%) rename src/app/{suggestion-notifications/suggestion-notifications-state.service.ts => notifications/notifications-state.service.ts} (95%) rename src/app/{suggestion-notifications/suggestion-notifications.module.ts => notifications/notifications.module.ts} (78%) rename src/app/{suggestion-notifications/suggestion-notifications.reducer.ts => notifications/notifications.reducer.ts} (100%) rename src/app/{suggestion-notifications => notifications}/qa/events/quality-assurance-events.component.html (96%) rename src/app/{suggestion-notifications => notifications}/qa/events/quality-assurance-events.component.scss (100%) rename src/app/{suggestion-notifications => notifications}/qa/events/quality-assurance-events.component.spec.ts (98%) rename src/app/{suggestion-notifications => notifications}/qa/events/quality-assurance-events.component.ts (98%) rename src/app/{suggestion-notifications => notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.html (94%) rename src/app/{suggestion-notifications => notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.scss (100%) rename src/app/{suggestion-notifications => notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts (100%) rename src/app/{suggestion-notifications => notifications}/qa/project-entry-import-modal/project-entry-import-modal.component.ts (98%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.actions.ts (85%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.component.html (100%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.component.scss (100%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.component.spec.ts (96%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.component.ts (92%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.effects.ts (94%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.reducer.spec.ts (100%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.reducer.ts (93%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.service.spec.ts (96%) rename src/app/{suggestion-notifications => notifications}/qa/source/quality-assurance-source.service.ts (91%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.actions.ts (84%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.component.html (100%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.component.scss (100%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.component.spec.ts (96%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.component.ts (93%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.effects.ts (94%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.reducer.spec.ts (100%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.reducer.ts (93%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.service.spec.ts (96%) rename src/app/{suggestion-notifications => notifications}/qa/topics/quality-assurance-topics.service.ts (92%) rename src/app/{suggestion-notifications => notifications}/selectors.ts (95%) 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 dc0d82c1d99..de12a48ade3 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -11,7 +11,7 @@ import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assuran 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'; +import { SourceDataResolver } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver'; @NgModule({ imports: [ diff --git a/src/app/admin/admin-notifications/admin-notifications.module.ts b/src/app/admin/admin-notifications/admin-notifications.module.ts index 159baedfecc..84475a1623e 100644 --- a/src/app/admin/admin-notifications/admin-notifications.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications.module.ts @@ -6,7 +6,7 @@ import { AdminNotificationsRoutingModule } from './admin-notifications-routing.m 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 { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component'; -import {SuggestionNotificationsModule} from '../../suggestion-notifications/suggestion-notifications.module'; +import {NotificationsModule} from '../../notifications/notifications.module'; @NgModule({ imports: [ @@ -14,7 +14,7 @@ import {SuggestionNotificationsModule} from '../../suggestion-notifications/sugg SharedModule, CoreModule.forRoot(), AdminNotificationsRoutingModule, - SuggestionNotificationsModule + NotificationsModule ], declarations: [ AdminQualityAssuranceTopicsPageComponent, diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts similarity index 87% rename from src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts rename to src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts index 8475732aeda..6201e0a7435 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.reslover.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts @@ -3,8 +3,8 @@ 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 { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; -import { QualityAssuranceSourceService } from '../../../suggestion-notifications/qa/source/quality-assurance-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. */ diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index e176af7d550..b3abf5f877e 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -157,9 +157,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 { QualityAssuranceTopicObject } from './suggestion-notifications/qa/models/quality-assurance-topic.model'; -import { QualityAssuranceEventObject } from './suggestion-notifications/qa/models/quality-assurance-event.model'; -import { QualityAssuranceSourceObject } from './suggestion-notifications/qa/models/quality-assurance-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 { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model'; import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model'; import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model'; diff --git a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.spec.ts b/src/app/core/notifications/qa/events/quality-assurance-event-data.service.spec.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.spec.ts rename to src/app/core/notifications/qa/events/quality-assurance-event-data.service.spec.ts diff --git a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts b/src/app/core/notifications/qa/events/quality-assurance-event-data.service.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts rename to src/app/core/notifications/qa/events/quality-assurance-event-data.service.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-event-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-event-object.resource-type.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-event.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-event.model.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-source-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-source-object.resource-type.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model.ts b/src/app/core/notifications/qa/models/quality-assurance-source.model.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-source.model.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts b/src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-topic-object.resource-type.ts rename to src/app/core/notifications/qa/models/quality-assurance-topic-object.resource-type.ts diff --git a/src/app/core/suggestion-notifications/qa/models/quality-assurance-topic.model.ts b/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/models/quality-assurance-topic.model.ts rename to src/app/core/notifications/qa/models/quality-assurance-topic.model.ts diff --git a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.spec.ts b/src/app/core/notifications/qa/source/quality-assurance-source-data.service.spec.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.spec.ts rename to src/app/core/notifications/qa/source/quality-assurance-source-data.service.spec.ts diff --git a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts b/src/app/core/notifications/qa/source/quality-assurance-source-data.service.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts rename to src/app/core/notifications/qa/source/quality-assurance-source-data.service.ts diff --git a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.spec.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-data.service.spec.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.spec.ts rename to src/app/core/notifications/qa/topics/quality-assurance-topic-data.service.spec.ts diff --git a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts b/src/app/core/notifications/qa/topics/quality-assurance-topic-data.service.ts similarity index 100% rename from src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts rename to src/app/core/notifications/qa/topics/quality-assurance-topic-data.service.ts diff --git a/src/app/suggestion-notifications/suggestion-notifications-effects.ts b/src/app/notifications/notifications-effects.ts similarity index 84% rename from src/app/suggestion-notifications/suggestion-notifications-effects.ts rename to src/app/notifications/notifications-effects.ts index ac5d9f8f928..bf70a058554 100644 --- a/src/app/suggestion-notifications/suggestion-notifications-effects.ts +++ b/src/app/notifications/notifications-effects.ts @@ -1,7 +1,7 @@ import { QualityAssuranceSourceEffects } from './qa/source/quality-assurance-source.effects'; import { QualityAssuranceTopicsEffects } from './qa/topics/quality-assurance-topics.effects'; -export const suggestionNotificationsEffects = [ +export const notificationsEffects = [ QualityAssuranceTopicsEffects, QualityAssuranceSourceEffects ]; diff --git a/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts b/src/app/notifications/notifications-state.service.spec.ts similarity index 93% rename from src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts rename to src/app/notifications/notifications-state.service.spec.ts index ac669ed9548..f07b4f56970 100644 --- a/src/app/suggestion-notifications/suggestion-notifications-state.service.spec.ts +++ b/src/app/notifications/notifications-state.service.spec.ts @@ -2,8 +2,8 @@ import { TestBed } from '@angular/core/testing'; import { Store, StoreModule } from '@ngrx/store'; import { provideMockStore } from '@ngrx/store/testing'; import { cold } from 'jasmine-marbles'; -import { suggestionNotificationsReducers } from './suggestion-notifications.reducer'; -import { SuggestionNotificationsStateService } from './suggestion-notifications-state.service'; +import { suggestionNotificationsReducers } from './notifications.reducer'; +import { NotificationsStateService } from './notifications-state.service'; import { qualityAssuranceSourceObjectMissingPid, qualityAssuranceSourceObjectMoreAbstract, @@ -16,7 +16,7 @@ import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.ac import { RetrieveAllSourceAction } from './qa/source/quality-assurance-source.actions'; describe('NotificationsStateService', () => { - let service: SuggestionNotificationsStateService; + let service: NotificationsStateService; let serviceAsAny: any; let store: any; let initialState: any; @@ -67,14 +67,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -159,14 +159,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -255,14 +255,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -325,14 +325,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -417,14 +417,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); @@ -513,14 +513,14 @@ describe('NotificationsStateService', () => { ], providers: [ provideMockStore({ initialState }), - { provide: SuggestionNotificationsStateService, useValue: service } + { provide: NotificationsStateService, useValue: service } ] }).compileComponents(); }); beforeEach(() => { store = TestBed.get(Store); - service = new SuggestionNotificationsStateService(store); + service = new NotificationsStateService(store); serviceAsAny = service; spyOn(store, 'dispatch'); }); diff --git a/src/app/suggestion-notifications/suggestion-notifications-state.service.ts b/src/app/notifications/notifications-state.service.ts similarity index 95% rename from src/app/suggestion-notifications/suggestion-notifications-state.service.ts rename to src/app/notifications/notifications-state.service.ts index ec1ea2e0394..c123cfa3047 100644 --- a/src/app/suggestion-notifications/suggestion-notifications-state.service.ts +++ b/src/app/notifications/notifications-state.service.ts @@ -16,17 +16,17 @@ import { getQualityAssuranceSourceCurrentPageSelector, getQualityAssuranceSourceTotalsSelector } from './selectors'; -import { QualityAssuranceTopicObject } from '../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; -import { SuggestionNotificationsState } from './suggestion-notifications.reducer'; +import { QualityAssuranceTopicObject } from '../core/notifications/qa/models/quality-assurance-topic.model'; +import { SuggestionNotificationsState } from './notifications.reducer'; import { RetrieveAllTopicsAction } from './qa/topics/quality-assurance-topics.actions'; -import { QualityAssuranceSourceObject } from '../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +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. */ @Injectable() -export class SuggestionNotificationsStateService { +export class NotificationsStateService { /** * Initialize the service variables. diff --git a/src/app/suggestion-notifications/suggestion-notifications.module.ts b/src/app/notifications/notifications.module.ts similarity index 78% rename from src/app/suggestion-notifications/suggestion-notifications.module.ts rename to src/app/notifications/notifications.module.ts index eac527d6726..7003ed3cc86 100644 --- a/src/app/suggestion-notifications/suggestion-notifications.module.ts +++ b/src/app/notifications/notifications.module.ts @@ -8,16 +8,16 @@ import { SharedModule } from '../shared/shared.module'; import { storeModuleConfig } from '../app.reducer'; import { QualityAssuranceTopicsComponent } from './qa/topics/quality-assurance-topics.component'; import { QualityAssuranceEventsComponent } from './qa/events/quality-assurance-events.component'; -import { SuggestionNotificationsStateService } from './suggestion-notifications-state.service'; -import { suggestionNotificationsReducers, SuggestionNotificationsState } from './suggestion-notifications.reducer'; -import { suggestionNotificationsEffects } from './suggestion-notifications-effects'; +import { NotificationsStateService } from './notifications-state.service'; +import { suggestionNotificationsReducers, SuggestionNotificationsState } from './notifications.reducer'; +import { notificationsEffects } from './notifications-effects'; import { QualityAssuranceTopicsService } from './qa/topics/quality-assurance-topics.service'; import { QualityAssuranceTopicDataService -} from '../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +} from '../core/notifications/qa/topics/quality-assurance-topic-data.service'; import { QualityAssuranceEventDataService -} from '../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; +} from '../core/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'; @@ -25,7 +25,7 @@ import { QualityAssuranceSourceComponent } from './qa/source/quality-assurance-s import { QualityAssuranceSourceService } from './qa/source/quality-assurance-source.service'; import { QualityAssuranceSourceDataService -} from '../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +} from '../core/notifications/qa/source/quality-assurance-source-data.service'; const MODULES = [ CommonModule, @@ -33,7 +33,7 @@ const MODULES = [ SearchModule, CoreModule.forRoot(), StoreModule.forFeature('suggestionNotifications', suggestionNotificationsReducers, storeModuleConfig as StoreConfig<SuggestionNotificationsState, Action>), - EffectsModule.forFeature(suggestionNotificationsEffects), + EffectsModule.forFeature(notificationsEffects), TranslateModule ]; @@ -50,7 +50,7 @@ const ENTRY_COMPONENTS = [ ]; const PROVIDERS = [ - SuggestionNotificationsStateService, + NotificationsStateService, QualityAssuranceTopicsService, QualityAssuranceSourceService, QualityAssuranceTopicDataService, @@ -82,5 +82,5 @@ const PROVIDERS = [ /** * This module handles all components that are necessary for the OpenAIRE components */ -export class SuggestionNotificationsModule { +export class NotificationsModule { } diff --git a/src/app/suggestion-notifications/suggestion-notifications.reducer.ts b/src/app/notifications/notifications.reducer.ts similarity index 100% rename from src/app/suggestion-notifications/suggestion-notifications.reducer.ts rename to src/app/notifications/notifications.reducer.ts diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html b/src/app/notifications/qa/events/quality-assurance-events.component.html similarity index 96% rename from src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html rename to src/app/notifications/qa/events/quality-assurance-events.component.html index 7f1b166d24c..d6bd828ed43 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/notifications/qa/events/quality-assurance-events.component.html @@ -52,13 +52,14 @@ <h4 class="border-bottom pb-2"> </td> <td><a *ngIf="eventElement?.target" target="_blank" + rel="noopener noreferrer" [routerLink]="['/items', eventElement?.target?.id]">{{eventElement.title}}</a> <span *ngIf="!eventElement?.target">{{eventElement.title}}</span> </td> <td *ngIf="showTopic.indexOf('/PID') !== -1"> <p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p> <p><span class="small">{{'quality-assurance.event.table.pidvalue' | translate}}</span><br> - <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" target="_blank"> + <a *ngIf="hasPIDHref(eventElement.event.message); else noPID" href="{{getPIDHref(eventElement.event.message)}}" rel="noopener noreferrer" target="_blank"> {{eventElement.event.message.value}} </a> <ng-template #noPID><span class="badge badge-info">{{eventElement.event.message.value}}</span></ng-template> @@ -84,7 +85,7 @@ <h4 class="border-bottom pb-2"> </p> <p> <span class="small">{{'quality-assurance.event.table.project' | translate}}</span><br> - <a href="https://explore.openaire.eu/search/project?projectId={{ eventElement.event.message.openaireId}}" target="_blank">{{eventElement.event.message.title}}</a> + <a href="{{openAireUrl}}{{ eventElement.event.message.openaireId}}" rel="noopener noreferrer" target="_blank">{{eventElement.event.message.title}}</a> </p> <p> <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'quality-assurance.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> @@ -96,7 +97,7 @@ <h4 class="border-bottom pb-2"> <hr> <div> {{(eventElement.hasProject ? 'quality-assurance.event.project.found' : 'quality-assurance.event.project.notFound') | translate}} - <a target="_blank" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}} </a> + <a target="_blank" rel="noopener noreferrer" *ngIf="eventElement.hasProject" title="{{eventElement.projectTitle}}" [routerLink]="['/items', eventElement.projectId]">{{eventElement.handle}} </a> <div class="btn-group"> <button *ngIf="!eventElement.hasProject" class="btn btn-outline-primary btn-sm" diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss b/src/app/notifications/qa/events/quality-assurance-events.component.scss similarity index 100% rename from src/app/suggestion-notifications/qa/events/quality-assurance-events.component.scss rename to src/app/notifications/qa/events/quality-assurance-events.component.scss diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts b/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts similarity index 98% rename from src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts rename to src/app/notifications/qa/events/quality-assurance-events.component.spec.ts index 04ece87fbb3..3349dd3154d 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.spec.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.spec.ts @@ -7,7 +7,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { of as observableOf } from 'rxjs'; import { QualityAssuranceEventDataService -} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; +} from '../../../core/notifications/qa/events/quality-assurance-event-data.service'; import { QualityAssuranceEventsComponent } from './quality-assurance-events.component'; import { getMockQualityAssuranceEventRestService, @@ -26,7 +26,7 @@ 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'; +} 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 { cold, getTestScheduler } from 'jasmine-marbles'; diff --git a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts b/src/app/notifications/qa/events/quality-assurance-events.component.ts similarity index 98% rename from src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts rename to src/app/notifications/qa/events/quality-assurance-events.component.ts index e34c121f359..a0e328538e1 100644 --- a/src/app/suggestion-notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -12,10 +12,10 @@ import { RemoteData } from '../../../core/data/remote-data'; import { OpenaireQualityAssuranceEventMessageObject, QualityAssuranceEventObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; +} from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceEventDataService -} from '../../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; +} from '../../../core/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'; @@ -95,6 +95,10 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * @type {boolean} */ public showMore = false; + /** + * The Open Aire base url for project search + */ + public openAireUrl = 'https://explore.openaire.eu/search/project?projectId='; /** * The FindListOptions object */ diff --git a/src/app/suggestion-notifications/qa/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 94% rename from src/app/suggestion-notifications/qa/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 index 42eb7e4b16a..0622e08ab09 100644 --- a/src/app/suggestion-notifications/qa/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 @@ -9,7 +9,7 @@ <h4 class="modal-title" id="modal-title">{{ (labelPrefix + label + '.title') | t <small>{{ (labelPrefix + label + '.publication' | translate) }}</small> <div class="mb-3"> <div class="text-truncate"> - <a target="_blank" href="/items/{{(externalSourceEntry.event.target|async)?.payload?.id}}"> + <a target="_blank" [routerLink]="'/items/{{(externalSourceEntry.event.target|async)?.payload?.id}}'"> {{externalSourceEntry.title}} </a> </div> @@ -18,7 +18,7 @@ <h4 class="modal-title" id="modal-title">{{ (labelPrefix + label + '.title') | t <small>{{ (labelPrefix + label + '.bountToLocal' |translate) }}</small> <div class="mb-3"> <div class="text-truncate"> - <a target="_blank" href="/items/{{externalSourceEntry.projectId}}"> + <a target="_blank" [routerLink]="'/items/{{externalSourceEntry.projectId}}'"> {{externalSourceEntry.projectTitle}} </a> </div> diff --git a/src/app/suggestion-notifications/qa/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/suggestion-notifications/qa/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/suggestion-notifications/qa/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 100% rename from src/app/suggestion-notifications/qa/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 diff --git a/src/app/suggestion-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 similarity index 98% rename from src/app/suggestion-notifications/qa/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 1a43f59a1fc..6872baeb90b 100644 --- a/src/app/suggestion-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 { OpenaireQualityAssuranceEventMessageObject, QualityAssuranceEventObject, -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-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'; diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts b/src/app/notifications/qa/source/quality-assurance-source.actions.ts similarity index 85% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts rename to src/app/notifications/qa/source/quality-assurance-source.actions.ts index 06db9dda06c..f6d9c19eaaf 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.actions.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.actions.ts @@ -1,7 +1,7 @@ /* eslint-disable max-classes-per-file */ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; /** * For each action type in an action group, make a simple @@ -12,9 +12,9 @@ import { QualityAssuranceSourceObject } from '../../../core/suggestion-notificat * action types in the application are unique. */ export const QualityAssuranceSourceActionTypes = { - ADD_SOURCE: type('dspace/integration/suggestion-notifications/qa/ADD_SOURCE'), - RETRIEVE_ALL_SOURCE: type('dspace/integration/suggestion-notifications/qa/RETRIEVE_ALL_SOURCE'), - RETRIEVE_ALL_SOURCE_ERROR: type('dspace/integration/suggestion-notifications/qa/RETRIEVE_ALL_SOURCE_ERROR'), + 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'), }; /** diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html b/src/app/notifications/qa/source/quality-assurance-source.component.html similarity index 100% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.component.html rename to src/app/notifications/qa/source/quality-assurance-source.component.html diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.scss b/src/app/notifications/qa/source/quality-assurance-source.component.scss similarity index 100% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.component.scss rename to src/app/notifications/qa/source/quality-assurance-source.component.scss diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts similarity index 96% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.component.spec.ts index 2f588125b28..ba3a903cc5e 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts @@ -11,7 +11,7 @@ import { qualityAssuranceSourceObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceSourceComponent } from './quality-assurance-source.component'; -import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; +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'; @@ -40,7 +40,7 @@ describe('QualityAssuranceSourceComponent test suite', () => { TestComponent, ], providers: [ - { provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService }, + { provide: NotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), params: observableOf({}) } }, { provide: PaginationService, useValue: paginationService }, QualityAssuranceSourceComponent diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts b/src/app/notifications/qa/source/quality-assurance-source.component.ts similarity index 92% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts rename to src/app/notifications/qa/source/quality-assurance-source.component.ts index f6f02d9ab97..aef56d09c71 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.component.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.ts @@ -3,9 +3,9 @@ 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 { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; -import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; +import { NotificationsStateService } from '../../notifications-state.service'; import { AdminQualityAssuranceSourcePageParams } from '../../../admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-page-resolver.service'; import { hasValue } from '../../../shared/empty.util'; @@ -50,11 +50,11 @@ export class QualityAssuranceSourceComponent implements OnInit { /** * Initialize the component variables. * @param {PaginationService} paginationService - * @param {SuggestionNotificationsStateService} notificationsStateService + * @param {NotificationsStateService} notificationsStateService */ constructor( private paginationService: PaginationService, - private notificationsStateService: SuggestionNotificationsStateService, + private notificationsStateService: NotificationsStateService, ) { } /** diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts b/src/app/notifications/qa/source/quality-assurance-source.effects.ts similarity index 94% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts rename to src/app/notifications/qa/source/quality-assurance-source.effects.ts index fd78911ab4d..bd85fb18a07 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.effects.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.effects.ts @@ -14,13 +14,13 @@ import { } from './quality-assurance-source.actions'; import { QualityAssuranceSourceObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +} from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceSourceService } from './quality-assurance-source.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { QualityAssuranceSourceDataService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +} from '../../../core/notifications/qa/source/quality-assurance-source-data.service'; /** * Provides effect methods for the Quality Assurance source actions. diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts similarity index 100% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.reducer.spec.ts diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts b/src/app/notifications/qa/source/quality-assurance-source.reducer.ts similarity index 93% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts rename to src/app/notifications/qa/source/quality-assurance-source.reducer.ts index d83a0e43416..08e26a177ac 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.reducer.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.reducer.ts @@ -1,4 +1,4 @@ -import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { QualityAssuranceSourceActionTypes, QualityAssuranceSourceActions } from './quality-assurance-source.actions'; /** diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts similarity index 96% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts rename to src/app/notifications/qa/source/quality-assurance-source.service.spec.ts index 745a2baef78..5ce2ed8ee02 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.service.spec.ts @@ -13,7 +13,7 @@ import { cold } from 'jasmine-marbles'; import { buildPaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceSourceDataService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +} from '../../../core/notifications/qa/source/quality-assurance-source-data.service'; import { FindListOptions } from '../../../core/data/find-list-options.model'; describe('QualityAssuranceSourceService', () => { diff --git a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts b/src/app/notifications/qa/source/quality-assurance-source.service.ts similarity index 91% rename from src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts rename to src/app/notifications/qa/source/quality-assurance-source.service.ts index 5c16fb1a03d..ea0cb2e5c51 100644 --- a/src/app/suggestion-notifications/qa/source/quality-assurance-source.service.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.service.ts @@ -5,13 +5,13 @@ import { map } from 'rxjs/operators'; import { QualityAssuranceSourceDataService -} from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +} from '../../../core/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'; import { QualityAssuranceSourceObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +} from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { FindListOptions } from '../../../core/data/find-list-options.model'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts b/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts similarity index 84% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.actions.ts index 2459d4352ab..6b83b1d349c 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.actions.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.actions.ts @@ -1,7 +1,7 @@ /* eslint-disable max-classes-per-file */ import { Action } from '@ngrx/store'; import { type } from '../../../shared/ngrx/type'; -import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; /** * For each action type in an action group, make a simple @@ -12,9 +12,9 @@ import { QualityAssuranceTopicObject } from '../../../core/suggestion-notificati * action types in the application are unique. */ export const QualityAssuranceTopicActionTypes = { - ADD_TOPICS: type('dspace/integration/suggestion-notifications/qa/topic/ADD_TOPICS'), - RETRIEVE_ALL_TOPICS: type('dspace/integration/suggestion-notifications/qa/topic/RETRIEVE_ALL_TOPICS'), - RETRIEVE_ALL_TOPICS_ERROR: type('dspace/integration/suggestion-notifications/qa/topic/RETRIEVE_ALL_TOPICS_ERROR'), + 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'), }; /** diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html b/src/app/notifications/qa/topics/quality-assurance-topics.component.html similarity index 100% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.html rename to src/app/notifications/qa/topics/quality-assurance-topics.component.html diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.scss b/src/app/notifications/qa/topics/quality-assurance-topics.component.scss similarity index 100% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.scss rename to src/app/notifications/qa/topics/quality-assurance-topics.component.scss diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts similarity index 96% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts index c80d2bce20b..fd64b82ce7d 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts @@ -12,7 +12,7 @@ import { qualityAssuranceTopicObjectMorePid } from '../../../shared/mocks/notifications.mock'; import { QualityAssuranceTopicsComponent } from './quality-assurance-topics.component'; -import { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; +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'; @@ -42,7 +42,7 @@ describe('QualityAssuranceTopicsComponent test suite', () => { TestComponent, ], providers: [ - { provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService }, + { provide: NotificationsStateService, useValue: mockNotificationsStateService }, { provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), snapshot: { paramMap: { get: () => 'openaire', diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts similarity index 93% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.component.ts index 3c8b4f8f38a..542d36a9ed1 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts @@ -6,10 +6,10 @@ import { distinctUntilChanged, take } from 'rxjs/operators'; import { SortOptions } from '../../../core/cache/models/sort-options.model'; import { QualityAssuranceTopicObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +} 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 { SuggestionNotificationsStateService } from '../../suggestion-notifications-state.service'; +import { NotificationsStateService } from '../../notifications-state.service'; import { AdminQualityAssuranceTopicsPageParams } from '../../../admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service'; @@ -64,13 +64,13 @@ export class QualityAssuranceTopicsComponent implements OnInit { * Initialize the component variables. * @param {PaginationService} paginationService * @param {ActivatedRoute} activatedRoute - * @param {SuggestionNotificationsStateService} notificationsStateService + * @param {NotificationsStateService} notificationsStateService * @param {QualityAssuranceTopicsService} qualityAssuranceTopicsService */ constructor( private paginationService: PaginationService, private activatedRoute: ActivatedRoute, - private notificationsStateService: SuggestionNotificationsStateService, + private notificationsStateService: NotificationsStateService, private qualityAssuranceTopicsService: QualityAssuranceTopicsService ) { } diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts similarity index 94% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.effects.ts index 13e36700001..a7b4dddd629 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.effects.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.effects.ts @@ -14,13 +14,13 @@ import { } from './quality-assurance-topics.actions'; import { QualityAssuranceTopicObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +} from '../../../core/notifications/qa/models/quality-assurance-topic.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceTopicsService } from './quality-assurance-topics.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { QualityAssuranceTopicDataService -} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +} from '../../../core/notifications/qa/topics/quality-assurance-topic-data.service'; /** * Provides effect methods for the Quality Assurance topics actions. diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts similarity index 100% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.reducer.spec.ts diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts similarity index 93% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts index 355ace977d2..ff94f1b8bb1 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.reducer.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.reducer.ts @@ -1,4 +1,4 @@ -import { QualityAssuranceTopicObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { QualityAssuranceTopicObject } from '../../../core/notifications/qa/models/quality-assurance-topic.model'; import { QualityAssuranceTopicActionTypes, QualityAssuranceTopicsActions } from './quality-assurance-topics.actions'; /** diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts similarity index 96% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts index 1e4e3fcffd9..c6aae27a888 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.service.spec.ts @@ -4,7 +4,7 @@ import { QualityAssuranceTopicsService } from './quality-assurance-topics.servic import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { QualityAssuranceTopicDataService -} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +} from '../../../core/notifications/qa/topics/quality-assurance-topic-data.service'; import { PageInfo } from '../../../core/shared/page-info.model'; import { getMockQualityAssuranceTopicRestService, diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts b/src/app/notifications/qa/topics/quality-assurance-topics.service.ts similarity index 92% rename from src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts rename to src/app/notifications/qa/topics/quality-assurance-topics.service.ts index 6820791dffd..9dd581ebedc 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.service.ts @@ -3,13 +3,13 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { QualityAssuranceTopicDataService -} from '../../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +} from '../../../core/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'; import { QualityAssuranceTopicObject -} from '../../../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +} 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'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; diff --git a/src/app/suggestion-notifications/selectors.ts b/src/app/notifications/selectors.ts similarity index 95% rename from src/app/suggestion-notifications/selectors.ts rename to src/app/notifications/selectors.ts index d98c023ee45..63b2da7a100 100644 --- a/src/app/suggestion-notifications/selectors.ts +++ b/src/app/notifications/selectors.ts @@ -1,12 +1,12 @@ import { createFeatureSelector, createSelector, MemoizedSelector } from '@ngrx/store'; import { subStateSelector } from '../shared/selector.util'; -import { suggestionNotificationsSelector, SuggestionNotificationsState } from './suggestion-notifications.reducer'; -import { QualityAssuranceTopicObject } from '../core/suggestion-notifications/qa/models/quality-assurance-topic.model'; +import { suggestionNotificationsSelector, SuggestionNotificationsState } from './notifications.reducer'; +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/suggestion-notifications/qa/models/quality-assurance-source.model'; +} from '../core/notifications/qa/models/quality-assurance-source.model'; /** * Returns the Notifications state. diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index dc1c98c7b95..8c8193071a7 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -2,16 +2,16 @@ 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'; +} from '../../core/notifications/qa/models/quality-assurance-topic.model'; import { QualityAssuranceEventObject -} from '../../core/suggestion-notifications/qa/models/quality-assurance-event.model'; +} from '../../core/notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceTopicDataService -} from '../../core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service'; +} from '../../core/notifications/qa/topics/quality-assurance-topic-data.service'; import { QualityAssuranceEventDataService -} from '../../core/suggestion-notifications/qa/events/quality-assurance-event-data.service'; +} from '../../core/notifications/qa/events/quality-assurance-event-data.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { Item } from '../../core/shared/item.model'; import { @@ -22,7 +22,7 @@ import { import { SearchResult } from '../search/models/search-result.model'; import { QualityAssuranceSourceObject -} from '../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; +} from '../../core/notifications/qa/models/quality-assurance-source.model'; // REST Mock --------------------------------------------------------------------- // ------------------------------------------------------------------------------- @@ -80,7 +80,7 @@ const ItemMockPid1: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -199,7 +199,7 @@ const ItemMockPid2: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -318,7 +318,7 @@ const ItemMockPid3: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -437,7 +437,7 @@ const ItemMockPid4: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -556,7 +556,7 @@ const ItemMockPid5: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -675,7 +675,7 @@ const ItemMockPid6: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -794,7 +794,7 @@ const ItemMockPid7: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -913,7 +913,7 @@ export const ItemMockPid8: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -1032,7 +1032,7 @@ export const ItemMockPid9: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -1151,7 +1151,7 @@ export const ItemMockPid10: Item = Object.assign( 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -1270,7 +1270,7 @@ export const NotificationsMockDspaceObject: SearchResult<DSpaceObject> = Object. 'dc.identifier.uri': [ { language: null, - value: 'http://dspace7.4science.it/xmlui/handle/10673/6' + value: 'https://demo.dspace.org/handle/10673/6' } ], 'dc.description.abstract': [ @@ -1799,7 +1799,7 @@ export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssurance // ------------------------------------------------------------------------------- /** - * Mock for [[SuggestionNotificationsStateService]] + * Mock for [[NotificationsStateService]] */ export function getMockNotificationsStateService(): any { return jasmine.createSpyObj('NotificationsStateService', { From 8113946f584790f4c9df41c181bc97a9a6523511 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Wed, 13 Dec 2023 12:38:38 +0100 Subject: [PATCH 255/282] remove console logs --- .../qa/events/quality-assurance-events.component.ts | 2 -- 1 file changed, 2 deletions(-) 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 e34c121f359..742047e76f8 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 @@ -140,7 +140,6 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { return this.getQualityAssuranceEvents(); }) ).subscribe((events: QualityAssuranceEventData[]) => { - console.log(events); this.eventsUpdated$.next(events); this.isEventPageLoading.next(false); }); @@ -356,7 +355,6 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { 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([]); From 7fe81ec111a78675f56716b69fca45fc13273dca Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Wed, 13 Dec 2023 17:00:24 +0100 Subject: [PATCH 256/282] add quality assurance configuration --- ...-quality-assurance-source-data.resolver.ts | 5 ++++- .../quality-assurance-events.component.ts | 3 ++- src/config/app-config.interface.ts | 2 ++ src/config/default-app-config.ts | 7 +++++++ src/config/quality-assurance.config.ts | 21 +++++++++++++++++++ src/environments/environment.test.ts | 5 +++++ 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/config/quality-assurance.config.ts diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts index 6201e0a7435..261ef95b88d 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts @@ -5,11 +5,14 @@ import { map } from 'rxjs/operators'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { QualityAssuranceSourceObject } from '../../../core/notifications/qa/models/quality-assurance-source.model'; import { QualityAssuranceSourceService } from '../../../notifications/qa/source/quality-assurance-source.service'; +import {environment} from '../../../../environments/environment'; /** * This class represents a resolver that retrieve the route data before the route is activated. */ @Injectable() export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSourceObject[]>> { + private paginationStart = environment.qualityAssuranceConfig.defaultPaginationStart; + private paginationItemsCount = environment.qualityAssuranceConfig.defaultPaginationItemsCount; /** * Initialize the effect class variables. * @param {QualityAssuranceSourceService} qualityAssuranceSourceService @@ -25,7 +28,7 @@ export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSo * @returns Observable<QualityAssuranceSourceObject[]> */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<QualityAssuranceSourceObject[]> { - return this.qualityAssuranceSourceService.getSources(5,0).pipe( + return this.qualityAssuranceSourceService.getSources(this.paginationItemsCount,this.paginationStart).pipe( map((sources: PaginatedList<QualityAssuranceSourceObject>) => { if (sources.page.length === 1) { this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]); 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 a0e328538e1..2594df46688 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -30,6 +30,7 @@ import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { Item } from '../../../core/shared/item.model'; import { FindListOptions } from '../../../core/data/find-list-options.model'; +import {environment} from '../../../../environments/environment'; /** * Component to display the Quality Assurance event list. @@ -98,7 +99,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { /** * The Open Aire base url for project search */ - public openAireUrl = 'https://explore.openaire.eu/search/project?projectId='; + public openAireUrl = environment.qualityAssuranceConfig.openAireUrl; /** * The FindListOptions object */ diff --git a/src/config/app-config.interface.ts b/src/config/app-config.interface.ts index 84a30549a72..cd8926f1c13 100644 --- a/src/config/app-config.interface.ts +++ b/src/config/app-config.interface.ts @@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface'; import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; +import {QualityAssuranceConfig} from './quality-assurance.config'; interface AppConfig extends Config { ui: UIServerConfig; @@ -48,6 +49,7 @@ interface AppConfig extends Config { markdown: MarkdownConfig; vocabularies: FilterVocabularyConfig[]; comcolSelectionSort: DiscoverySortConfig; + qualityAssuranceConfig: QualityAssuranceConfig; } /** diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index a6e9e092e46..094bd9080a3 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -22,6 +22,7 @@ import { HomeConfig } from './homepage-config.interface'; import { MarkdownConfig } from './markdown-config.interface'; import { FilterVocabularyConfig } from './filter-vocabulary-config'; import { DiscoverySortConfig } from './discovery-sort.config'; +import {QualityAssuranceConfig} from './quality-assurance.config'; export class DefaultAppConfig implements AppConfig { production = false; @@ -432,4 +433,10 @@ export class DefaultAppConfig implements AppConfig { sortField:'dc.title', sortDirection:'ASC', }; + + qualityAssuranceConfig: QualityAssuranceConfig = { + openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', + defaultPaginationItemsCount: 5, + defaultPaginationStart: 0 + }; } diff --git a/src/config/quality-assurance.config.ts b/src/config/quality-assurance.config.ts new file mode 100644 index 00000000000..46e11fbdd51 --- /dev/null +++ b/src/config/quality-assurance.config.ts @@ -0,0 +1,21 @@ +import { Config } from './config.interface'; + +/** + * Config that determines a metadata sorting config. + * It's created mainly to sort by metadata community and collection edition and creation + */ +export class QualityAssuranceConfig implements Config { + + /** + * Url for OAIRE resources + */ + public openAireUrl: string; + /** + * default count of QA sources to load + */ + public defaultPaginationItemsCount: number; + /** + * default starting point of pagination + */ + public defaultPaginationStart: number; +} diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index cb9d2c71303..dd1dbf58c13 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -306,6 +306,11 @@ export const environment: BuildConfig = { sortField:'dc.title', sortDirection:'ASC', }, + qualityAssuranceConfig: { + openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', + defaultPaginationItemsCount: 5, + defaultPaginationStart: 0 + }, vocabularies: [ { From f2be578d2ac7dba8d1357909677829d02bced089 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Thu, 14 Dec 2023 12:11:06 +0100 Subject: [PATCH 257/282] refactor config QA --- .../admin-quality-assurance-source-data.resolver.ts | 5 ++--- src/config/default-app-config.ts | 3 +-- src/config/quality-assurance.config.ts | 6 +----- src/environments/environment.test.ts | 3 +-- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts index 261ef95b88d..a6bfd6e7fe4 100644 --- a/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts +++ b/src/app/admin/admin-notifications/admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver.ts @@ -11,8 +11,7 @@ import {environment} from '../../../../environments/environment'; */ @Injectable() export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSourceObject[]>> { - private paginationStart = environment.qualityAssuranceConfig.defaultPaginationStart; - private paginationItemsCount = environment.qualityAssuranceConfig.defaultPaginationItemsCount; + private pageSize = environment.qualityAssuranceConfig.pageSize; /** * Initialize the effect class variables. * @param {QualityAssuranceSourceService} qualityAssuranceSourceService @@ -28,7 +27,7 @@ export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSo * @returns Observable<QualityAssuranceSourceObject[]> */ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<QualityAssuranceSourceObject[]> { - return this.qualityAssuranceSourceService.getSources(this.paginationItemsCount,this.paginationStart).pipe( + return this.qualityAssuranceSourceService.getSources(this.pageSize, 0).pipe( map((sources: PaginatedList<QualityAssuranceSourceObject>) => { if (sources.page.length === 1) { this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]); diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 094bd9080a3..e379b365e0e 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -436,7 +436,6 @@ export class DefaultAppConfig implements AppConfig { qualityAssuranceConfig: QualityAssuranceConfig = { openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', - defaultPaginationItemsCount: 5, - defaultPaginationStart: 0 + pageSize: 5, }; } diff --git a/src/config/quality-assurance.config.ts b/src/config/quality-assurance.config.ts index 46e11fbdd51..14161b41133 100644 --- a/src/config/quality-assurance.config.ts +++ b/src/config/quality-assurance.config.ts @@ -13,9 +13,5 @@ export class QualityAssuranceConfig implements Config { /** * default count of QA sources to load */ - public defaultPaginationItemsCount: number; - /** - * default starting point of pagination - */ - public defaultPaginationStart: number; + public pageSize: number; } diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index dd1dbf58c13..89a8e2bc0fe 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -308,8 +308,7 @@ export const environment: BuildConfig = { }, qualityAssuranceConfig: { openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', - defaultPaginationItemsCount: 5, - defaultPaginationStart: 0 + pageSize: 5, }, vocabularies: [ From f7be255345afc499a49d0b5a5ae2d4db69809e69 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Fri, 15 Dec 2023 15:20:39 +0100 Subject: [PATCH 258/282] add QA authorization config --- src/app/core/data/feature-authorization/feature-id.ts | 1 + src/app/menu.resolver.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/core/data/feature-authorization/feature-id.ts b/src/app/core/data/feature-authorization/feature-id.ts index 8fef45a9532..e2943f1762f 100644 --- a/src/app/core/data/feature-authorization/feature-id.ts +++ b/src/app/core/data/feature-authorization/feature-id.ts @@ -34,4 +34,5 @@ export enum FeatureID { CanEditItem = 'canEditItem', CanRegisterDOI = 'canRegisterDOI', CanSubscribe = 'canSubscribeDso', + CanSeeQA = 'canSeeQA' } diff --git a/src/app/menu.resolver.ts b/src/app/menu.resolver.ts index 7a3a16d6265..a9a247007f5 100644 --- a/src/app/menu.resolver.ts +++ b/src/app/menu.resolver.ts @@ -530,13 +530,17 @@ export class MenuResolver implements Resolve<boolean> { * Create menu sections dependent on whether or not the current user is a site administrator */ createSiteAdministratorMenuSections() { - this.authorizationService.isAuthorized(FeatureID.AdministratorOf).subscribe((authorized) => { + combineLatest([ + this.authorizationService.isAuthorized(FeatureID.AdministratorOf), + this.authorizationService.isAuthorized(FeatureID.CanSeeQA) + ]) + .subscribe(([authorized, canSeeQA]) => { const menuList = [ /* Notifications */ { id: 'notifications', active: false, - visible: authorized, + visible: authorized && canSeeQA, model: { type: MenuItemType.TEXT, text: 'menu.section.notifications' From 2d2ca2016afee28f7ef31176df9f9b1a42d2b276 Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Mon, 18 Dec 2023 11:40:09 +0100 Subject: [PATCH 259/282] refactor --- .../qa/models/quality-assurance-event.model.ts | 8 ++++---- .../quality-assurance-events.component.html | 2 +- .../quality-assurance-events.component.ts | 10 +++++----- .../project-entry-import-modal.component.ts | 4 ++-- src/app/shared/mocks/notifications.mock.ts | 18 +++++++++--------- src/config/default-app-config.ts | 2 +- src/config/quality-assurance.config.ts | 4 ++-- src/environments/environment.test.ts | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) 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 7517148def4..0cdb4a57456 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 @@ -22,7 +22,7 @@ export interface QualityAssuranceEventMessageObject { /** * The interface representing the Quality Assurance event message */ -export interface OpenaireQualityAssuranceEventMessageObject { +export interface SourceQualityAssuranceEventMessageObject { /** * The type of 'value' */ @@ -69,9 +69,9 @@ export interface OpenaireQualityAssuranceEventMessageObject { title: string; /** - * The OPENAIRE ID. + * The Source ID. */ - openaireId: string; + sourceId: string; /** * The PID href. @@ -136,7 +136,7 @@ export class QualityAssuranceEventObject implements CacheableObject { * The suggestion data. Data may vary depending on the source */ @autoserialize - message: OpenaireQualityAssuranceEventMessageObject; + message: SourceQualityAssuranceEventMessageObject; /** * The type of this ConfigObject 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 dde372f4dde..f12714b389d 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.html +++ b/src/app/notifications/qa/events/quality-assurance-events.component.html @@ -85,7 +85,7 @@ <h4 class="border-bottom pb-2"> </p> <p> <span class="small">{{'quality-assurance.event.table.project' | translate}}</span><br> - <a href="{{openAireUrl}}{{ eventElement.event.message.openaireId}}" rel="noopener noreferrer" target="_blank">{{eventElement.event.message.title}}</a> + <a href="{{sourceUrlForProjectSearch}}{{ eventElement.event.message.sourceId}}" rel="noopener noreferrer" target="_blank">{{eventElement.event.message.title}}</a> </p> <p> <span *ngIf="eventElement.event.message.acronym"><span class="small">{{'quality-assurance.event.table.acronym' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.acronym}}</span><br></span> 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 aa2f6c262ec..a54186f9571 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -10,7 +10,7 @@ import { SortDirection, SortOptions } from '../../../core/cache/models/sort-opti import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { - OpenaireQualityAssuranceEventMessageObject, + SourceQualityAssuranceEventMessageObject, QualityAssuranceEventObject } from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { @@ -97,9 +97,9 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { */ public showMore = false; /** - * The Open Aire base url for project search + * The quality assurance source base url for project search */ - public openAireUrl = environment.qualityAssuranceConfig.openAireUrl; + public sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlForProjectSearch; /** * The FindListOptions object */ @@ -332,7 +332,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * Check if the event has a valid href. * @param event */ - public hasPIDHref(event: OpenaireQualityAssuranceEventMessageObject): boolean { + public hasPIDHref(event: SourceQualityAssuranceEventMessageObject): boolean { return this.getPIDHref(event) !== null; } @@ -340,7 +340,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { * Get the event pid href. * @param event */ - public getPIDHref(event: OpenaireQualityAssuranceEventMessageObject): string { + public getPIDHref(event: SourceQualityAssuranceEventMessageObject): string { return event.pidHref; } 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 6872baeb90b..ad9c1035a51 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 @@ -13,7 +13,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio import { SearchService } from '../../../core/shared/search/search.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { - OpenaireQualityAssuranceEventMessageObject, + SourceQualityAssuranceEventMessageObject, QualityAssuranceEventObject, } from '../../../core/notifications/qa/models/quality-assurance-event.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; @@ -180,7 +180,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 OpenaireQualityAssuranceEventMessageObject).title; + : (this.externalSourceEntry.event.message as SourceQualityAssuranceEventMessageObject).title; this.searchOptions = Object.assign(new PaginatedSearchOptions( { configuration: this.configuration, diff --git a/src/app/shared/mocks/notifications.mock.ts b/src/app/shared/mocks/notifications.mock.ts index 8c8193071a7..707b9a9e6ab 100644 --- a/src/app/shared/mocks/notifications.mock.ts +++ b/src/app/shared/mocks/notifications.mock.ts @@ -1476,7 +1476,7 @@ export const qualityAssuranceEventObjectMissingPid: QualityAssuranceEventObject value: '10.18848/1447-9494/cgp/v15i09/45934', pidHref: 'https://doi.org/10.18848/1447-9494/cgp/v15i09/45934', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1513,7 +1513,7 @@ export const qualityAssuranceEventObjectMissingPid2: QualityAssuranceEventObject value: 'http://thesis2.sba.units.it/store/handle/item/12238', pidHref:'http://thesis2.sba.units.it/store/handle/item/12238', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1550,7 +1550,7 @@ export const qualityAssuranceEventObjectMissingPid3: QualityAssuranceEventObject value: '10.4324/9780203408889', pidHref: 'https://doi.org/10.4324/9780203408889', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1587,7 +1587,7 @@ export const qualityAssuranceEventObjectMissingPid4: QualityAssuranceEventObject value: '10.1080/13698230.2018.1430104', pidHref: 'https://doi.org/10.1080/13698230.2018.1430104', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1624,7 +1624,7 @@ export const qualityAssuranceEventObjectMissingPid5: QualityAssuranceEventObject value: 'http://thesis2.sba.units.it/store/handle/item/12477', pidHref:'http://thesis2.sba.units.it/store/handle/item/12477', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1661,7 +1661,7 @@ export const qualityAssuranceEventObjectMissingPid6: QualityAssuranceEventObject value: '10.1111/j.1475-4975.2004.00098.x', pidHref: 'https://doi.org/10.1111/j.1475-4975.2004.00098.x', abstract: null, - openaireId: null, + sourceId: null, acronym: null, code: null, funder: null, @@ -1698,7 +1698,7 @@ export const qualityAssuranceEventObjectMissingAbstract: QualityAssuranceEventOb value: null, pidHref: 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, + sourceId: null, acronym: null, code: null, funder: null, @@ -1735,7 +1735,7 @@ export const qualityAssuranceEventObjectMissingProjectFound: QualityAssuranceEve value: null, pidHref: null, abstract: null, - openaireId: null, + sourceId: null, acronym: 'PAThs', code: '687567', funder: 'EC', @@ -1772,7 +1772,7 @@ export const qualityAssuranceEventObjectMissingProjectNotFound: QualityAssurance value: null, pidHref: null, abstract: null, - openaireId: null, + sourceId: null, acronym: 'PAThs', code: '687567B', funder: 'EC', diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index e379b365e0e..16de9b2e1c7 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -435,7 +435,7 @@ export class DefaultAppConfig implements AppConfig { }; qualityAssuranceConfig: QualityAssuranceConfig = { - openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', + sourceUrlForProjectSearch: 'https://explore.openaire.eu/search/project?projectId=', pageSize: 5, }; } diff --git a/src/config/quality-assurance.config.ts b/src/config/quality-assurance.config.ts index 14161b41133..10f4106d7f4 100644 --- a/src/config/quality-assurance.config.ts +++ b/src/config/quality-assurance.config.ts @@ -7,9 +7,9 @@ import { Config } from './config.interface'; export class QualityAssuranceConfig implements Config { /** - * Url for OAIRE resources + * Url for project search on quality assurance resource */ - public openAireUrl: string; + public sourceUrlForProjectSearch: string; /** * default count of QA sources to load */ diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index 89a8e2bc0fe..e882527ee80 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -307,7 +307,7 @@ export const environment: BuildConfig = { sortDirection:'ASC', }, qualityAssuranceConfig: { - openAireUrl: 'https://explore.openaire.eu/search/project?projectId=', + sourceUrlForProjectSearch: 'https://explore.openaire.eu/search/project?projectId=', pageSize: 5, }, From c386a4d505a7b26321c23d961bb476dba8e0067d Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Mon, 18 Dec 2023 12:22:05 +0100 Subject: [PATCH 260/282] adapt config for url search --- .../qa/events/quality-assurance-events.component.ts | 7 +++++-- src/config/default-app-config.ts | 4 +++- src/config/quality-assurance.config.ts | 2 +- src/environments/environment.test.ts | 4 +++- 4 files changed, 12 insertions(+), 5 deletions(-) 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 a54186f9571..c22c28f41e9 100644 --- a/src/app/notifications/qa/events/quality-assurance-events.component.ts +++ b/src/app/notifications/qa/events/quality-assurance-events.component.ts @@ -99,7 +99,7 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { /** * The quality assurance source base url for project search */ - public sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlForProjectSearch; + public sourceUrlForProjectSearch: string; /** * The FindListOptions object */ @@ -136,7 +136,10 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy { this.isEventPageLoading.next(true); this.activatedRoute.paramMap.pipe( - map((params) => params.get('topicId')), + tap((params) => { + this.sourceUrlForProjectSearch = environment.qualityAssuranceConfig.sourceUrlMapForProjectSearch[params.get('sourceId')]; + }), + map((params) => params.get('topicId')), take(1), switchMap((id: string) => { const regEx = /!/g; diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index 16de9b2e1c7..2c5a37ab3ef 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -435,7 +435,9 @@ export class DefaultAppConfig implements AppConfig { }; qualityAssuranceConfig: QualityAssuranceConfig = { - sourceUrlForProjectSearch: 'https://explore.openaire.eu/search/project?projectId=', + sourceUrlMapForProjectSearch: { + openaire: 'https://explore.openaire.eu/search/project?projectId=' + }, pageSize: 5, }; } diff --git a/src/config/quality-assurance.config.ts b/src/config/quality-assurance.config.ts index 10f4106d7f4..7b2723f9d96 100644 --- a/src/config/quality-assurance.config.ts +++ b/src/config/quality-assurance.config.ts @@ -9,7 +9,7 @@ export class QualityAssuranceConfig implements Config { /** * Url for project search on quality assurance resource */ - public sourceUrlForProjectSearch: string; + public sourceUrlMapForProjectSearch: {[key: string]: string}; /** * default count of QA sources to load */ diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index e882527ee80..8b906764620 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -307,7 +307,9 @@ export const environment: BuildConfig = { sortDirection:'ASC', }, qualityAssuranceConfig: { - sourceUrlForProjectSearch: 'https://explore.openaire.eu/search/project?projectId=', + sourceUrlMapForProjectSearch: { + openaire: 'https://explore.openaire.eu/search/project?projectId=' + }, pageSize: 5, }, From 56cf0e1451e6823313e4225715ba70bf013dcd3a Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro <francesco.molinaro@4science.com> Date: Mon, 18 Dec 2023 17:47:19 +0100 Subject: [PATCH 261/282] fix lint --- .../admin-notifications-routing.module.ts | 6 +++--- .../quality-assurance-breadcrumb.resolver.spec.ts | 2 +- .../breadcrumbs/quality-assurance-breadcrumb.service.ts | 8 ++++---- 3 files changed, 8 insertions(+), 8 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 3af922918e6..63d555d7b74 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -11,11 +11,11 @@ import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assuran 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 {QualityAssuranceBreadcrumbResolver} from '../../core/breadcrumbs/quality-assurance-breadcrumb.resolver'; -import {QualityAssuranceBreadcrumbService} from '../../core/breadcrumbs/quality-assurance-breadcrumb.service'; +import { QualityAssuranceBreadcrumbResolver } from '../../core/breadcrumbs/quality-assurance-breadcrumb.resolver'; +import { QualityAssuranceBreadcrumbService } from '../../core/breadcrumbs/quality-assurance-breadcrumb.service'; import { SourceDataResolver -} from "./admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver"; +} from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver'; @NgModule({ imports: [ diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts index de676f4cc30..3544af62e7a 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.resolver.spec.ts @@ -12,7 +12,7 @@ describe('QualityAssuranceBreadcrumbResolver', () => { route = { paramMap: { get: function (param) { - return this[param] + return this[param]; }, sourceId: 'testSourceId', topicId: 'testTopicId' diff --git a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts index 1d286a9b5e2..209ae0722ce 100644 --- a/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts +++ b/src/app/core/breadcrumbs/quality-assurance-breadcrumb.service.ts @@ -2,10 +2,10 @@ import { Breadcrumb } from '../../breadcrumbs/breadcrumb/breadcrumb.model'; import { BreadcrumbsProviderService } from './breadcrumbsProviderService'; import { Observable, of as observableOf } from 'rxjs'; import { Injectable } from '@angular/core'; -import {map} from 'rxjs/operators'; -import {getFirstCompletedRemoteData} from '../shared/operators'; -import {TranslateService} from '@ngx-translate/core'; -import {QualityAssuranceTopicDataService} from "../notifications/qa/topics/quality-assurance-topic-data.service"; +import { map } from 'rxjs/operators'; +import { getFirstCompletedRemoteData } from '../shared/operators'; +import { TranslateService } from '@ngx-translate/core'; +import { QualityAssuranceTopicDataService } from '../notifications/qa/topics/quality-assurance-topic-data.service'; From 7bedf7fc59983983bfdd1061db8d0ae4a5822f12 Mon Sep 17 00:00:00 2001 From: Alan Orth <alan.orth@gmail.com> Date: Wed, 20 Dec 2023 17:45:35 +0300 Subject: [PATCH 262/282] src/app/community-list-page: remove newlines in links The newlines cause whitespace to be enapsulated in the rendered link. --- .../community-list/community-list.component.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index de67607bb4b..eed9ca64cad 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -35,9 +35,7 @@ </button> <div class="d-flex flex-row"> <span class="align-middle pt-2 lead"> - <a [routerLink]="node.route" class="lead"> - {{ dsoNameService.getName(node.payload) }} - </a> + <a [routerLink]="node.route" class="lead">{{ dsoNameService.getName(node.payload) }}</a> <span class="pr-2"> </span> <span *ngIf="node.payload.archivedItemsCount >= 0" class="badge badge-pill badge-secondary align-top archived-items-lead">{{node.payload.archivedItemsCount}}</span> </span> @@ -73,9 +71,7 @@ <span class="fa fa-chevron-right invisible" aria-hidden="true"></span> </button> <h6 class="align-middle pt-2"> - <a [routerLink]="node.route" class="lead"> - {{ dsoNameService.getName(node.payload) }} - </a> + <a [routerLink]="node.route" class="lead">{{ dsoNameService.getName(node.payload) }}</a> </h6> </div> <ds-truncatable [id]="node.id"> From 7207bbbd0e647693148438f49cb7bdbd7ca3fe86 Mon Sep 17 00:00:00 2001 From: Alan Orth <alan.orth@gmail.com> Date: Wed, 20 Dec 2023 22:32:22 +0300 Subject: [PATCH 263/282] src/app/item-page: remove newlines in links The newlines cause whitespace to be enapsulated in the rendered link. --- .../metadata-values/metadata-values.component.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/item-page/field-components/metadata-values/metadata-values.component.html b/src/app/item-page/field-components/metadata-values/metadata-values.component.html index 61088edd164..a598815d4cc 100644 --- a/src/app/item-page/field-components/metadata-values/metadata-values.component.html +++ b/src/app/item-page/field-components/metadata-values/metadata-values.component.html @@ -32,7 +32,5 @@ <ng-template #browselink let-value="value"> <a class="dont-break-out preserve-line-breaks ds-browse-link" [routerLink]="['/browse', browseDefinition.id]" - [queryParams]="getQueryParams(value)"> - {{value}} - </a> + [queryParams]="getQueryParams(value)">{{value}}</a> </ng-template> From bd6c99da2e68653d29373a9b41a7190cd7256c78 Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Wed, 29 Nov 2023 14:25:36 +0100 Subject: [PATCH 264/282] ensure HALEndpointService doesn't use stale requests (cherry picked from commit 38752d9d71b2441b83bbcb616347df66b7fb5e75) --- src/app/core/server-check/server-check.guard.spec.ts | 10 ++++++---- src/app/core/server-check/server-check.guard.ts | 6 ++---- src/app/core/shared/hal-endpoint.service.ts | 12 ++++++++---- 3 files changed, 16 insertions(+), 12 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 044609ef427..f65a7deca7c 100644 --- a/src/app/core/server-check/server-check.guard.spec.ts +++ b/src/app/core/server-check/server-check.guard.spec.ts @@ -9,7 +9,7 @@ import SpyObj = jasmine.SpyObj; describe('ServerCheckGuard', () => { let guard: ServerCheckGuard; let router: Router; - const eventSubject = new ReplaySubject<RouterEvent>(1); + let eventSubject: ReplaySubject<RouterEvent>; let rootDataServiceStub: SpyObj<RootDataService>; let testScheduler: TestScheduler; let redirectUrlTree: UrlTree; @@ -24,6 +24,7 @@ describe('ServerCheckGuard', () => { findRoot: jasmine.createSpy('findRoot') }); redirectUrlTree = new UrlTree(); + eventSubject = new ReplaySubject<RouterEvent>(1); router = { events: eventSubject.asObservable(), navigateByUrl: jasmine.createSpy('navigateByUrl'), @@ -64,10 +65,10 @@ describe('ServerCheckGuard', () => { }); describe(`listenForRouteChanges`, () => { - it(`should retrieve the root endpoint, without using the cache, when the method is first called`, () => { + it(`should invalidate the root cache, when the method is first called`, () => { testScheduler.run(() => { guard.listenForRouteChanges(); - expect(rootDataServiceStub.findRoot).toHaveBeenCalledWith(false); + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(1); }); }); @@ -80,7 +81,8 @@ describe('ServerCheckGuard', () => { eventSubject.next(new NavigationEnd(2,'', '')); eventSubject.next(new NavigationStart(3,'')); }); - expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(3); + // once when the method is first called, and then 3 times for NavigationStart events + expect(rootDataServiceStub.invalidateRootCache).toHaveBeenCalledTimes(1 + 3); }); }); }); diff --git a/src/app/core/server-check/server-check.guard.ts b/src/app/core/server-check/server-check.guard.ts index 65ca2b0c498..79c34c36590 100644 --- a/src/app/core/server-check/server-check.guard.ts +++ b/src/app/core/server-check/server-check.guard.ts @@ -53,10 +53,8 @@ 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. 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); + // so this statement is for the very first route operation. + this.rootDataService.invalidateRootCache(); this.router.events.pipe( filter(event => event instanceof NavigationStart), diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts index 8b6316a6ce2..98ab6a16ea0 100644 --- a/src/app/core/shared/hal-endpoint.service.ts +++ b/src/app/core/shared/hal-endpoint.service.ts @@ -1,5 +1,5 @@ import { Observable } from 'rxjs'; -import { distinctUntilChanged, map, startWith, switchMap, take } from 'rxjs/operators'; +import { distinctUntilChanged, map, startWith, switchMap, take, skipWhile } from 'rxjs/operators'; import { RequestService } from '../data/request.service'; import { EndpointMapRequest } from '../data/request.models'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; @@ -9,7 +9,7 @@ import { EndpointMap } from '../cache/response.models'; import { getFirstCompletedRemoteData } from './operators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { RemoteData } from '../data/remote-data'; -import { UnCacheableObject } from './uncacheable-object.model'; +import { CacheableObject } from '../cache/cacheable-object.model'; @Injectable() export class HALEndpointService { @@ -33,9 +33,13 @@ export class HALEndpointService { this.requestService.send(request, true); - return this.rdbService.buildFromHref<UnCacheableObject>(href).pipe( + return this.rdbService.buildFromHref<CacheableObject>(href).pipe( + // This skip ensures that if a stale object is present in the cache when you do a + // call it isn't immediately returned, but we wait until the remote data for the new request + // is created. + skipWhile((rd: RemoteData<CacheableObject>) => rd.isStale), getFirstCompletedRemoteData(), - map((response: RemoteData<UnCacheableObject>) => { + map((response: RemoteData<CacheableObject>) => { if (hasValue(response.payload)) { return response.payload._links; } else { From d109a5aeb2e8bb3bbee79029e840bc46f9293e08 Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Fri, 1 Dec 2023 16:19:12 +0100 Subject: [PATCH 265/282] also skip loading hal requests (cherry picked from commit c8ac260b783d6bd9426325f7e2893e4b4f8d6f0d) --- src/app/core/shared/hal-endpoint.service.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts index 98ab6a16ea0..5cdd7ccfad7 100644 --- a/src/app/core/shared/hal-endpoint.service.ts +++ b/src/app/core/shared/hal-endpoint.service.ts @@ -6,7 +6,6 @@ import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { Injectable } from '@angular/core'; import { EndpointMap } from '../cache/response.models'; -import { getFirstCompletedRemoteData } from './operators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { RemoteData } from '../data/remote-data'; import { CacheableObject } from '../cache/cacheable-object.model'; @@ -37,8 +36,8 @@ export class HALEndpointService { // This skip ensures that if a stale object is present in the cache when you do a // call it isn't immediately returned, but we wait until the remote data for the new request // is created. - skipWhile((rd: RemoteData<CacheableObject>) => rd.isStale), - getFirstCompletedRemoteData(), + skipWhile((rd: RemoteData<CacheableObject>) => rd.isLoading || rd.isStale), + take(1), map((response: RemoteData<CacheableObject>) => { if (hasValue(response.payload)) { return response.payload._links; From 33b7c39dd13758c3b02ed2333bc9c58cc49e2716 Mon Sep 17 00:00:00 2001 From: Art Lowel <art.lowel@gmail.com> Date: Wed, 6 Dec 2023 11:14:41 +0100 Subject: [PATCH 266/282] add ResponsePendingStale state (cherry picked from commit 790e7171992f2cefc6999306703e52586204986b) --- .../core/data/base/base-data.service.spec.ts | 98 ++++---- src/app/core/data/base/base-data.service.ts | 4 +- .../data/request-entry-state.model.spec.ts | 186 +++++++++++++++ .../core/data/request-entry-state.model.ts | 25 +- src/app/core/data/request.reducer.spec.ts | 222 +++++++++++++++--- src/app/core/data/request.reducer.ts | 55 +++-- src/app/core/data/request.service.ts | 2 +- .../core/shared/hal-endpoint.service.spec.ts | 180 +++++++++++--- src/app/core/shared/hal-endpoint.service.ts | 25 +- 9 files changed, 658 insertions(+), 139 deletions(-) create mode 100644 src/app/core/data/request-entry-state.model.spec.ts diff --git a/src/app/core/data/base/base-data.service.spec.ts b/src/app/core/data/base/base-data.service.spec.ts index 098f075c101..75662a691fa 100644 --- a/src/app/core/data/base/base-data.service.spec.ts +++ b/src/app/core/data/base/base-data.service.spec.ts @@ -95,6 +95,7 @@ describe('BaseDataService', () => { remoteDataMocks = { RequestPending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.RequestPending, undefined, undefined, undefined), ResponsePending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.ResponsePending, undefined, undefined, undefined), + ResponsePendingStale: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.ResponsePendingStale, undefined, undefined, undefined), Success: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Success, undefined, payload, statusCodeSuccess), SuccessStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.SuccessStale, undefined, payload, statusCodeSuccess), Error: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Error, errorMessage, undefined, statusCodeError), @@ -303,19 +304,21 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { - spyOn(rdbService, 'buildSingle').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + spyOn(rdbService, 'buildSingle').and.returnValue(cold('a-b-c-d-e-f-g', { + a: remoteDataMocks.ResponsePendingStale, + b: remoteDataMocks.SuccessStale, + c: remoteDataMocks.ErrorStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, })); - const expected = '--b-c-d-e'; + const expected = '------d-e-f-g'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, }; expectObservable(service.findByHref(selfLink, true, true, ...linksToFollow)).toBe(expected, values); @@ -354,19 +357,21 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { - spyOn(rdbService, 'buildSingle').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + spyOn(rdbService, 'buildSingle').and.returnValue(cold('a-b-c-d-e-f-g', { + a: remoteDataMocks.ResponsePendingStale, + b: remoteDataMocks.SuccessStale, + c: remoteDataMocks.ErrorStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, })); - const expected = '--b-c-d-e'; + const expected = '------d-e-f-g'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, }; expectObservable(service.findByHref(selfLink, false, true, ...linksToFollow)).toBe(expected, values); @@ -487,19 +492,21 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { - spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e-f-g', { + a: remoteDataMocks.ResponsePendingStale, + b: remoteDataMocks.SuccessStale, + c: remoteDataMocks.ErrorStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, })); - const expected = '--b-c-d-e'; + const expected = '------d-e-f-g'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, }; expectObservable(service.findListByHref(selfLink, findListOptions, true, true, ...linksToFollow)).toBe(expected, values); @@ -538,21 +545,24 @@ describe('BaseDataService', () => { it(`should not emit a cached stale RemoteData, but only start emitting after the state first changes to RequestPending`, () => { testScheduler.run(({ cold, expectObservable }) => { - spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e', { - a: remoteDataMocks.SuccessStale, - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + spyOn(rdbService, 'buildList').and.returnValue(cold('a-b-c-d-e-f-g', { + a: remoteDataMocks.ResponsePendingStale, + b: remoteDataMocks.SuccessStale, + c: remoteDataMocks.ErrorStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, })); - const expected = '--b-c-d-e'; + const expected = '------d-e-f-g'; const values = { - b: remoteDataMocks.RequestPending, - c: remoteDataMocks.ResponsePending, - d: remoteDataMocks.Success, - e: remoteDataMocks.SuccessStale, + d: remoteDataMocks.RequestPending, + e: remoteDataMocks.ResponsePending, + f: remoteDataMocks.Success, + g: remoteDataMocks.SuccessStale, }; + expectObservable(service.findListByHref(selfLink, findListOptions, false, true, ...linksToFollow)).toBe(expected, values); }); }); diff --git a/src/app/core/data/base/base-data.service.ts b/src/app/core/data/base/base-data.service.ts index edd6d9e2a42..c7cd5b0a705 100644 --- a/src/app/core/data/base/base-data.service.ts +++ b/src/app/core/data/base/base-data.service.ts @@ -273,7 +273,7 @@ export class BaseDataService<T extends CacheableObject> implements HALDataServic // call it isn't immediately returned, but we wait until the remote data for the new request // is created. If useCachedVersionIfAvailable is false it also ensures you don't get a // cached completed object - skipWhile((rd: RemoteData<T>) => useCachedVersionIfAvailable ? rd.isStale : rd.hasCompleted), + skipWhile((rd: RemoteData<T>) => rd.isStale || (!useCachedVersionIfAvailable && rd.hasCompleted)), this.reRequestStaleRemoteData(reRequestOnStale, () => this.findByHref(href$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)), ); @@ -307,7 +307,7 @@ export class BaseDataService<T extends CacheableObject> implements HALDataServic // call it isn't immediately returned, but we wait until the remote data for the new request // is created. If useCachedVersionIfAvailable is false it also ensures you don't get a // cached completed object - skipWhile((rd: RemoteData<PaginatedList<T>>) => useCachedVersionIfAvailable ? rd.isStale : rd.hasCompleted), + skipWhile((rd: RemoteData<PaginatedList<T>>) => rd.isStale || (!useCachedVersionIfAvailable && rd.hasCompleted)), this.reRequestStaleRemoteData(reRequestOnStale, () => this.findListByHref(href$, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)), ); diff --git a/src/app/core/data/request-entry-state.model.spec.ts b/src/app/core/data/request-entry-state.model.spec.ts new file mode 100644 index 00000000000..7daa655566a --- /dev/null +++ b/src/app/core/data/request-entry-state.model.spec.ts @@ -0,0 +1,186 @@ +import { + isRequestPending, + isError, + isSuccess, + isErrorStale, + isSuccessStale, + isResponsePending, + isResponsePendingStale, + isLoading, + isStale, + hasFailed, + hasSucceeded, + hasCompleted, + RequestEntryState +} from './request-entry-state.model'; + +describe(`isRequestPending`, () => { + it(`should only return true if the given state is RequestPending`, () => { + expect(isRequestPending(RequestEntryState.RequestPending)).toBeTrue(); + + expect(isRequestPending(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isRequestPending(RequestEntryState.Error)).toBeFalse(); + expect(isRequestPending(RequestEntryState.Success)).toBeFalse(); + expect(isRequestPending(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isRequestPending(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isRequestPending(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isError`, () => { + it(`should only return true if the given state is Error`, () => { + expect(isError(RequestEntryState.Error)).toBeTrue(); + + expect(isError(RequestEntryState.RequestPending)).toBeFalse(); + expect(isError(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isError(RequestEntryState.Success)).toBeFalse(); + expect(isError(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isError(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isError(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isSuccess`, () => { + it(`should only return true if the given state is Success`, () => { + expect(isSuccess(RequestEntryState.Success)).toBeTrue(); + + expect(isSuccess(RequestEntryState.RequestPending)).toBeFalse(); + expect(isSuccess(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isSuccess(RequestEntryState.Error)).toBeFalse(); + expect(isSuccess(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isSuccess(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isSuccess(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isErrorStale`, () => { + it(`should only return true if the given state is ErrorStale`, () => { + expect(isErrorStale(RequestEntryState.ErrorStale)).toBeTrue(); + + expect(isErrorStale(RequestEntryState.RequestPending)).toBeFalse(); + expect(isErrorStale(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isErrorStale(RequestEntryState.Error)).toBeFalse(); + expect(isErrorStale(RequestEntryState.Success)).toBeFalse(); + expect(isErrorStale(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isErrorStale(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isSuccessStale`, () => { + it(`should only return true if the given state is SuccessStale`, () => { + expect(isSuccessStale(RequestEntryState.SuccessStale)).toBeTrue(); + + expect(isSuccessStale(RequestEntryState.RequestPending)).toBeFalse(); + expect(isSuccessStale(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isSuccessStale(RequestEntryState.Error)).toBeFalse(); + expect(isSuccessStale(RequestEntryState.Success)).toBeFalse(); + expect(isSuccessStale(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isSuccessStale(RequestEntryState.ErrorStale)).toBeFalse(); + }); +}); + +describe(`isResponsePending`, () => { + it(`should only return true if the given state is ResponsePending`, () => { + expect(isResponsePending(RequestEntryState.ResponsePending)).toBeTrue(); + + expect(isResponsePending(RequestEntryState.RequestPending)).toBeFalse(); + expect(isResponsePending(RequestEntryState.Error)).toBeFalse(); + expect(isResponsePending(RequestEntryState.Success)).toBeFalse(); + expect(isResponsePending(RequestEntryState.ResponsePendingStale)).toBeFalse(); + expect(isResponsePending(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isResponsePending(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isResponsePendingStale`, () => { + it(`should only return true if the given state is requestPending`, () => { + expect(isResponsePendingStale(RequestEntryState.ResponsePendingStale)).toBeTrue(); + + expect(isResponsePendingStale(RequestEntryState.RequestPending)).toBeFalse(); + expect(isResponsePendingStale(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isResponsePendingStale(RequestEntryState.Error)).toBeFalse(); + expect(isResponsePendingStale(RequestEntryState.Success)).toBeFalse(); + expect(isResponsePendingStale(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isResponsePendingStale(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`isLoading`, () => { + it(`should only return true if the given state is RequestPending, ResponsePending or ResponsePendingStale`, () => { + expect(isLoading(RequestEntryState.RequestPending)).toBeTrue(); + expect(isLoading(RequestEntryState.ResponsePending)).toBeTrue(); + expect(isLoading(RequestEntryState.ResponsePendingStale)).toBeTrue(); + + expect(isLoading(RequestEntryState.Error)).toBeFalse(); + expect(isLoading(RequestEntryState.Success)).toBeFalse(); + expect(isLoading(RequestEntryState.ErrorStale)).toBeFalse(); + expect(isLoading(RequestEntryState.SuccessStale)).toBeFalse(); + }); +}); + +describe(`hasFailed`, () => { + describe(`when the state is loading`, () => { + it(`should return undefined`, () => { + expect(hasFailed(RequestEntryState.RequestPending)).toBeUndefined(); + expect(hasFailed(RequestEntryState.ResponsePending)).toBeUndefined(); + expect(hasFailed(RequestEntryState.ResponsePendingStale)).toBeUndefined(); + }); + }); + + describe(`when the state has completed`, () => { + it(`should only return true if the given state is Error or ErrorStale`, () => { + expect(hasFailed(RequestEntryState.Error)).toBeTrue(); + expect(hasFailed(RequestEntryState.ErrorStale)).toBeTrue(); + + expect(hasFailed(RequestEntryState.Success)).toBeFalse(); + expect(hasFailed(RequestEntryState.SuccessStale)).toBeFalse(); + }); + }); +}); + +describe(`hasSucceeded`, () => { + describe(`when the state is loading`, () => { + it(`should return undefined`, () => { + expect(hasSucceeded(RequestEntryState.RequestPending)).toBeUndefined(); + expect(hasSucceeded(RequestEntryState.ResponsePending)).toBeUndefined(); + expect(hasSucceeded(RequestEntryState.ResponsePendingStale)).toBeUndefined(); + }); + }); + + describe(`when the state has completed`, () => { + it(`should only return true if the given state is Error or ErrorStale`, () => { + expect(hasSucceeded(RequestEntryState.Success)).toBeTrue(); + expect(hasSucceeded(RequestEntryState.SuccessStale)).toBeTrue(); + + expect(hasSucceeded(RequestEntryState.Error)).toBeFalse(); + expect(hasSucceeded(RequestEntryState.ErrorStale)).toBeFalse(); + }); + }); +}); + + +describe(`hasCompleted`, () => { + it(`should only return true if the given state is Error, Success, ErrorStale or SuccessStale`, () => { + expect(hasCompleted(RequestEntryState.Error)).toBeTrue(); + expect(hasCompleted(RequestEntryState.Success)).toBeTrue(); + expect(hasCompleted(RequestEntryState.ErrorStale)).toBeTrue(); + expect(hasCompleted(RequestEntryState.SuccessStale)).toBeTrue(); + + expect(hasCompleted(RequestEntryState.RequestPending)).toBeFalse(); + expect(hasCompleted(RequestEntryState.ResponsePending)).toBeFalse(); + expect(hasCompleted(RequestEntryState.ResponsePendingStale)).toBeFalse(); + }); +}); + +describe(`isStale`, () => { + it(`should only return true if the given state is ResponsePendingStale, SuccessStale or ErrorStale`, () => { + expect(isStale(RequestEntryState.ResponsePendingStale)).toBeTrue(); + expect(isStale(RequestEntryState.SuccessStale)).toBeTrue(); + expect(isStale(RequestEntryState.ErrorStale)).toBeTrue(); + + expect(isStale(RequestEntryState.RequestPending)).toBeFalse(); + expect(isStale(RequestEntryState.ResponsePending)).toBeFalse(); + expect(isStale(RequestEntryState.Error)).toBeFalse(); + expect(isStale(RequestEntryState.Success)).toBeFalse(); + }); +}); diff --git a/src/app/core/data/request-entry-state.model.ts b/src/app/core/data/request-entry-state.model.ts index a813b6e7436..3aeace39d29 100644 --- a/src/app/core/data/request-entry-state.model.ts +++ b/src/app/core/data/request-entry-state.model.ts @@ -3,8 +3,9 @@ export enum RequestEntryState { ResponsePending = 'ResponsePending', Error = 'Error', Success = 'Success', + ResponsePendingStale = 'ResponsePendingStale', ErrorStale = 'ErrorStale', - SuccessStale = 'SuccessStale' + SuccessStale = 'SuccessStale', } /** @@ -42,12 +43,21 @@ export const isSuccessStale = (state: RequestEntryState) => */ export const isResponsePending = (state: RequestEntryState) => state === RequestEntryState.ResponsePending; + /** - * Returns true if the given state is RequestPending or ResponsePending, - * false otherwise + * Returns true if the given state is ResponsePendingStale, false otherwise + */ +export const isResponsePendingStale = (state: RequestEntryState) => + state === RequestEntryState.ResponsePendingStale; + +/** + * Returns true if the given state is RequestPending, RequestPendingStale, ResponsePending, or + * ResponsePendingStale, false otherwise */ export const isLoading = (state: RequestEntryState) => - isRequestPending(state) || isResponsePending(state); + isRequestPending(state) || + isResponsePending(state) || + isResponsePendingStale(state); /** * If isLoading is true for the given state, this method returns undefined, we can't know yet. @@ -82,7 +92,10 @@ export const hasCompleted = (state: RequestEntryState) => !isLoading(state); /** - * Returns true if the given state is SuccessStale or ErrorStale, false otherwise + * Returns true if the given state is isRequestPendingStale, isResponsePendingStale, SuccessStale or + * ErrorStale, false otherwise */ export const isStale = (state: RequestEntryState) => - isSuccessStale(state) || isErrorStale(state); + isResponsePendingStale(state) || + isSuccessStale(state) || + isErrorStale(state); diff --git a/src/app/core/data/request.reducer.spec.ts b/src/app/core/data/request.reducer.spec.ts index 05f074a96a7..86b9c4cd5dc 100644 --- a/src/app/core/data/request.reducer.spec.ts +++ b/src/app/core/data/request.reducer.spec.ts @@ -48,9 +48,16 @@ describe('requestReducer', () => { lastUpdated: 0 } }; + const testResponsePendingState = { + [id1]: { + state: RequestEntryState.ResponsePending, + lastUpdated: 0 + } + }; deepFreeze(testInitState); deepFreeze(testSuccessState); deepFreeze(testErrorState); + deepFreeze(testResponsePendingState); it('should return the current state when no valid actions have been made', () => { const action = new NullAction(); @@ -91,29 +98,94 @@ describe('requestReducer', () => { expect(newState[id1].response).toEqual(undefined); }); - it('should set state to Success for the given RestRequest in the state, in response to a SUCCESS action', () => { - const state = testInitState; + describe(`in response to a SUCCESS action`, () => { + let startState; + describe(`when the entry isn't stale`, () => { + beforeEach(() => { + startState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ResponsePending + }) + }); + deepFreeze(startState); + }); + it('should set state to Success for the given RestRequest in the state', () => { + const action = new RequestSuccessAction(id1, 200); + const newState = requestReducer(startState, action); - const action = new RequestSuccessAction(id1, 200); - const newState = requestReducer(state, action); + expect(newState[id1].request.uuid).toEqual(id1); + expect(newState[id1].request.href).toEqual(link1); + expect(newState[id1].state).toEqual(RequestEntryState.Success); + expect(newState[id1].response.statusCode).toEqual(200); + }); + }); + + describe(`when the entry is stale`, () => { + beforeEach(() => { + startState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ResponsePendingStale + }) + }); + deepFreeze(startState); + }); + it('should set state to SuccessStale for the given RestRequest in the state', () => { + const action = new RequestSuccessAction(id1, 200); + const newState = requestReducer(startState, action); + + expect(newState[id1].request.uuid).toEqual(id1); + expect(newState[id1].request.href).toEqual(link1); + expect(newState[id1].state).toEqual(RequestEntryState.SuccessStale); + expect(newState[id1].response.statusCode).toEqual(200); + }); + }); - expect(newState[id1].request.uuid).toEqual(id1); - expect(newState[id1].request.href).toEqual(link1); - expect(newState[id1].state).toEqual(RequestEntryState.Success); - expect(newState[id1].response.statusCode).toEqual(200); }); - it('should set state to Error for the given RestRequest in the state, in response to an ERROR action', () => { - const state = testInitState; + describe(`in response to an ERROR action`, () => { + let startState; + describe(`when the entry isn't stale`, () => { + beforeEach(() => { + startState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ResponsePending + }) + }); + deepFreeze(startState); + }); + it('should set state to Error for the given RestRequest in the state', () => { + const action = new RequestErrorAction(id1, 404, 'Not Found'); + const newState = requestReducer(startState, action); - const action = new RequestErrorAction(id1, 404, 'Not Found'); - const newState = requestReducer(state, action); + expect(newState[id1].request.uuid).toEqual(id1); + expect(newState[id1].request.href).toEqual(link1); + expect(newState[id1].state).toEqual(RequestEntryState.Error); + expect(newState[id1].response.statusCode).toEqual(404); + expect(newState[id1].response.errorMessage).toEqual('Not Found'); + }); + }); - expect(newState[id1].request.uuid).toEqual(id1); - expect(newState[id1].request.href).toEqual(link1); - expect(newState[id1].state).toEqual(RequestEntryState.Error); - expect(newState[id1].response.statusCode).toEqual(404); - expect(newState[id1].response.errorMessage).toEqual('Not Found'); + describe(`when the entry is stale`, () => { + beforeEach(() => { + startState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ResponsePendingStale + }) + }); + deepFreeze(startState); + }); + it('should set state to ErrorStale for the given RestRequest in the state', () => { + const action = new RequestErrorAction(id1, 404, 'Not Found'); + const newState = requestReducer(startState, action); + + expect(newState[id1].request.uuid).toEqual(id1); + expect(newState[id1].request.href).toEqual(link1); + expect(newState[id1].state).toEqual(RequestEntryState.ErrorStale); + expect(newState[id1].response.statusCode).toEqual(404); + expect(newState[id1].response.errorMessage).toEqual('Not Found'); + }); + + }); }); it('should update the response\'s timeCompleted for the given RestRequest in the state, in response to a RESET_TIMESTAMPS action', () => { @@ -145,28 +217,112 @@ describe('requestReducer', () => { expect(newState[id1]).toBeNull(); }); - describe(`for an entry with state: Success`, () => { - it(`should set the state to SuccessStale, in response to a STALE action`, () => { - const state = testSuccessState; + describe(`in response to a STALE action`, () => { + describe(`when the entry has been removed`, () => { + it(`shouldn't do anything`, () => { + const startState = { + [id1]: null + }; + deepFreeze(startState); - const action = new RequestStaleAction(id1); - const newState = requestReducer(state, action); + const action = new RequestStaleAction(id1); + const newState = requestReducer(startState, action); - expect(newState[id1].state).toEqual(RequestEntryState.SuccessStale); - expect(newState[id1].lastUpdated).toBe(action.lastUpdated); + expect(newState[id1]).toBeNull(); + }); }); - }); - describe(`for an entry with state: Error`, () => { - it(`should set the state to ErrorStale, in response to a STALE action`, () => { - const state = testErrorState; + describe(`for stale entries`, () => { + it(`shouldn't do anything`, () => { + const rpsStartState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ResponsePendingStale + }) + }); + deepFreeze(rpsStartState); + + const action = new RequestStaleAction(id1); + let newState = requestReducer(rpsStartState, action); + + expect(newState[id1].state).toEqual(rpsStartState[id1].state); + expect(newState[id1].lastUpdated).toBe(rpsStartState[id1].lastUpdated); - const action = new RequestStaleAction(id1); - const newState = requestReducer(state, action); + const ssStartState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.SuccessStale + }) + }); - expect(newState[id1].state).toEqual(RequestEntryState.ErrorStale); - expect(newState[id1].lastUpdated).toBe(action.lastUpdated); + newState = requestReducer(ssStartState, action); + + expect(newState[id1].state).toEqual(ssStartState[id1].state); + expect(newState[id1].lastUpdated).toBe(ssStartState[id1].lastUpdated); + + const esStartState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.ErrorStale + }) + }); + + newState = requestReducer(esStartState, action); + + expect(newState[id1].state).toEqual(esStartState[id1].state); + expect(newState[id1].lastUpdated).toBe(esStartState[id1].lastUpdated); + + }); }); - }); + describe(`for and entry with state: RequestPending`, () => { + it(`shouldn't do anything`, () => { + const startState = Object.assign({}, testInitState, { + [id1]: Object.assign({}, testInitState[id1], { + state: RequestEntryState.RequestPending + }) + }); + + const action = new RequestStaleAction(id1); + const newState = requestReducer(startState, action); + + expect(newState[id1].state).toEqual(startState[id1].state); + expect(newState[id1].lastUpdated).toBe(startState[id1].lastUpdated); + + }); + }); + + describe(`for an entry with state: ResponsePending`, () => { + it(`should set the state to ResponsePendingStale`, () => { + const state = testResponsePendingState; + + const action = new RequestStaleAction(id1); + const newState = requestReducer(state, action); + + expect(newState[id1].state).toEqual(RequestEntryState.ResponsePendingStale); + expect(newState[id1].lastUpdated).toBe(action.lastUpdated); + }); + }); + + describe(`for an entry with state: Success`, () => { + it(`should set the state to SuccessStale`, () => { + const state = testSuccessState; + + const action = new RequestStaleAction(id1); + const newState = requestReducer(state, action); + + expect(newState[id1].state).toEqual(RequestEntryState.SuccessStale); + expect(newState[id1].lastUpdated).toBe(action.lastUpdated); + }); + }); + + describe(`for an entry with state: Error`, () => { + it(`should set the state to ErrorStale`, () => { + const state = testErrorState; + + const action = new RequestStaleAction(id1); + const newState = requestReducer(state, action); + + expect(newState[id1].state).toEqual(RequestEntryState.ErrorStale); + expect(newState[id1].lastUpdated).toBe(action.lastUpdated); + }); + }); + }); }); diff --git a/src/app/core/data/request.reducer.ts b/src/app/core/data/request.reducer.ts index 9bf17faf8d7..9cf4fee0e2c 100644 --- a/src/app/core/data/request.reducer.ts +++ b/src/app/core/data/request.reducer.ts @@ -11,7 +11,13 @@ import { ResetResponseTimestampsAction } from './request.actions'; import { isNull } from '../../shared/empty.util'; -import { hasSucceeded, isStale, RequestEntryState } from './request-entry-state.model'; +import { + hasSucceeded, + isStale, + RequestEntryState, + isRequestPending, + isResponsePending +} from './request-entry-state.model'; import { RequestState } from './request-state.model'; // Object.create(null) ensures the object has no default js properties (e.g. `__proto__`) @@ -91,14 +97,17 @@ function executeRequest(storeState: RequestState, action: RequestExecuteAction): * the new storeState, with the response added to the request */ function completeSuccessRequest(storeState: RequestState, action: RequestSuccessAction): RequestState { - if (isNull(storeState[action.payload.uuid])) { + const prevEntry = storeState[action.payload.uuid]; + if (isNull(prevEntry)) { // after a request has been removed it's possible pending changes still come in. // Don't store them return storeState; } else { return Object.assign({}, storeState, { - [action.payload.uuid]: Object.assign({}, storeState[action.payload.uuid], { - state: RequestEntryState.Success, + [action.payload.uuid]: Object.assign({}, prevEntry, { + // If a response comes in for a request that's already stale, still store it otherwise + // components that are waiting for it might freeze + state: isStale(prevEntry.state) ? RequestEntryState.SuccessStale : RequestEntryState.Success, response: { timeCompleted: action.payload.timeCompleted, lastUpdated: action.payload.timeCompleted, @@ -124,14 +133,17 @@ function completeSuccessRequest(storeState: RequestState, action: RequestSuccess * the new storeState, with the response added to the request */ function completeFailedRequest(storeState: RequestState, action: RequestErrorAction): RequestState { - if (isNull(storeState[action.payload.uuid])) { + const prevEntry = storeState[action.payload.uuid]; + if (isNull(prevEntry)) { // after a request has been removed it's possible pending changes still come in. // Don't store them return storeState; } else { return Object.assign({}, storeState, { - [action.payload.uuid]: Object.assign({}, storeState[action.payload.uuid], { - state: RequestEntryState.Error, + [action.payload.uuid]: Object.assign({}, prevEntry, { + // If a response comes in for a request that's already stale, still store it otherwise + // components that are waiting for it might freeze + state: isStale(prevEntry.state) ? RequestEntryState.ErrorStale : RequestEntryState.Error, response: { timeCompleted: action.payload.timeCompleted, lastUpdated: action.payload.timeCompleted, @@ -155,22 +167,27 @@ function completeFailedRequest(storeState: RequestState, action: RequestErrorAct * the new storeState, set to stale */ function expireRequest(storeState: RequestState, action: RequestStaleAction): RequestState { - if (isNull(storeState[action.payload.uuid])) { - // after a request has been removed it's possible pending changes still come in. - // Don't store them + const prevEntry = storeState[action.payload.uuid]; + if (isNull(prevEntry) || isStale(prevEntry.state) || isRequestPending(prevEntry.state)) { + // No need to do anything if the entry doesn't exist, is already stale, or if the request is + // still pending, because that means it still needs to be sent to the server. Any response + // is guaranteed to have been generated after the request was set to stale. return storeState; } else { - const prevEntry = storeState[action.payload.uuid]; - if (isStale(prevEntry.state)) { - return storeState; + let nextRequestEntryState: RequestEntryState; + if (isResponsePending(prevEntry.state)) { + nextRequestEntryState = RequestEntryState.ResponsePendingStale; + } else if (hasSucceeded(prevEntry.state)) { + nextRequestEntryState = RequestEntryState.SuccessStale; } else { - return Object.assign({}, storeState, { - [action.payload.uuid]: Object.assign({}, prevEntry, { - state: hasSucceeded(prevEntry.state) ? RequestEntryState.SuccessStale : RequestEntryState.ErrorStale, - lastUpdated: action.lastUpdated - }) - }); + nextRequestEntryState = RequestEntryState.ErrorStale; } + return Object.assign({}, storeState, { + [action.payload.uuid]: Object.assign({}, prevEntry, { + state: nextRequestEntryState, + lastUpdated: action.lastUpdated + }) + }); } } diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index ec633370ce2..9f43c3f5992 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -164,7 +164,7 @@ export class RequestService { this.getByHref(request.href).pipe( take(1)) .subscribe((re: RequestEntry) => { - isPending = (hasValue(re) && isLoading(re.state)); + isPending = (hasValue(re) && isLoading(re.state) && !isStale(re.state)); }); return isPending; } diff --git a/src/app/core/shared/hal-endpoint.service.spec.ts b/src/app/core/shared/hal-endpoint.service.spec.ts index 56e890b3189..b81d0806dfd 100644 --- a/src/app/core/shared/hal-endpoint.service.spec.ts +++ b/src/app/core/shared/hal-endpoint.service.spec.ts @@ -1,4 +1,3 @@ -import { cold, hot } from 'jasmine-marbles'; import { getMockRequestService } from '../../shared/mocks/request.service.mock'; import { RequestService } from '../data/request.service'; import { HALEndpointService } from './hal-endpoint.service'; @@ -7,12 +6,17 @@ import { combineLatest as observableCombineLatest, of as observableOf } from 'rx import { environment } from '../../../environments/environment'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; +import { TestScheduler } from 'rxjs/testing'; +import { RemoteData } from '../data/remote-data'; +import { RequestEntryState } from '../data/request-entry-state.model'; describe('HALEndpointService', () => { let service: HALEndpointService; let requestService: RequestService; let rdbService: RemoteDataBuildService; let envConfig; + let testScheduler; + let remoteDataMocks; const endpointMap = { test: { href: 'https://rest.api/test' @@ -68,7 +72,30 @@ describe('HALEndpointService', () => { }; const linkPath = 'test'; + const timeStamp = new Date().getTime(); + const msToLive = 15 * 60 * 1000; + const payload = { + _links: endpointMaps[one] + }; + const statusCodeSuccess = 200; + const statusCodeError = 404; + const errorMessage = 'not found'; + remoteDataMocks = { + RequestPending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.RequestPending, undefined, undefined, undefined), + ResponsePending: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.ResponsePending, undefined, undefined, undefined), + ResponsePendingStale: new RemoteData(undefined, msToLive, timeStamp, RequestEntryState.ResponsePendingStale, undefined, undefined, undefined), + Success: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Success, undefined, payload, statusCodeSuccess), + SuccessStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.SuccessStale, undefined, payload, statusCodeSuccess), + Error: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.Error, errorMessage, undefined, statusCodeError), + ErrorStale: new RemoteData(timeStamp, msToLive, timeStamp, RequestEntryState.ErrorStale, errorMessage, undefined, statusCodeError), + }; + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + // asserting the two objects are equal + // e.g. using chai. + expect(actual).toEqual(expected); + }); requestService = getMockRequestService(); rdbService = jasmine.createSpyObj('rdbService', { buildFromHref: createSuccessfulRemoteDataObject$({ @@ -111,20 +138,28 @@ describe('HALEndpointService', () => { }); it(`should return the endpoint URL for the service's linkPath`, () => { - spyOn(service as any, 'getEndpointAt').and - .returnValue(hot('a-', { a: 'https://rest.api/test' })); - const result = service.getEndpoint(linkPath); - - const expected = cold('(b|)', { b: endpointMap.test.href }); - expect(result).toBeObservable(expected); + testScheduler.run(({ cold, expectObservable }) => { + spyOn(service as any, 'getEndpointAt').and + .returnValue(cold('a-', { a: 'https://rest.api/test' })); + const result = service.getEndpoint(linkPath); + + const expected = '(b|)'; + const values = { + b: endpointMap.test.href + }; + expectObservable(result).toBe(expected, values); + }); }); it('should return undefined for a linkPath that isn\'t in the endpoint map', () => { - spyOn(service as any, 'getEndpointAt').and - .returnValue(hot('a-', { a: undefined })); - const result = service.getEndpoint('unknown'); - const expected = cold('(b|)', { b: undefined }); - expect(result).toBeObservable(expected); + testScheduler.run(({ cold, expectObservable }) => { + spyOn(service as any, 'getEndpointAt').and + .returnValue(cold('a-', { a: undefined })); + const result = service.getEndpoint('unknown'); + const expected = '(b|)'; + const values = { b: undefined }; + expectObservable(result).toBe(expected, values); + }); }); }); @@ -183,29 +218,118 @@ describe('HALEndpointService', () => { }); it('should return undefined as long as getRootEndpointMap hasn\'t fired', () => { - spyOn(service as any, 'getRootEndpointMap').and - .returnValue(hot('----')); - - const result = service.isEnabledOnRestApi(linkPath); - const expected = cold('b---', { b: undefined }); - expect(result).toBeObservable(expected); + testScheduler.run(({ cold, expectObservable }) => { + spyOn(service as any, 'getRootEndpointMap').and + .returnValue(cold('----')); + + const result = service.isEnabledOnRestApi(linkPath); + const expected = 'b---'; + const values = { b: undefined }; + expectObservable(result).toBe(expected, values); + }); }); it('should return true if the service\'s linkPath is in the endpoint map', () => { - spyOn(service as any, 'getRootEndpointMap').and - .returnValue(hot('--a-', { a: endpointMap })); - const result = service.isEnabledOnRestApi(linkPath); - const expected = cold('b-c-', { b: undefined, c: true }); - expect(result).toBeObservable(expected); + testScheduler.run(({ cold, expectObservable }) => { + spyOn(service as any, 'getRootEndpointMap').and + .returnValue(cold('--a-', { a: endpointMap })); + const result = service.isEnabledOnRestApi(linkPath); + const expected = 'b-c-'; + const values = { b: undefined, c: true }; + expectObservable(result).toBe(expected, values); + }); }); it('should return false if the service\'s linkPath isn\'t in the endpoint map', () => { - spyOn(service as any, 'getRootEndpointMap').and - .returnValue(hot('--a-', { a: endpointMap })); + testScheduler.run(({ cold, expectObservable }) => { + spyOn(service as any, 'getRootEndpointMap').and + .returnValue(cold('--a-', { a: endpointMap })); + + const result = service.isEnabledOnRestApi('unknown'); + const expected = 'b-c-'; + const values = { b: undefined, c: false }; + expectObservable(result).toBe(expected, values); + }); + }); + + }); + + describe(`getEndpointMapAt`, () => { + const href = 'https://rest.api/some/sub/path'; + + it(`should call requestService.send with a new EndpointMapRequest for the given href. useCachedVersionIfAvailable should be true`, () => { + testScheduler.run(() => { + (service as any).getEndpointMapAt(href); + }); + const expected = new EndpointMapRequest(requestService.generateRequestId(), href); + expect(requestService.send).toHaveBeenCalledWith(expected, true); + }); + + it(`should call rdbService.buildFromHref with the given href`, () => { + testScheduler.run(() => { + (service as any).getEndpointMapAt(href); + }); + expect(rdbService.buildFromHref).toHaveBeenCalledWith(href); + }); + + describe(`when the RemoteData returned from rdbService is stale`, () => { + it(`should re-request it`, () => { + spyOn(service as any, 'getEndpointMapAt').and.callThrough(); + testScheduler.run(({ cold }) => { + (rdbService.buildFromHref as jasmine.Spy).and.returnValue(cold('a', { a: remoteDataMocks.ResponsePendingStale })); + // we need to subscribe to the result, to ensure the "tap" that does the re-request can fire + (service as any).getEndpointMapAt(href).subscribe(); + }); + expect((service as any).getEndpointMapAt).toHaveBeenCalledTimes(2); + }); + }); + + describe(`when the RemoteData returned from rdbService isn't stale`, () => { + it(`should not re-request it`, () => { + spyOn(service as any, 'getEndpointMapAt').and.callThrough(); + testScheduler.run(({ cold }) => { + (rdbService.buildFromHref as jasmine.Spy).and.returnValue(cold('a', { a: remoteDataMocks.ResponsePending })); + // we need to subscribe to the result, to ensure the "tap" that does the re-request can fire + (service as any).getEndpointMapAt(href).subscribe(); + }); + expect((service as any).getEndpointMapAt).toHaveBeenCalledTimes(1); + }); + }); - const result = service.isEnabledOnRestApi('unknown'); - const expected = cold('b-c-', { b: undefined, c: false }); - expect(result).toBeObservable(expected); + it(`should emit exactly once, returning the endpoint map in the response, when the RemoteData completes`, () => { + testScheduler.run(({ cold, expectObservable }) => { + (rdbService.buildFromHref as jasmine.Spy).and.returnValue(cold('a-b-c-d-e-f-g-h-i-j-k-l', { + a: remoteDataMocks.RequestPending, + b: remoteDataMocks.ResponsePending, + c: remoteDataMocks.ResponsePendingStale, + d: remoteDataMocks.SuccessStale, + e: remoteDataMocks.RequestPending, + f: remoteDataMocks.ResponsePending, + g: remoteDataMocks.Success, + h: remoteDataMocks.SuccessStale, + i: remoteDataMocks.RequestPending, + k: remoteDataMocks.ResponsePending, + l: remoteDataMocks.Error, + })); + const expected = '------------(g|)'; + const values = { + g: endpointMaps[one] + }; + expectObservable((service as any).getEndpointMapAt(one)).toBe(expected, values); + }); + }); + + it(`should emit undefined when the response doesn't have a payload`, () => { + testScheduler.run(({ cold, expectObservable }) => { + (rdbService.buildFromHref as jasmine.Spy).and.returnValue(cold('a', { + a: remoteDataMocks.Error, + })); + const expected = '(a|)'; + const values = { + g: undefined + }; + expectObservable((service as any).getEndpointMapAt(href)).toBe(expected, values); + }); }); }); diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts index 5cdd7ccfad7..07754616c73 100644 --- a/src/app/core/shared/hal-endpoint.service.ts +++ b/src/app/core/shared/hal-endpoint.service.ts @@ -1,11 +1,19 @@ import { Observable } from 'rxjs'; -import { distinctUntilChanged, map, startWith, switchMap, take, skipWhile } from 'rxjs/operators'; +import { + distinctUntilChanged, + map, + startWith, + switchMap, + take, + tap, filter +} from 'rxjs/operators'; import { RequestService } from '../data/request.service'; import { EndpointMapRequest } from '../data/request.models'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { Injectable } from '@angular/core'; import { EndpointMap } from '../cache/response.models'; +import { getFirstCompletedRemoteData } from './operators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { RemoteData } from '../data/remote-data'; import { CacheableObject } from '../cache/cacheable-object.model'; @@ -33,11 +41,16 @@ export class HALEndpointService { this.requestService.send(request, true); return this.rdbService.buildFromHref<CacheableObject>(href).pipe( - // This skip ensures that if a stale object is present in the cache when you do a - // call it isn't immediately returned, but we wait until the remote data for the new request - // is created. - skipWhile((rd: RemoteData<CacheableObject>) => rd.isLoading || rd.isStale), - take(1), + // Re-request stale responses + tap((rd: RemoteData<CacheableObject>) => { + if (hasValue(rd) && rd.isStale) { + this.getEndpointMapAt(href); + } + }), + // Filter out all stale responses. We're only interested in a single, non-stale, + // completed RemoteData + filter((rd: RemoteData<CacheableObject>) => !rd.isStale), + getFirstCompletedRemoteData(), map((response: RemoteData<CacheableObject>) => { if (hasValue(response.payload)) { return response.payload._links; From 92a74cee5aa2e4a9085a7a3d7694edf4855d6281 Mon Sep 17 00:00:00 2001 From: Sascha Szott <szott@gmx.de> Date: Wed, 10 Jan 2024 16:54:18 +0100 Subject: [PATCH 267/282] use localized error message --- src/app/core/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 6604936cde1..8b08b4f32db 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -119,7 +119,7 @@ export class AuthService { if (hasValue(rd.payload) && rd.payload.authenticated) { return rd.payload; } else { - throw (new Error('Invalid email or password')); + throw (new Error('auth.errors.invalid-user')); } })); From 7fbb692e94b6bcf9f16c8b2ec6880831175b936e Mon Sep 17 00:00:00 2001 From: Dawnkai <dawnwender@gmail.com> Date: Fri, 27 Oct 2023 14:32:50 +0200 Subject: [PATCH 268/282] Deque Analysis Color Contrast fixes --- .../dso-edit-metadata-value.component.scss | 16 +++ src/app/shared/alert/alert.component.scss | 3 + .../notification/notification.component.scss | 6 + .../search-range-filter.component.scss | 8 +- .../submission-form-footer.component.scss | 15 +++ src/styles/_bootstrap_variables.scss | 5 +- src/styles/_custom_variables.scss | 15 ++- src/styles/_global-styles.scss | 107 ++++++++++++++++-- 8 files changed, 161 insertions(+), 14 deletions(-) diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss index 4a207ee1a4a..e3bda1697a7 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss @@ -14,3 +14,19 @@ .cdk-drag-placeholder { opacity: 0; } + +.btn.btn-outline-warning:not(:disabled):hover { + background-color: #7f480c; +} +.btn.btn-success:not(:disabled):focus, .btn.btn-outline-success:not(:disabled):focus{ + outline: 2px solid rgba(43, 99, 47, 1) +} +.btn.btn-danger:not(:disabled):focus, .btn.btn-outline-danger:not(:disabled):focus{ + outline: 2px solid rgba(190, 114, 114, 1); +} +.btn.btn-warning:not(:disabled):focus, .btn.btn-outline-warning:not(:disabled):focus { + outline: 2px solid rgba(88, 87, 65, 1); +} +.btn.btn-primary:not(:disabled):focus, .btn.btn-outline-primary:not(:disabled):focus { + outline: 2px solid rgba(130, 135, 139, 1); +} diff --git a/src/app/shared/alert/alert.component.scss b/src/app/shared/alert/alert.component.scss index 1a70081367a..7b225a47b55 100644 --- a/src/app/shared/alert/alert.component.scss +++ b/src/app/shared/alert/alert.component.scss @@ -1,3 +1,6 @@ .close:focus { outline: none !important; } +button.close { + opacity: 0.6; +} diff --git a/src/app/shared/notifications/notification/notification.component.scss b/src/app/shared/notifications/notification/notification.component.scss index 06c46b0f5d0..aa0720afb70 100644 --- a/src/app/shared/notifications/notification/notification.component.scss +++ b/src/app/shared/notifications/notification/notification.component.scss @@ -30,3 +30,9 @@ .alert-warning .notification-progress-loader span { background: var(--ds-notification-bg-warning); } +.alert-success{ + color: var(--ds-notification-success-color); +} +.alert-danger { + color: var(--ds-notification-danger-color); +} diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss index b1cfa841f83..8d207dd023c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss @@ -26,7 +26,7 @@ } .noUi-connect { - background: var(--ds-slider-color); + background: var(--ds-range-filter-connect-color); } .noUi-target { @@ -37,4 +37,10 @@ margin: 0 calc(-1 * (var(--ds-slider-handle-width) / 2)); width: calc(100% + var(--ds-slider-handle-width)); } + .noUi-handle { + border-color: var(--ds-range-filter-border-color); + &::before, &::after { + background-color: var(--ds-range-filter-border-color); + } + } } diff --git a/src/app/submission/form/footer/submission-form-footer.component.scss b/src/app/submission/form/footer/submission-form-footer.component.scss index e69de29bb2d..a435e5c3932 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.scss +++ b/src/app/submission/form/footer/submission-form-footer.component.scss @@ -0,0 +1,15 @@ +:host{ + .btn:focus, .btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-primary.dropdown-toggle:focus, .custom-control-input:focus ~ .custom-control-label::before{ + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.25), 0 0 0 0.2rem rgba(27, 41, 55, 0.6); + } + + .btn.btn-success:focus{ + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(0, 100, 0, 0.7) + } + .btn.btn-danger:focus{ + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(200, 0, 0, 0.7) + } + .btn.btn-warning:focus{ + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(89, 81, 0, 0.7) + } +} diff --git a/src/styles/_bootstrap_variables.scss b/src/styles/_bootstrap_variables.scss index 5dfc03fbd36..cc3d09369bc 100644 --- a/src/styles/_bootstrap_variables.scss +++ b/src/styles/_bootstrap_variables.scss @@ -26,10 +26,9 @@ $green: #94BA65 !default; $cyan: #006666 !default; $yellow: #ec9433 !default; $red: #CF4444 !default; +$teal: #1F7293 !default; $dark: darken($blue, 17%) !default; - - $theme-colors: ( primary: $blue, secondary: $gray-700, @@ -41,7 +40,7 @@ $theme-colors: ( dark: $dark ) !default; /* Fonts */ -$link-color: map-get($theme-colors, info) !default; +$link-color: $teal !default; $navbar-dark-color: rgba(white, .5) !default; $navbar-light-color: rgba(black, .5) !default; diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 778ef6e9e3a..0e356a5a376 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -61,6 +61,19 @@ --ds-notification-bg-danger: #{darken(adjust-hue($danger, -10), 10%)}; --ds-notification-bg-info: #{darken(adjust-hue($info, -10), 10%)}; --ds-notification-bg-warning: #{darken(adjust-hue($warning, -10), 10%)}; + --ds-notification-success-color: #307B23; + --ds-notification-danger-color: #9a6e6e; + --ds-text-warning-color: #cf822c; + --ds-text-success-color: #74a030; + --ds-range-filter-border-color: #949494; + --ds-range-filter-connect-color: #63852e; + + --ds-badge-archived-background-color: #2a701e; + --ds-badge-archived-color: #000; + --ds-button-success-background-color: #358726; + --ds-button-success-background-hover-color: #{darken(#358726, 10%)}; + --ds-button-warning-background-color: #{darken($yellow, 20%)}; + --ds-button-warning-background-hover-color: #{darken($yellow, 30%)}; --ds-fa-fixed-width: #{$fa-fixed-width}; --ds-icon-padding: #{$icon-padding}; @@ -81,7 +94,7 @@ --ds-home-news-background-color: #{$gray-200}; --ds-breadcrumb-bg: #{$gray-200} !important; - --ds-breadcrumb-link-color: #{$cyan}; + --ds-breadcrumb-link-color: #{darken($cyan, 10%)}; --ds-breadcrumb-link-active-color: #{darken($cyan, 30%)}; --ds-breadcrumb-max-length: 200px; diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index 00fcb0f86f1..16a4799e1eb 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -234,7 +234,8 @@ ds-dynamic-form-control-container.d-none { } .badge-archived { - background-color: #{map-get($theme-colors, success)}; + background-color: var(--ds-badge-archived-background-color); + color: var(--ds-badge-archived-color) } .badge-workflow { @@ -269,27 +270,115 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { } .pt-0\.5 { - padding-top: 0.125rem !important; + padding-top: 0.125rem !important; } .pr-0\.5 { - padding-right: 0.125rem !important; + padding-right: 0.125rem !important; } .pb-0\.5 { - padding-bottom: 0.125rem !important; + padding-bottom: 0.125rem !important; } .pl-0\.5 { - padding-left: 0.125rem !important; + padding-left: 0.125rem !important; } .px-0\.5 { - padding-left: 0.125rem !important; - padding-right: 0.125rem !important; + padding-left: 0.125rem !important; + padding-right: 0.125rem !important; } .py-0\.5 { - padding-top: 0.125rem !important; - padding-bottom: 0.125rem !important; + padding-top: 0.125rem !important; + padding-bottom: 0.125rem !important; +} + +.btn.btn-success{ + background-color: var(--ds-button-success-background-color); + border-color: var(--ds-button-success-background-color); + &:hover{ + background-color: var(--ds-button-success-background-hover-color); + border-color: var(--ds-button-success-background-hover-color); + } +} +.btn.btn-outline-success{ + border-color: var(--ds-button-success-background-color); + color: var(--ds-button-success-background-color); + &:hover{ + background-color: var(--ds-button-success-background-hover-color); + color: $white; + } +} +.btn.btn-outline-warning{ + border-color:var(--ds-button-warning-background-color); + color:var(--ds-button-warning-background-color); + &:hover{ + background-color:var(--ds-button-warning-background-hover-color); + color: $white; + } + &:disabled{ + background-color: transparent; + &:hover{ + color:var(--ds-button-warning-background-color); + } + } +} + + +.btn:focus, .btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-primary.dropdown-toggle:focus, .custom-control-input:focus ~ .custom-control-label::before, .form-control:focus, .page-link:focus{ + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.25), 0 0 0 0.2rem rgba(27, 41, 55, 0.5); +} + +.btn.btn-success:focus, .btn.btn-outline-success:focus{ + outline: 2px solid rgba(76, 145, 76, 1); + outline-offset: 2px; + box-shadow: none; +} +.btn.btn-danger:focus, .btn.btn-outline-danger:focus{ + outline: 2px solid rgba(205, 126, 126, 1); + outline-offset: 2px; + box-shadow: none; +} +.btn.btn-warning:focus, .btn.btn-outline-warning:focus { + outline: 2px solid rgba(88, 87, 65, 1); + outline-offset: 2px; + box-shadow: none; +} +.btn.btn-primary:focus, .btn.btn-outline-primary:focus { + box-shadow: none; + outline: 2px solid rgba(134, 137, 139, 1); + outline-offset: 2px; +} +.btn.btn-secondary:focus, .btn.btn-outline-secondary:focus { + box-shadow: none; + outline: 2px solid rgba(141, 148, 155, 1); + outline-offset: 2px; +} +.btn.btn-warning{ + background-color:var(--ds-button-warning-background-color); + &:hover{ + background-color:var(--ds-button-warning-background-hover-color); + } + &:disabled{ + background-color: transparent; + } +} +dynamic-ng-bootstrap-checkbox .custom-control-label::before { + border-color: #858c91; +} +.text-warning { + color: var(--ds-text-warning-color) !important; +} +.text-success { + color: var(--ds-text-success-color) !important; +} +ngb-accordion { + a.close { + opacity: 0.75; + } + a.close:not(:disabled):not(.disabled):hover { + opacity: 0.9; + } } From c20b0a7c1156a844ac09c32d24464a61f1a69c7c Mon Sep 17 00:00:00 2001 From: Maciej Kleban <dawnwender@gmail.com> Date: Fri, 17 Nov 2023 17:11:08 +0100 Subject: [PATCH 269/282] Replace hard-coded colors with bootstrap variants * Replace custom variables with Bootstrap variants * Replace custom button colors with Bootstrap variants * Remove custom colors and replace them with bootstrap variants * Fix checkbox offset styles --------- Co-authored-by: Maciej Kleban <maciej.kleban@pcgacademia.pl> --- .../dso-edit-metadata-value.component.scss | 16 -- src/app/shared/alert/alert.component.scss | 7 +- .../notification/notification.component.scss | 9 +- .../search-range-filter.component.scss | 6 +- .../submission-form-footer.component.scss | 15 -- src/styles/_custom_variables.scss | 16 +- src/styles/_global-styles.scss | 230 ++++++++++-------- .../_theme_sass_variable_overrides.scss | 2 +- 8 files changed, 148 insertions(+), 153 deletions(-) diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss index e3bda1697a7..4a207ee1a4a 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.scss @@ -14,19 +14,3 @@ .cdk-drag-placeholder { opacity: 0; } - -.btn.btn-outline-warning:not(:disabled):hover { - background-color: #7f480c; -} -.btn.btn-success:not(:disabled):focus, .btn.btn-outline-success:not(:disabled):focus{ - outline: 2px solid rgba(43, 99, 47, 1) -} -.btn.btn-danger:not(:disabled):focus, .btn.btn-outline-danger:not(:disabled):focus{ - outline: 2px solid rgba(190, 114, 114, 1); -} -.btn.btn-warning:not(:disabled):focus, .btn.btn-outline-warning:not(:disabled):focus { - outline: 2px solid rgba(88, 87, 65, 1); -} -.btn.btn-primary:not(:disabled):focus, .btn.btn-outline-primary:not(:disabled):focus { - outline: 2px solid rgba(130, 135, 139, 1); -} diff --git a/src/app/shared/alert/alert.component.scss b/src/app/shared/alert/alert.component.scss index 7b225a47b55..907edae24bf 100644 --- a/src/app/shared/alert/alert.component.scss +++ b/src/app/shared/alert/alert.component.scss @@ -1,5 +1,8 @@ -.close:focus { - outline: none !important; +.close { + opacity: 0.75; + &:focus { + outline: none !important; + } } button.close { opacity: 0.6; diff --git a/src/app/shared/notifications/notification/notification.component.scss b/src/app/shared/notifications/notification/notification.component.scss index aa0720afb70..ecfc25fee06 100644 --- a/src/app/shared/notifications/notification/notification.component.scss +++ b/src/app/shared/notifications/notification/notification.component.scss @@ -5,7 +5,8 @@ } .close { - outline: none !important + outline: none !important; + opacity: 0.8; } .notification-icon { @@ -30,9 +31,3 @@ .alert-warning .notification-progress-loader span { background: var(--ds-notification-bg-warning); } -.alert-success{ - color: var(--ds-notification-success-color); -} -.alert-danger { - color: var(--ds-notification-danger-color); -} diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss index 8d207dd023c..1240f356786 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.scss @@ -26,7 +26,7 @@ } .noUi-connect { - background: var(--ds-range-filter-connect-color); + background: var(--ds-slider-color); } .noUi-target { @@ -38,9 +38,9 @@ width: calc(100% + var(--ds-slider-handle-width)); } .noUi-handle { - border-color: var(--ds-range-filter-border-color); + border-color: var(--ds-slider-handle-color); &::before, &::after { - background-color: var(--ds-range-filter-border-color); + background-color: var(--ds-slider-handle-color); } } } diff --git a/src/app/submission/form/footer/submission-form-footer.component.scss b/src/app/submission/form/footer/submission-form-footer.component.scss index a435e5c3932..e69de29bb2d 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.scss +++ b/src/app/submission/form/footer/submission-form-footer.component.scss @@ -1,15 +0,0 @@ -:host{ - .btn:focus, .btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-primary.dropdown-toggle:focus, .custom-control-input:focus ~ .custom-control-label::before{ - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.25), 0 0 0 0.2rem rgba(27, 41, 55, 0.6); - } - - .btn.btn-success:focus{ - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(0, 100, 0, 0.7) - } - .btn.btn-danger:focus{ - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(200, 0, 0, 0.7) - } - .btn.btn-warning:focus{ - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 0.2rem rgba(89, 81, 0, 0.7) - } -} diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 0e356a5a376..37af68509e9 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -61,19 +61,6 @@ --ds-notification-bg-danger: #{darken(adjust-hue($danger, -10), 10%)}; --ds-notification-bg-info: #{darken(adjust-hue($info, -10), 10%)}; --ds-notification-bg-warning: #{darken(adjust-hue($warning, -10), 10%)}; - --ds-notification-success-color: #307B23; - --ds-notification-danger-color: #9a6e6e; - --ds-text-warning-color: #cf822c; - --ds-text-success-color: #74a030; - --ds-range-filter-border-color: #949494; - --ds-range-filter-connect-color: #63852e; - - --ds-badge-archived-background-color: #2a701e; - --ds-badge-archived-color: #000; - --ds-button-success-background-color: #358726; - --ds-button-success-background-hover-color: #{darken(#358726, 10%)}; - --ds-button-warning-background-color: #{darken($yellow, 20%)}; - --ds-button-warning-background-hover-color: #{darken($yellow, 30%)}; --ds-fa-fixed-width: #{$fa-fixed-width}; --ds-icon-padding: #{$icon-padding}; @@ -98,8 +85,9 @@ --ds-breadcrumb-link-active-color: #{darken($cyan, 30%)}; --ds-breadcrumb-max-length: 200px; - --ds-slider-color: #{$green}; + --ds-slider-color: #{darken($green, 20%)}; --ds-slider-handle-width: 18px; + --ds-slider-handle-color: #{darken($blue, 17%)}; --ds-search-form-scope-max-width: 150px; diff --git a/src/styles/_global-styles.scss b/src/styles/_global-styles.scss index 16a4799e1eb..27d11250b4a 100644 --- a/src/styles/_global-styles.scss +++ b/src/styles/_global-styles.scss @@ -222,51 +222,50 @@ ds-dynamic-form-control-container.d-none { } .badge-validation { - background-color: #{map-get($theme-colors, warning)}; + background-color: #{map-get($theme-colors, warning)}; } .badge-waiting-controller { - background-color: #{map-get($theme-colors, info)}; + background-color: #{map-get($theme-colors, info)}; } .badge-workspace { - background-color: #{map-get($theme-colors, primary)}; + background-color: #{map-get($theme-colors, primary)}; } .badge-archived { - background-color: var(--ds-badge-archived-background-color); - color: var(--ds-badge-archived-color) + background-color: darken($green, 25); } .badge-workflow { - background-color: #{map-get($theme-colors, info)}; + background-color: #{map-get($theme-colors, info)}; } .badge-item-type { - background-color: #{map-get($theme-colors, info)}; + background-color: #{map-get($theme-colors, info)}; } .visually-hidden { - position: absolute !important; - width: 1px !important; - height: 1px !important; - padding: 0 !important; - margin: -1px !important; - overflow: hidden !important; - clip: rect(0, 0, 0, 0) !important; - white-space: nowrap !important; - border: 0 !important; -} - -ul.dso-edit-menu-dropdown > li .nav-item.nav-link { - // ensure that links in DSO edit menu dropdowns are unstyled (li elements are styled instead to support icons) - padding: 0; - display: inline; + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +ul.dso-edit-menu-dropdown>li .nav-item.nav-link { + // ensure that links in DSO edit menu dropdowns are unstyled (li elements are styled instead to support icons) + padding: 0; + display: inline; } .table th, .table td { - vertical-align: middle; + vertical-align: middle; } .pt-0\.5 { @@ -295,85 +294,107 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link { padding-bottom: 0.125rem !important; } -.btn.btn-success{ - background-color: var(--ds-button-success-background-color); - border-color: var(--ds-button-success-background-color); - &:hover{ - background-color: var(--ds-button-success-background-hover-color); - border-color: var(--ds-button-success-background-hover-color); - } -} -.btn.btn-outline-success{ - border-color: var(--ds-button-success-background-color); - color: var(--ds-button-success-background-color); - &:hover{ - background-color: var(--ds-button-success-background-hover-color); - color: $white; - } -} -.btn.btn-outline-warning{ - border-color:var(--ds-button-warning-background-color); - color:var(--ds-button-warning-background-color); - &:hover{ - background-color:var(--ds-button-warning-background-hover-color); - color: $white; - } - &:disabled{ - background-color: transparent; - &:hover{ - color:var(--ds-button-warning-background-color); - } - } -} - - -.btn:focus, .btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-primary.dropdown-toggle:focus, .custom-control-input:focus ~ .custom-control-label::before, .form-control:focus, .page-link:focus{ - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.25), 0 0 0 0.2rem rgba(27, 41, 55, 0.5); -} - -.btn.btn-success:focus, .btn.btn-outline-success:focus{ - outline: 2px solid rgba(76, 145, 76, 1); - outline-offset: 2px; - box-shadow: none; -} -.btn.btn-danger:focus, .btn.btn-outline-danger:focus{ - outline: 2px solid rgba(205, 126, 126, 1); - outline-offset: 2px; - box-shadow: none; -} -.btn.btn-warning:focus, .btn.btn-outline-warning:focus { - outline: 2px solid rgba(88, 87, 65, 1); - outline-offset: 2px; - box-shadow: none; -} -.btn.btn-primary:focus, .btn.btn-outline-primary:focus { - box-shadow: none; - outline: 2px solid rgba(134, 137, 139, 1); - outline-offset: 2px; -} -.btn.btn-secondary:focus, .btn.btn-outline-secondary:focus { - box-shadow: none; - outline: 2px solid rgba(141, 148, 155, 1); - outline-offset: 2px; -} -.btn.btn-warning{ - background-color:var(--ds-button-warning-background-color); - &:hover{ - background-color:var(--ds-button-warning-background-hover-color); - } - &:disabled{ - background-color: transparent; - } +.btn { + &:focus { + outline-offset: 2px !important; + outline-style: solid !important; + outline-width: 2px !important; + box-shadow: none !important; + } + &:disabled { + opacity: 0.7; + } + &.btn-success { + background-color: darken($success, 20%); + border-color: darken($success, 20%); + &:hover { + background-color: darken($success, 30%); + border-color: darken($success, 30%); + } + &:focus { + outline-color: darken($success, 20%); + } + } + &.btn-outline-success { + border-color: darken($success, 20%); + color: darken($success, 20%); + + &:hover { + background-color: darken($success, 30%); + color: $white; + } + &:focus { + outline-color: darken($success, 20%); + } + } + &.btn-warning { + background-color: darken($warning, 20%); + &:hover { + background-color: darken($warning, 30%); + } + &:disabled { + background-color: transparent; + } + &:focus { + outline-color: darken($warning, 22%); + } + } + + &.btn-outline-warning { + border-color: darken($warning, 20%); + color: darken($warning, 20%); + &:hover { + background-color: darken($warning, 30%); + color: $white; + } + &:disabled { + background-color: transparent; + + &:hover { + color: darken($warning, 20%); + } + } + :focus { + outline-color: darken($warning, 22%); + } + &:not(:disabled):hover { + background-color: darken($warning, 22%); + } + } + + &.btn-secondary { + &:focus { + outline-color: darken($secondary, 20%); + } + } + + &.btn-danger:focus, &.btn-outline-danger:focus { + outline-color: darken($danger, 20%); + } + + &.btn-primary:focus, &.btn-outline-primary:focus { + outline-color: darken($primary, 5%); + } +} + +dynamic-ng-bootstrap-checkbox .custom-control-input:focus ~ .custom-control-label::before { + outline: 2px solid $gray-700 !important; + box-shadow: none !important; + outline-offset: 2px !important; } + dynamic-ng-bootstrap-checkbox .custom-control-label::before { - border-color: #858c91; + border-color: $gray-700; } + .text-warning { - color: var(--ds-text-warning-color) !important; + color: darken($warning, 10%) !important; } + .text-success { - color: var(--ds-text-success-color) !important; + color: darken($success, 11%) !important; } + ngb-accordion { a.close { opacity: 0.75; @@ -382,3 +403,22 @@ ngb-accordion { opacity: 0.9; } } + +.form-control, .page-link { + &:disabled::placeholder { + color: lighten($gray-700, 10%); + } + &:focus { + box-shadow: none; + outline: 2px solid lighten($gray-700, 10%); + outline-offset: 2px !important; + } +} + +.alert-success { + color: darken($success, 22%); +} + +.alert-danger { + color: darken($danger, 22%); +} diff --git a/src/themes/dspace/styles/_theme_sass_variable_overrides.scss b/src/themes/dspace/styles/_theme_sass_variable_overrides.scss index b5799c97496..aaa27f6f9e7 100644 --- a/src/themes/dspace/styles/_theme_sass_variable_overrides.scss +++ b/src/themes/dspace/styles/_theme_sass_variable_overrides.scss @@ -12,7 +12,7 @@ $navbar-dark-color: #FFFFFF; /* Reassign color vars to semantic color scheme */ $blue: #2b4e72 !default; $green: #92C642 !default; -$cyan: #207698 !default; +$cyan: #1e6f90 !default; $yellow: #ec9433 !default; $red: #CF4444 !default; $dark: #43515f !default; From 53d521a87e7e1962875f29f9f2f868b717f825ef Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 30 Aug 2023 16:00:10 -0500 Subject: [PATCH 270/282] Add new e2e accessibility tests & update some existing ones --- cypress/e2e/login-modal.cy.ts | 21 +++++++++++++++++---- cypress/e2e/my-dspace.cy.ts | 16 +++++----------- cypress/e2e/search-page.cy.ts | 5 ++--- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/cypress/e2e/login-modal.cy.ts b/cypress/e2e/login-modal.cy.ts index d29c13c2f96..d4559dc6bf9 100644 --- a/cypress/e2e/login-modal.cy.ts +++ b/cypress/e2e/login-modal.cy.ts @@ -109,6 +109,9 @@ describe('Login Modal', () => { cy.get('ds-themed-navbar [data-test="register"]').click(); cy.location('pathname').should('eq', '/register'); cy.get('ds-register-email').should('exist'); + + // Test accessibility of this page + testA11y('ds-register-email'); }); it('should allow forgot password', () => { @@ -123,16 +126,26 @@ describe('Login Modal', () => { cy.get('ds-themed-navbar [data-test="forgot"]').click(); cy.location('pathname').should('eq', '/forgot'); cy.get('ds-forgot-email').should('exist'); + + // Test accessibility of this page + testA11y('ds-forgot-email'); }); - it('should pass accessibility tests', () => { + it('should pass accessibility tests in menus', () => { cy.visit('/'); + // Open login menu & verify accessibility page.openLoginMenu(); - cy.get('ds-log-in').should('exist'); - - // Analyze <ds-log-in> for accessibility issues testA11y('ds-log-in'); + + // Now login + page.submitLoginAndPasswordByPressingButton(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + cy.get('ds-log-in').should('not.exist'); + + // Open user menu, verify user menu accesibility + page.openUserMenu(); + cy.get('ds-user-menu').should('be.visible'); + testA11y('ds-user-menu'); }); }); diff --git a/cypress/e2e/my-dspace.cy.ts b/cypress/e2e/my-dspace.cy.ts index 13f4a1b5471..4b27fe13de6 100644 --- a/cypress/e2e/my-dspace.cy.ts +++ b/cypress/e2e/my-dspace.cy.ts @@ -1,4 +1,3 @@ -import { Options } from 'cypress-axe'; import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; @@ -35,16 +34,8 @@ describe('My DSpace page', () => { cy.get('ds-object-detail').should('be.visible'); - // Analyze <ds-search-page> for accessibility issues - testA11y('ds-my-dspace-page', - { - rules: { - // Search filters fail these two "moderate" impact rules - 'heading-order': { enabled: false }, - 'landmark-unique': { enabled: false } - } - } as Options - ); + // Analyze <ds-my-dspace-page> for accessibility issues + testA11y('ds-my-dspace-page'); }); // NOTE: Deleting existing submissions is exercised by submission.spec.ts @@ -136,6 +127,9 @@ describe('My DSpace page', () => { // The external import searchbox should be visible cy.get('ds-submission-import-external-searchbar').should('be.visible'); + + // Test for accessibility issues + testA11y('ds-submission-import-external'); }); }); diff --git a/cypress/e2e/search-page.cy.ts b/cypress/e2e/search-page.cy.ts index 755f8eaac6c..aca3d23d04f 100644 --- a/cypress/e2e/search-page.cy.ts +++ b/cypress/e2e/search-page.cy.ts @@ -46,9 +46,8 @@ describe('Search Page', () => { testA11y('ds-search-page', { rules: { - // Search filters fail these two "moderate" impact rules - 'heading-order': { enabled: false }, - 'landmark-unique': { enabled: false } + // Card titles fail this test currently + 'heading-order': { enabled: false } } } as Options ); From aeea1cd592c9dfe7bb1f98f096c6eb0f3d6d3cf2 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 1 Sep 2023 09:47:32 -0500 Subject: [PATCH 271/282] Fix ARIA labels on submission form relationship button and dynamic dropdowns --- .../ds-dynamic-form-control-container.component.html | 2 ++ .../dynamic-scrollable-dropdown.component.html | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html index 9e1f1d48aa1..606db29db37 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html @@ -45,7 +45,9 @@ <button class="btn btn-secondary" type="button" ngbTooltip="{{'form.lookup-help' | translate}}" + [attr.aria-label]="'form.lookup-help' | translate" placement="top" + data-test="lookup-button" (click)="openLookup(); $event.stopPropagation();"><i class="fa fa-search"></i> </button> </div> diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index 1ac38e9943c..3be79b20f32 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -2,14 +2,15 @@ <div class="position-relative right-addon" role="combobox" [attr.aria-label]="model.label" - [attr.aria-owns]="'combobox_' + id + '_listbox'"> + [attr.aria-owns]="'combobox_' + id + '_listbox'" + [attr.aria-expanded]="sdRef.isOpen()" + [attr.aria-activedescendant]="(currentValue | async) ? 'combobox_' + id + '_selected' : null"> <i *ngIf="!model.readOnly" ngbDropdownToggle class="position-absolute scrollable-dropdown-toggle" aria-hidden="true"></i> <i *ngIf="model.readOnly" class="dropdown-toggle position-absolute toggle-icon" aria-hidden="true"></i> <input class="form-control" [attr.aria-controls]="'combobox_' + id + '_listbox'" - [attr.aria-activedescendant]="'combobox_' + id + '_selected'" [attr.aria-label]="model.placeholder" [attr.autoComplete]="model.autoComplete" [class.is-invalid]="showErrorMessages" @@ -28,8 +29,6 @@ <div ngbDropdownMenu class="dropdown-menu scrollable-dropdown-menu w-100" - aria-haspopup="true" - aria-expanded="false" [attr.aria-label]="model.placeholder"> <div class="scrollable-menu" role="listbox" From 5dad8bec392cc581baa7116559fe780be51198cf Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 1 Sep 2023 09:48:17 -0500 Subject: [PATCH 272/282] Fix ARIA labels and tabindex on date picker in submission form. Tabindex is unnecessary & throws accessibility errors from AXE tools --- .../models/date-picker/date-picker.component.html | 6 +++--- .../shared/form/number-picker/number-picker.component.html | 5 +++-- .../form/number-picker/number-picker.component.spec.ts | 1 - 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html index 26803f3c67b..3bf02c4abd5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html @@ -4,7 +4,7 @@ {{model.placeholder}} <span *ngIf="model.required">*</span> </legend> <ds-number-picker - tabindex="1" + tabindex="0" [id]="model.id + '_year'" [disabled]="model.disabled" [min]="minYear" @@ -21,7 +21,7 @@ ></ds-number-picker> <ds-number-picker - tabindex="2" + tabindex="0" [id]="model.id + '_month'" [min]="minMonth" [max]="maxMonth" @@ -37,7 +37,7 @@ ></ds-number-picker> <ds-number-picker - tabindex="3" + tabindex="0" [id]="model.id + '_day'" [min]="minDay" [max]="maxDay" diff --git a/src/app/shared/form/number-picker/number-picker.component.html b/src/app/shared/form/number-picker/number-picker.component.html index 9b2ef989256..d4cf9e23f4b 100644 --- a/src/app/shared/form/number-picker/number-picker.component.html +++ b/src/app/shared/form/number-picker/number-picker.component.html @@ -6,7 +6,7 @@ [disabled]="disabled" (click)="toggleUp()"> <span class="chevron"></span> - <span class="sr-only">Increment</span> + <span class="sr-only">Increment {{placeholder}}</span> </button> <input id="{{id}}" @@ -24,6 +24,7 @@ [disabled]="disabled" [ngClass]="{'is-invalid': invalid}" title="{{placeholder}}" + [attr.aria-label]="placeholder" > <button class="btn btn-link-focus" @@ -32,6 +33,6 @@ [disabled]="disabled" (click)="toggleDown()"> <span class="chevron bottom"></span> - <span class="sr-only">Decrement</span> + <span class="sr-only">Decrement {{placeholder}}</span> </button> </div> diff --git a/src/app/shared/form/number-picker/number-picker.component.spec.ts b/src/app/shared/form/number-picker/number-picker.component.spec.ts index d4484dbfa33..bf33a6bdd0a 100644 --- a/src/app/shared/form/number-picker/number-picker.component.spec.ts +++ b/src/app/shared/form/number-picker/number-picker.component.spec.ts @@ -42,7 +42,6 @@ describe('NumberPickerComponent test suite', () => { beforeEach(() => { html = ` <ds-number-picker - tabindex="1" [disabled]="disabled" [min]="min" [max]="max" From a581219df59b494d12838c1bb82097e7e1e93660 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 1 Sep 2023 11:29:05 -0500 Subject: [PATCH 273/282] Refactor e2e test infrastruction to allow easier way to lookup REST API info and generate CSRF tokens --- cypress/plugins/index.ts | 24 +++++ cypress/support/commands.ts | 179 +++++++++++++++--------------------- cypress/support/e2e.ts | 51 +++++++--- 3 files changed, 140 insertions(+), 114 deletions(-) diff --git a/cypress/plugins/index.ts b/cypress/plugins/index.ts index ead38afb921..cc3dccba38e 100644 --- a/cypress/plugins/index.ts +++ b/cypress/plugins/index.ts @@ -1,5 +1,11 @@ const fs = require('fs'); +// These two global variables are used to store information about the REST API used +// by these e2e tests. They are filled out prior to running any tests in the before() +// method of e2e.ts. They can then be accessed by any tests via the getters below. +let REST_BASE_URL: string; +let REST_DOMAIN: string; + // Plugins enable you to tap into, modify, or extend the internal behavior of Cypress // For more info, visit https://on.cypress.io/plugins-api module.exports = (on, config) => { @@ -30,6 +36,24 @@ module.exports = (on, config) => { } return null; + }, + // Save value of REST Base URL, looked up before all tests. + // This allows other tests to use it easily via getRestBaseURL() below. + saveRestBaseURL(url: string) { + return (REST_BASE_URL = url); + }, + // Retrieve currently saved value of REST Base URL + getRestBaseURL() { + return REST_BASE_URL ; + }, + // Save value of REST Domain, looked up before all tests. + // This allows other tests to use it easily via getRestBaseDomain() below. + saveRestBaseDomain(domain: string) { + return (REST_DOMAIN = domain); + }, + // Retrieve currently saved value of REST Domain + getRestBaseDomain() { + return REST_DOMAIN ; } }); }; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 92f0b1aeeb6..7da454e2d0c 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -5,11 +5,7 @@ import { AuthTokenInfo, TOKENITEM } from 'src/app/core/auth/models/auth-token-info.model'; import { DSPACE_XSRF_COOKIE, XSRF_REQUEST_HEADER } from 'src/app/core/xsrf/xsrf.constants'; - -// NOTE: FALLBACK_TEST_REST_BASE_URL is only used if Cypress cannot read the REST API BaseURL -// from the Angular UI's config.json. See 'login()'. -export const FALLBACK_TEST_REST_BASE_URL = 'http://localhost:8080/server'; -export const FALLBACK_TEST_REST_DOMAIN = 'localhost'; +import { v4 as uuidv4 } from 'uuid'; // Declare Cypress namespace to help with Intellisense & code completion in IDEs // ALL custom commands MUST be listed here for code completion to work @@ -41,6 +37,13 @@ declare global { * @param dsoType type of DSpace Object (e.g. "item", "collection", "community") */ generateViewEvent(uuid: string, dsoType: string): typeof generateViewEvent; + + /** + * Create a new CSRF token and add to required Cookie. CSRF Token is returned + * in chainable in order to allow it to be sent also in required CSRF header. + * @returns Chainable reference to allow CSRF token to also be sent in header. + */ + createCSRFCookie(): Chainable<any>; } } } @@ -54,59 +57,32 @@ declare global { * @param password password to login as */ function login(email: string, password: string): void { - // Cypress doesn't have access to the running application in Node.js. - // So, it's not possible to inject or load the AppConfig or environment of the Angular UI. - // Instead, we'll read our running application's config.json, which contains the configs & - // is regenerated at runtime each time the Angular UI application starts up. - cy.task('readUIConfig').then((str: string) => { - // Parse config into a JSON object - const config = JSON.parse(str); - - // Find the URL of our REST API. Have a fallback ready, just in case 'rest.baseUrl' cannot be found. - let baseRestUrl = FALLBACK_TEST_REST_BASE_URL; - if (!config.rest.baseUrl) { - console.warn("Could not load 'rest.baseUrl' from config.json. Falling back to " + FALLBACK_TEST_REST_BASE_URL); - } else { - //console.log("Found 'rest.baseUrl' in config.json. Using this REST API for login: ".concat(config.rest.baseUrl)); - baseRestUrl = config.rest.baseUrl; - } - - // Now find domain of our REST API, again with a fallback. - let baseDomain = FALLBACK_TEST_REST_DOMAIN; - if (!config.rest.host) { - console.warn("Could not load 'rest.host' from config.json. Falling back to " + FALLBACK_TEST_REST_DOMAIN); - } else { - baseDomain = config.rest.host; - } - - // Create a fake CSRF Token. Set it in the required server-side cookie - const csrfToken = 'fakeLoginCSRFToken'; - cy.setCookie(DSPACE_XSRF_COOKIE, csrfToken, { 'domain': baseDomain }); - - // Now, send login POST request including that CSRF token - cy.request({ - method: 'POST', - url: baseRestUrl + '/api/authn/login', - headers: { [XSRF_REQUEST_HEADER]: csrfToken}, - form: true, // indicates the body should be form urlencoded - body: { user: email, password: password } - }).then((resp) => { - // We expect a successful login - expect(resp.status).to.eq(200); - // We expect to have a valid authorization header returned (with our auth token) - expect(resp.headers).to.have.property('authorization'); - - // Initialize our AuthTokenInfo object from the authorization header. - const authheader = resp.headers.authorization as string; - const authinfo: AuthTokenInfo = new AuthTokenInfo(authheader); - - // Save our AuthTokenInfo object to our dsAuthInfo UI cookie - // This ensures the UI will recognize we are logged in on next "visit()" - cy.setCookie(TOKENITEM, JSON.stringify(authinfo)); + // Create a fake CSRF cookie/token to use in POST + cy.createCSRFCookie().then((csrfToken: string) => { + // get our REST API's base URL, also needed for POST + cy.task('getRestBaseURL').then((baseRestUrl: string) => { + // Now, send login POST request including that CSRF token + cy.request({ + method: 'POST', + url: baseRestUrl + '/api/authn/login', + headers: { [XSRF_REQUEST_HEADER]: csrfToken}, + form: true, // indicates the body should be form urlencoded + body: { user: email, password: password } + }).then((resp) => { + // We expect a successful login + expect(resp.status).to.eq(200); + // We expect to have a valid authorization header returned (with our auth token) + expect(resp.headers).to.have.property('authorization'); + + // Initialize our AuthTokenInfo object from the authorization header. + const authheader = resp.headers.authorization as string; + const authinfo: AuthTokenInfo = new AuthTokenInfo(authheader); + + // Save our AuthTokenInfo object to our dsAuthInfo UI cookie + // This ensures the UI will recognize we are logged in on next "visit()" + cy.setCookie(TOKENITEM, JSON.stringify(authinfo)); + }); }); - - // Remove cookie with fake CSRF token, as it's no longer needed - cy.clearCookie(DSPACE_XSRF_COOKIE); }); } // Add as a Cypress command (i.e. assign to 'cy.login') @@ -141,56 +117,53 @@ Cypress.Commands.add('loginViaForm', loginViaForm); * @param dsoType type of DSpace Object (e.g. "item", "collection", "community") */ function generateViewEvent(uuid: string, dsoType: string): void { - // Cypress doesn't have access to the running application in Node.js. - // So, it's not possible to inject or load the AppConfig or environment of the Angular UI. - // Instead, we'll read our running application's config.json, which contains the configs & - // is regenerated at runtime each time the Angular UI application starts up. - cy.task('readUIConfig').then((str: string) => { - // Parse config into a JSON object - const config = JSON.parse(str); + // Create a fake CSRF cookie/token to use in POST + cy.createCSRFCookie().then((csrfToken: string) => { + // get our REST API's base URL, also needed for POST + cy.task('getRestBaseURL').then((baseRestUrl: string) => { + // Now, send 'statistics/viewevents' POST request including that fake CSRF token in required header + cy.request({ + method: 'POST', + url: baseRestUrl + '/api/statistics/viewevents', + headers: { + [XSRF_REQUEST_HEADER] : csrfToken, + // use a known public IP address to avoid being seen as a "bot" + 'X-Forwarded-For': '1.1.1.1', + // Use a user-agent of a Firefox browser on Windows. This again avoids being seen as a "bot" + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0', + }, + //form: true, // indicates the body should be form urlencoded + body: { targetId: uuid, targetType: dsoType }, + }).then((resp) => { + // We expect a 201 (which means statistics event was created) + expect(resp.status).to.eq(201); + }); + }); + }); +} +// Add as a Cypress command (i.e. assign to 'cy.generateViewEvent') +Cypress.Commands.add('generateViewEvent', generateViewEvent); - // Find the URL of our REST API. Have a fallback ready, just in case 'rest.baseUrl' cannot be found. - let baseRestUrl = FALLBACK_TEST_REST_BASE_URL; - if (!config.rest.baseUrl) { - console.warn("Could not load 'rest.baseUrl' from config.json. Falling back to " + FALLBACK_TEST_REST_BASE_URL); - } else { - baseRestUrl = config.rest.baseUrl; - } - // Now find domain of our REST API, again with a fallback. - let baseDomain = FALLBACK_TEST_REST_DOMAIN; - if (!config.rest.host) { - console.warn("Could not load 'rest.host' from config.json. Falling back to " + FALLBACK_TEST_REST_DOMAIN); - } else { - baseDomain = config.rest.host; - } +/** + * Can be used by tests to generate a random XSRF/CSRF token and save it to + * the required XSRF/CSRF cookie for usage when sending POST requests or similar. + * The generated CSRF token is returned in a Chainable to allow it to be also sent + * in the CSRF HTTP Header. + * @returns a Cypress Chainable which can be used to get the generated CSRF Token + */ +function createCSRFCookie(): Cypress.Chainable { + // Generate a new token which is a random UUID + const csrfToken: string = uuidv4(); + // Save it to our required cookie + cy.task('getRestBaseDomain').then((baseDomain: string) => { // Create a fake CSRF Token. Set it in the required server-side cookie - const csrfToken = 'fakeGenerateViewEventCSRFToken'; cy.setCookie(DSPACE_XSRF_COOKIE, csrfToken, { 'domain': baseDomain }); - - // Now, send 'statistics/viewevents' POST request including that fake CSRF token in required header - cy.request({ - method: 'POST', - url: baseRestUrl + '/api/statistics/viewevents', - headers: { - [XSRF_REQUEST_HEADER] : csrfToken, - // use a known public IP address to avoid being seen as a "bot" - 'X-Forwarded-For': '1.1.1.1', - // Use a user-agent of a Firefox browser on Windows. This again avoids being seen as a "bot" - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0', - }, - //form: true, // indicates the body should be form urlencoded - body: { targetId: uuid, targetType: dsoType }, - }).then((resp) => { - // We expect a 201 (which means statistics event was created) - expect(resp.status).to.eq(201); - }); - - // Remove cookie with fake CSRF token, as it's no longer needed - cy.clearCookie(DSPACE_XSRF_COOKIE); }); -} -// Add as a Cypress command (i.e. assign to 'cy.generateViewEvent') -Cypress.Commands.add('generateViewEvent', generateViewEvent); + // return the generated token wrapped in a chainable + return cy.wrap(csrfToken); +} +// Add as a Cypress command (i.e. assign to 'cy.createCSRFCookie') +Cypress.Commands.add('createCSRFCookie', createCSRFCookie); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index dd7ee1824c4..5e4fddb8059 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -19,23 +19,49 @@ import './commands'; // Import Cypress Axe tools for all tests // https://github.com/component-driven/cypress-axe import 'cypress-axe'; +import { DSPACE_XSRF_COOKIE } from 'src/app/core/xsrf/xsrf.constants'; + + +// Runs once before all tests +before(() => { + // Cypress doesn't have access to the running application in Node.js. + // So, it's not possible to inject or load the AppConfig or environment of the Angular UI. + // Instead, we'll read our running application's config.json, which contains the configs & + // is regenerated at runtime each time the Angular UI application starts up. + cy.task('readUIConfig').then((str: string) => { + // Parse config into a JSON object + const config = JSON.parse(str); + + // Find URL of our REST API & save to global variable via task + let baseRestUrl = FALLBACK_TEST_REST_BASE_URL; + if (!config.rest.baseUrl) { + console.warn("Could not load 'rest.baseUrl' from config.json. Falling back to " + FALLBACK_TEST_REST_BASE_URL); + } else { + baseRestUrl = config.rest.baseUrl; + } + cy.task('saveRestBaseURL', baseRestUrl); + + // Find domain of our REST API & save to global variable via task. + let baseDomain = FALLBACK_TEST_REST_DOMAIN; + if (!config.rest.host) { + console.warn("Could not load 'rest.host' from config.json. Falling back to " + FALLBACK_TEST_REST_DOMAIN); + } else { + baseDomain = config.rest.host; + } + cy.task('saveRestBaseDomain', baseDomain); + + }); +}); // Runs once before the first test in each "block" beforeEach(() => { // Pre-agree to all Klaro cookies by setting the klaro-anonymous cookie // This just ensures it doesn't get in the way of matching other objects in the page. cy.setCookie('klaro-anonymous', '{%22authentication%22:true%2C%22preferences%22:true%2C%22acknowledgement%22:true%2C%22google-analytics%22:true%2C%22google-recaptcha%22:true}'); -}); - -// For better stability between tests, we visit "about:blank" (i.e. blank page) after each test. -// This ensures any remaining/outstanding XHR requests are killed, so they don't affect the next test. -// Borrowed from: https://glebbahmutov.com/blog/visit-blank-page-between-tests/ -/*afterEach(() => { - cy.window().then((win) => { - win.location.href = 'about:blank'; - }); -});*/ + // Remove any CSRF cookies saved from prior tests + cy.clearCookie(DSPACE_XSRF_COOKIE); +}); // Global constants used in tests // May be overridden in our cypress.json config file using specified environment variables. @@ -57,7 +83,10 @@ export const TEST_SUBMIT_COLLECTION_NAME = Cypress.env('DSPACE_TEST_SUBMIT_COLLE export const TEST_SUBMIT_COLLECTION_UUID = Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_UUID') || '9d8334e9-25d3-4a67-9cea-3dffdef80144'; export const TEST_SUBMIT_USER = Cypress.env('DSPACE_TEST_SUBMIT_USER') || 'dspacedemo+submit@gmail.com'; export const TEST_SUBMIT_USER_PASSWORD = Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD') || 'dspace'; - +// NOTE: FALLBACK_TEST_REST_BASE_URL is only used if Cypress cannot read the REST API BaseURL +// from the Angular UI's config.json. See 'before()' above. +const FALLBACK_TEST_REST_BASE_URL = 'http://localhost:8080/server'; +const FALLBACK_TEST_REST_DOMAIN = 'localhost'; // USEFUL REGEX for testing From 8d61fa6ac3cb65e72bfd2d9afb3a80908e4b8774 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Tue, 5 Sep 2023 14:47:59 -0500 Subject: [PATCH 274/282] Improve accessibility testing on Submission page --- cypress/e2e/submission.cy.ts | 87 +++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/submission.cy.ts b/cypress/e2e/submission.cy.ts index ed10b2d13aa..43a063035d0 100644 --- a/cypress/e2e/submission.cy.ts +++ b/cypress/e2e/submission.cy.ts @@ -1,8 +1,10 @@ -import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME, TEST_SUBMIT_COLLECTION_UUID } from 'cypress/support/e2e'; +import { testA11y } from 'cypress/support/utils'; +import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME, TEST_SUBMIT_COLLECTION_UUID, TEST_ADMIN_USER, TEST_ADMIN_PASSWORD } from 'cypress/support/e2e'; +import { Options } from 'cypress-axe'; describe('New Submission page', () => { - // NOTE: We already test that new submissions can be started from MyDSpace in my-dspace.spec.ts + // NOTE: We already test that new Item submissions can be started from MyDSpace in my-dspace.spec.ts it('should create a new submission when using /submit path & pass accessibility', () => { // Test that calling /submit with collection & entityType will create a new submission cy.visit('/submit?collection='.concat(TEST_SUBMIT_COLLECTION_UUID).concat('&entityType=none')); @@ -25,6 +27,22 @@ describe('New Submission page', () => { cy.get('div#section_upload').should('be.visible'); cy.get('div#section_license').should('be.visible'); + // Test entire page for accessibility + testA11y('ds-submission-edit', + { + rules: { + // Author & Subject fields have invalid "aria-multiline" attrs, see #1272 + 'aria-allowed-attr': { enabled: false }, + // All panels are accordians & fail "aria-required-children" and "nested-interactive". Seem to require updating ng-bootstrap and #2216 + 'aria-required-children': { enabled: false }, + 'nested-interactive': { enabled: false }, + // All select boxes fail to have a name / aria-label. This is a bug in ng-dynamic-forms and may require #2216 + 'select-name': { enabled: false }, + } + + } as Options + ); + // Discard button should work // Clicking it will display a confirmation, which we will confirm with another click cy.get('button#discard').click(); @@ -131,4 +149,69 @@ describe('New Submission page', () => { cy.get('ds-notification div.alert-success').should('be.visible'); }); + it('is possible to submit a new "Person" and that form passes accessibility', () => { + // To submit a different entity type, we'll start from MyDSpace + cy.visit('/mydspace'); + + // This page is restricted, so we will be shown the login form. Fill it out & submit. + // NOTE: At this time, we MUST login as admin to submit Person objects + cy.loginViaForm(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + + // Open the New Submission dropdown + cy.get('button[data-test="submission-dropdown"]').click(); + // Click on the "Person" type in that dropdown + cy.get('#entityControlsDropdownMenu button[title="Person"]').click(); + + // This should display the <ds-create-item-parent-selector> (popup window) + cy.get('ds-create-item-parent-selector').should('be.visible'); + + // Click on the first Collection button to seelect a collection (actual collection doesn't matter) + cy.get('ds-authorized-collection-selector button:first-child').click(); + + // New URL should include /workspaceitems, as we've started a new submission + cy.url().should('include', '/workspaceitems'); + + // The Submission edit form tag should be visible + cy.get('ds-submission-edit').should('be.visible'); + + // 3 sections should be visible by default + cy.get('div#section_personStep').should('be.visible'); + cy.get('div#section_upload').should('be.visible'); + cy.get('div#section_license').should('be.visible'); + + // Test entire page for accessibility + testA11y('ds-submission-edit', + { + rules: { + // All panels are accordians & fail "aria-required-children" and "nested-interactive". Seem to require updating ng-bootstrap and #2216 + 'aria-required-children': { enabled: false }, + 'nested-interactive': { enabled: false }, + } + + } as Options + ); + + // Click the lookup button next to "Publication" field + cy.get('button[data-test="lookup-button"]').click(); + + // A popup modal window should be visible + cy.get('ds-dynamic-lookup-relation-modal').should('be.visible'); + + // Popup modal should also pass accessibility tests + //testA11y('ds-dynamic-lookup-relation-modal'); + testA11y({ + include: ['ds-dynamic-lookup-relation-modal'], + exclude: [ + ['ul.nav-tabs'] // Tabs at top of model have several issues which seem to be caused by ng-bootstrap + ], + }); + + // Close popup window + cy.get('ds-dynamic-lookup-relation-modal button.close').click(); + + // Back on the form, click the discard button to remove new submission + // Clicking it will display a confirmation, which we will confirm with another click + cy.get('button#discard').click(); + cy.get('button#discard_submit').click(); + }); }); From e47593b303f269a18b2a40b7920daa85a6c23123 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 8 Sep 2023 16:14:24 -0500 Subject: [PATCH 275/282] Fix circular dependency issue by using Cypres env variables directly instead of global constants --- cypress.config.ts | 5 +++-- cypress/e2e/breadcrumbs.cy.ts | 3 +-- cypress/e2e/collection-page.cy.ts | 3 +-- cypress/e2e/collection-statistics.cy.ts | 8 ++++---- cypress/e2e/community-page.cy.ts | 3 +-- cypress/e2e/community-statistics.cy.ts | 8 ++++---- cypress/e2e/homepage-statistics.cy.ts | 6 +++--- cypress/e2e/item-page.cy.ts | 5 ++--- cypress/e2e/item-statistics.cy.ts | 8 ++++---- cypress/e2e/login-modal.cy.ts | 11 +++++------ cypress/e2e/my-dspace.cy.ts | 15 +++++++-------- cypress/e2e/search-navbar.cy.ts | 4 +--- cypress/e2e/search-page.cy.ts | 10 ++++++---- cypress/e2e/submission.cy.ts | 18 +++++++++--------- cypress/support/e2e.ts | 20 -------------------- 15 files changed, 51 insertions(+), 76 deletions(-) diff --git a/cypress.config.ts b/cypress.config.ts index 91eeb9838b3..b1da2b47935 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -9,8 +9,9 @@ export default defineConfig({ openMode: 0, }, env: { - // Global constants used in DSpace e2e tests (see also ./cypress/support/e2e.ts) - // May be overridden in our cypress.json config file using specified environment variables. + // Global DSpace environment variables used in all our Cypress e2e tests + // May be modified in this config, or overridden in a variety of ways. + // See Cypress environment variable docs: https://docs.cypress.io/guides/guides/environment-variables // Default values listed here are all valid for the Demo Entities Data set available at // https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data // (This is the data set used in our CI environment) diff --git a/cypress/e2e/breadcrumbs.cy.ts b/cypress/e2e/breadcrumbs.cy.ts index ea6acdafcde..0cddbc723c6 100644 --- a/cypress/e2e/breadcrumbs.cy.ts +++ b/cypress/e2e/breadcrumbs.cy.ts @@ -1,10 +1,9 @@ -import { TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Breadcrumbs', () => { it('should pass accessibility tests', () => { // Visit an Item, as those have more breadcrumbs - cy.visit('/entities/publication/'.concat(TEST_ENTITY_PUBLICATION)); + cy.visit('/entities/publication/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION'))); // Wait for breadcrumbs to be visible cy.get('ds-breadcrumbs').should('be.visible'); diff --git a/cypress/e2e/collection-page.cy.ts b/cypress/e2e/collection-page.cy.ts index a034b4361d6..55c10cc6e22 100644 --- a/cypress/e2e/collection-page.cy.ts +++ b/cypress/e2e/collection-page.cy.ts @@ -1,10 +1,9 @@ -import { TEST_COLLECTION } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Collection Page', () => { it('should pass accessibility tests', () => { - cy.visit('/collections/'.concat(TEST_COLLECTION)); + cy.visit('/collections/'.concat(Cypress.env('DSPACE_TEST_COLLECTION'))); // <ds-collection-page> tag must be loaded cy.get('ds-collection-page').should('be.visible'); diff --git a/cypress/e2e/collection-statistics.cy.ts b/cypress/e2e/collection-statistics.cy.ts index 6df4e9a4542..43bf67ce51f 100644 --- a/cypress/e2e/collection-statistics.cy.ts +++ b/cypress/e2e/collection-statistics.cy.ts @@ -1,11 +1,11 @@ -import { REGEX_MATCH_NON_EMPTY_TEXT, TEST_COLLECTION } from 'cypress/support/e2e'; +import { REGEX_MATCH_NON_EMPTY_TEXT } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Collection Statistics Page', () => { - const COLLECTIONSTATISTICSPAGE = '/statistics/collections/'.concat(TEST_COLLECTION); + const COLLECTIONSTATISTICSPAGE = '/statistics/collections/'.concat(Cypress.env('DSPACE_TEST_COLLECTION')); it('should load if you click on "Statistics" from a Collection page', () => { - cy.visit('/collections/'.concat(TEST_COLLECTION)); + cy.visit('/collections/'.concat(Cypress.env('DSPACE_TEST_COLLECTION'))); cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); cy.location('pathname').should('eq', COLLECTIONSTATISTICSPAGE); }); @@ -18,7 +18,7 @@ describe('Collection Statistics Page', () => { it('should contain a "Total visits per month" section', () => { cy.visit(COLLECTIONSTATISTICSPAGE); // Check just for existence because this table is empty in CI environment as it's historical data - cy.get('.'.concat(TEST_COLLECTION).concat('_TotalVisitsPerMonth')).should('exist'); + cy.get('.'.concat(Cypress.env('DSPACE_TEST_COLLECTION')).concat('_TotalVisitsPerMonth')).should('exist'); }); it('should pass accessibility tests', () => { diff --git a/cypress/e2e/community-page.cy.ts b/cypress/e2e/community-page.cy.ts index 6c628e21ce1..4a2e2f9baa5 100644 --- a/cypress/e2e/community-page.cy.ts +++ b/cypress/e2e/community-page.cy.ts @@ -1,10 +1,9 @@ -import { TEST_COMMUNITY } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Community Page', () => { it('should pass accessibility tests', () => { - cy.visit('/communities/'.concat(TEST_COMMUNITY)); + cy.visit('/communities/'.concat(Cypress.env('DSPACE_TEST_COMMUNITY'))); // <ds-community-page> tag must be loaded cy.get('ds-community-page').should('be.visible'); diff --git a/cypress/e2e/community-statistics.cy.ts b/cypress/e2e/community-statistics.cy.ts index 710450e7972..ca306eff5c2 100644 --- a/cypress/e2e/community-statistics.cy.ts +++ b/cypress/e2e/community-statistics.cy.ts @@ -1,11 +1,11 @@ -import { REGEX_MATCH_NON_EMPTY_TEXT, TEST_COMMUNITY } from 'cypress/support/e2e'; +import { REGEX_MATCH_NON_EMPTY_TEXT } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Community Statistics Page', () => { - const COMMUNITYSTATISTICSPAGE = '/statistics/communities/'.concat(TEST_COMMUNITY); + const COMMUNITYSTATISTICSPAGE = '/statistics/communities/'.concat(Cypress.env('DSPACE_TEST_COMMUNITY')); it('should load if you click on "Statistics" from a Community page', () => { - cy.visit('/communities/'.concat(TEST_COMMUNITY)); + cy.visit('/communities/'.concat(Cypress.env('DSPACE_TEST_COMMUNITY'))); cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); cy.location('pathname').should('eq', COMMUNITYSTATISTICSPAGE); }); @@ -18,7 +18,7 @@ describe('Community Statistics Page', () => { it('should contain a "Total visits per month" section', () => { cy.visit(COMMUNITYSTATISTICSPAGE); // Check just for existence because this table is empty in CI environment as it's historical data - cy.get('.'.concat(TEST_COMMUNITY).concat('_TotalVisitsPerMonth')).should('exist'); + cy.get('.'.concat(Cypress.env('DSPACE_TEST_COMMUNITY')).concat('_TotalVisitsPerMonth')).should('exist'); }); it('should pass accessibility tests', () => { diff --git a/cypress/e2e/homepage-statistics.cy.ts b/cypress/e2e/homepage-statistics.cy.ts index 2a1ab9785ab..ff7dbeb852d 100644 --- a/cypress/e2e/homepage-statistics.cy.ts +++ b/cypress/e2e/homepage-statistics.cy.ts @@ -1,4 +1,4 @@ -import { REGEX_MATCH_NON_EMPTY_TEXT, TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; +import { REGEX_MATCH_NON_EMPTY_TEXT } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; import '../support/commands'; @@ -11,8 +11,8 @@ describe('Site Statistics Page', () => { it('should pass accessibility tests', () => { // generate 2 view events on an Item's page - cy.generateViewEvent(TEST_ENTITY_PUBLICATION, 'item'); - cy.generateViewEvent(TEST_ENTITY_PUBLICATION, 'item'); + cy.generateViewEvent(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION'), 'item'); + cy.generateViewEvent(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION'), 'item'); cy.visit('/statistics'); diff --git a/cypress/e2e/item-page.cy.ts b/cypress/e2e/item-page.cy.ts index 9dba6eb8cea..a6a208e9f45 100644 --- a/cypress/e2e/item-page.cy.ts +++ b/cypress/e2e/item-page.cy.ts @@ -1,9 +1,8 @@ -import { TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Item Page', () => { - const ITEMPAGE = '/items/'.concat(TEST_ENTITY_PUBLICATION); - const ENTITYPAGE = '/entities/publication/'.concat(TEST_ENTITY_PUBLICATION); + const ITEMPAGE = '/items/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')); + const ENTITYPAGE = '/entities/publication/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')); // Test that entities will redirect to /entities/[type]/[uuid] when accessed via /items/[uuid] it('should redirect to the entity page when navigating to an item page', () => { diff --git a/cypress/e2e/item-statistics.cy.ts b/cypress/e2e/item-statistics.cy.ts index 9b90cb24afc..b856744cba7 100644 --- a/cypress/e2e/item-statistics.cy.ts +++ b/cypress/e2e/item-statistics.cy.ts @@ -1,11 +1,11 @@ -import { REGEX_MATCH_NON_EMPTY_TEXT, TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; +import { REGEX_MATCH_NON_EMPTY_TEXT } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Item Statistics Page', () => { - const ITEMSTATISTICSPAGE = '/statistics/items/'.concat(TEST_ENTITY_PUBLICATION); + const ITEMSTATISTICSPAGE = '/statistics/items/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')); it('should load if you click on "Statistics" from an Item/Entity page', () => { - cy.visit('/entities/publication/'.concat(TEST_ENTITY_PUBLICATION)); + cy.visit('/entities/publication/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION'))); cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); cy.location('pathname').should('eq', ITEMSTATISTICSPAGE); }); @@ -24,7 +24,7 @@ describe('Item Statistics Page', () => { it('should contain a "Total visits per month" section', () => { cy.visit(ITEMSTATISTICSPAGE); // Check just for existence because this table is empty in CI environment as it's historical data - cy.get('.'.concat(TEST_ENTITY_PUBLICATION).concat('_TotalVisitsPerMonth')).should('exist'); + cy.get('.'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')).concat('_TotalVisitsPerMonth')).should('exist'); }); it('should pass accessibility tests', () => { diff --git a/cypress/e2e/login-modal.cy.ts b/cypress/e2e/login-modal.cy.ts index d4559dc6bf9..c56b98fd269 100644 --- a/cypress/e2e/login-modal.cy.ts +++ b/cypress/e2e/login-modal.cy.ts @@ -1,4 +1,3 @@ -import { TEST_ADMIN_PASSWORD, TEST_ADMIN_USER, TEST_ENTITY_PUBLICATION } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; const page = { @@ -37,7 +36,7 @@ const page = { describe('Login Modal', () => { it('should login when clicking button & stay on same page', () => { - const ENTITYPAGE = '/entities/publication/'.concat(TEST_ENTITY_PUBLICATION); + const ENTITYPAGE = '/entities/publication/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')); cy.visit(ENTITYPAGE); // Login menu should exist @@ -47,7 +46,7 @@ describe('Login Modal', () => { page.openLoginMenu(); cy.get('.form-login').should('be.visible'); - page.submitLoginAndPasswordByPressingButton(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + page.submitLoginAndPasswordByPressingButton(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); cy.get('ds-log-in').should('not.exist'); // Verify we are still on the same page @@ -67,7 +66,7 @@ describe('Login Modal', () => { cy.get('.form-login').should('be.visible'); // Login, and the <ds-log-in> tag should no longer exist - page.submitLoginAndPasswordByPressingEnter(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + page.submitLoginAndPasswordByPressingEnter(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); cy.get('.form-login').should('not.exist'); // Verify we are still on homepage @@ -81,7 +80,7 @@ describe('Login Modal', () => { it('should support logout', () => { // First authenticate & access homepage - cy.login(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + cy.login(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); cy.visit('/'); // Verify ds-log-in tag doesn't exist, but ds-log-out tag does exist @@ -140,7 +139,7 @@ describe('Login Modal', () => { testA11y('ds-log-in'); // Now login - page.submitLoginAndPasswordByPressingButton(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + page.submitLoginAndPasswordByPressingButton(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); cy.get('ds-log-in').should('not.exist'); // Open user menu, verify user menu accesibility diff --git a/cypress/e2e/my-dspace.cy.ts b/cypress/e2e/my-dspace.cy.ts index 4b27fe13de6..c48656ffcc0 100644 --- a/cypress/e2e/my-dspace.cy.ts +++ b/cypress/e2e/my-dspace.cy.ts @@ -1,4 +1,3 @@ -import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('My DSpace page', () => { @@ -6,7 +5,7 @@ describe('My DSpace page', () => { cy.visit('/mydspace'); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); cy.get('ds-my-dspace-page').should('be.visible'); @@ -25,7 +24,7 @@ describe('My DSpace page', () => { cy.visit('/mydspace'); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); cy.get('ds-my-dspace-page').should('be.visible'); @@ -43,7 +42,7 @@ describe('My DSpace page', () => { cy.visit('/mydspace'); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); // Open the New Submission dropdown cy.get('button[data-test="submission-dropdown"]').click(); @@ -54,10 +53,10 @@ describe('My DSpace page', () => { cy.get('ds-create-item-parent-selector').should('be.visible'); // Type in a known Collection name in the search box - cy.get('ds-authorized-collection-selector input[type="search"]').type(TEST_SUBMIT_COLLECTION_NAME); + cy.get('ds-authorized-collection-selector input[type="search"]').type(Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_NAME')); // Click on the button matching that known Collection name - cy.get('ds-authorized-collection-selector button[title="'.concat(TEST_SUBMIT_COLLECTION_NAME).concat('"]')).click(); + cy.get('ds-authorized-collection-selector button[title="'.concat(Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_NAME')).concat('"]')).click(); // New URL should include /workspaceitems, as we've started a new submission cy.url().should('include', '/workspaceitems'); @@ -66,7 +65,7 @@ describe('My DSpace page', () => { cy.get('ds-submission-edit').should('be.visible'); // A Collection menu button should exist & its value should be the selected collection - cy.get('#collectionControlsMenuButton span').should('have.text', TEST_SUBMIT_COLLECTION_NAME); + cy.get('#collectionControlsMenuButton span').should('have.text', Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_NAME')); // Now that we've created a submission, we'll test that we can go back and Edit it. // Get our Submission URL, to parse out the ID of this new submission @@ -115,7 +114,7 @@ describe('My DSpace page', () => { cy.visit('/mydspace'); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); // Open the New Import dropdown cy.get('button[data-test="import-dropdown"]').click(); diff --git a/cypress/e2e/search-navbar.cy.ts b/cypress/e2e/search-navbar.cy.ts index 648db17fe65..9dd93c7a2dd 100644 --- a/cypress/e2e/search-navbar.cy.ts +++ b/cypress/e2e/search-navbar.cy.ts @@ -1,5 +1,3 @@ -import { TEST_SEARCH_TERM } from 'cypress/support/e2e'; - const page = { fillOutQueryInNavBar(query) { // Click the magnifying glass @@ -17,7 +15,7 @@ const page = { describe('Search from Navigation Bar', () => { // NOTE: these tests currently assume this query will return results! - const query = TEST_SEARCH_TERM; + const query = Cypress.env('DSPACE_TEST_SEARCH_TERM'); it('should go to search page with correct query if submitted (from home)', () => { cy.visit('/'); diff --git a/cypress/e2e/search-page.cy.ts b/cypress/e2e/search-page.cy.ts index aca3d23d04f..429f4e6da46 100644 --- a/cypress/e2e/search-page.cy.ts +++ b/cypress/e2e/search-page.cy.ts @@ -1,8 +1,10 @@ import { Options } from 'cypress-axe'; -import { TEST_SEARCH_TERM } from 'cypress/support/e2e'; import { testA11y } from 'cypress/support/utils'; describe('Search Page', () => { + // NOTE: these tests currently assume this query will return results! + const query = Cypress.env('DSPACE_TEST_SEARCH_TERM'); + it('should redirect to the correct url when query was set and submit button was triggered', () => { const queryString = 'Another interesting query string'; cy.visit('/search'); @@ -13,8 +15,8 @@ describe('Search Page', () => { }); it('should load results and pass accessibility tests', () => { - cy.visit('/search?query='.concat(TEST_SEARCH_TERM)); - cy.get('[data-test="search-box"]').should('have.value', TEST_SEARCH_TERM); + cy.visit('/search?query='.concat(query)); + cy.get('[data-test="search-box"]').should('have.value', query); // <ds-search-page> tag must be loaded cy.get('ds-search-page').should('be.visible'); @@ -31,7 +33,7 @@ describe('Search Page', () => { }); it('should have a working grid view that passes accessibility tests', () => { - cy.visit('/search?query='.concat(TEST_SEARCH_TERM)); + cy.visit('/search?query='.concat(query)); // Click button in sidebar to display grid view cy.get('ds-search-sidebar [data-test="grid-view"]').click(); diff --git a/cypress/e2e/submission.cy.ts b/cypress/e2e/submission.cy.ts index 43a063035d0..2b482d85151 100644 --- a/cypress/e2e/submission.cy.ts +++ b/cypress/e2e/submission.cy.ts @@ -1,5 +1,5 @@ import { testA11y } from 'cypress/support/utils'; -import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME, TEST_SUBMIT_COLLECTION_UUID, TEST_ADMIN_USER, TEST_ADMIN_PASSWORD } from 'cypress/support/e2e'; +//import { TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD, TEST_SUBMIT_COLLECTION_NAME, TEST_SUBMIT_COLLECTION_UUID, TEST_ADMIN_USER, TEST_ADMIN_PASSWORD } from 'cypress/support/e2e'; import { Options } from 'cypress-axe'; describe('New Submission page', () => { @@ -7,10 +7,10 @@ describe('New Submission page', () => { // NOTE: We already test that new Item submissions can be started from MyDSpace in my-dspace.spec.ts it('should create a new submission when using /submit path & pass accessibility', () => { // Test that calling /submit with collection & entityType will create a new submission - cy.visit('/submit?collection='.concat(TEST_SUBMIT_COLLECTION_UUID).concat('&entityType=none')); + cy.visit('/submit?collection='.concat(Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_UUID')).concat('&entityType=none')); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); // Should redirect to /workspaceitems, as we've started a new submission cy.url().should('include', '/workspaceitems'); @@ -19,7 +19,7 @@ describe('New Submission page', () => { cy.get('ds-submission-edit').should('be.visible'); // A Collection menu button should exist & it's value should be the selected collection - cy.get('#collectionControlsMenuButton span').should('have.text', TEST_SUBMIT_COLLECTION_NAME); + cy.get('#collectionControlsMenuButton span').should('have.text', Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_NAME')); // 4 sections should be visible by default cy.get('div#section_traditionalpageone').should('be.visible'); @@ -51,10 +51,10 @@ describe('New Submission page', () => { it('should block submission & show errors if required fields are missing', () => { // Create a new submission - cy.visit('/submit?collection='.concat(TEST_SUBMIT_COLLECTION_UUID).concat('&entityType=none')); + cy.visit('/submit?collection='.concat(Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_UUID')).concat('&entityType=none')); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); // Attempt an immediate deposit without filling out any fields cy.get('button#deposit').click(); @@ -111,10 +111,10 @@ describe('New Submission page', () => { it('should allow for deposit if all required fields completed & file uploaded', () => { // Create a new submission - cy.visit('/submit?collection='.concat(TEST_SUBMIT_COLLECTION_UUID).concat('&entityType=none')); + cy.visit('/submit?collection='.concat(Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_UUID')).concat('&entityType=none')); // This page is restricted, so we will be shown the login form. Fill it out & submit. - cy.loginViaForm(TEST_SUBMIT_USER, TEST_SUBMIT_USER_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_SUBMIT_USER'), Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD')); // Fill out all required fields (Title, Date) cy.get('input#dc_title').type('DSpace logo uploaded via e2e tests'); @@ -155,7 +155,7 @@ describe('New Submission page', () => { // This page is restricted, so we will be shown the login form. Fill it out & submit. // NOTE: At this time, we MUST login as admin to submit Person objects - cy.loginViaForm(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); // Open the New Submission dropdown cy.get('button[data-test="submission-dropdown"]').click(); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index 5e4fddb8059..f6c68650528 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -63,26 +63,6 @@ beforeEach(() => { cy.clearCookie(DSPACE_XSRF_COOKIE); }); -// Global constants used in tests -// May be overridden in our cypress.json config file using specified environment variables. -// Default values listed here are all valid for the Demo Entities Data set available at -// https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data -// (This is the data set used in our CI environment) - -// Admin account used for administrative tests -export const TEST_ADMIN_USER = Cypress.env('DSPACE_TEST_ADMIN_USER') || 'dspacedemo+admin@gmail.com'; -export const TEST_ADMIN_PASSWORD = Cypress.env('DSPACE_TEST_ADMIN_PASSWORD') || 'dspace'; -// Community/collection/publication used for view/edit tests -export const TEST_COLLECTION = Cypress.env('DSPACE_TEST_COLLECTION') || '282164f5-d325-4740-8dd1-fa4d6d3e7200'; -export const TEST_COMMUNITY = Cypress.env('DSPACE_TEST_COMMUNITY') || '0958c910-2037-42a9-81c7-dca80e3892b4'; -export const TEST_ENTITY_PUBLICATION = Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION') || 'e98b0f27-5c19-49a0-960d-eb6ad5287067'; -// Search term (should return results) used in search tests -export const TEST_SEARCH_TERM = Cypress.env('DSPACE_TEST_SEARCH_TERM') || 'test'; -// Collection used for submission tests -export const TEST_SUBMIT_COLLECTION_NAME = Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_NAME') || 'Sample Collection'; -export const TEST_SUBMIT_COLLECTION_UUID = Cypress.env('DSPACE_TEST_SUBMIT_COLLECTION_UUID') || '9d8334e9-25d3-4a67-9cea-3dffdef80144'; -export const TEST_SUBMIT_USER = Cypress.env('DSPACE_TEST_SUBMIT_USER') || 'dspacedemo+submit@gmail.com'; -export const TEST_SUBMIT_USER_PASSWORD = Cypress.env('DSPACE_TEST_SUBMIT_USER_PASSWORD') || 'dspace'; // NOTE: FALLBACK_TEST_REST_BASE_URL is only used if Cypress cannot read the REST API BaseURL // from the Angular UI's config.json. See 'before()' above. const FALLBACK_TEST_REST_BASE_URL = 'http://localhost:8080/server'; From 6c76d8c1d77c5466042edc5301e81742546640b4 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 8 Dec 2023 14:54:15 -0600 Subject: [PATCH 276/282] Add Edit Community accessibility tests & minor cleanup --- cypress/e2e/community-edit.cy.ts | 98 +++++++++++++++++++ cypress/e2e/community-page.cy.ts | 2 +- cypress/e2e/submission.cy.ts | 12 ++- .../edit-comcol-page.component.html | 6 +- 4 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 cypress/e2e/community-edit.cy.ts diff --git a/cypress/e2e/community-edit.cy.ts b/cypress/e2e/community-edit.cy.ts new file mode 100644 index 00000000000..06d78701f07 --- /dev/null +++ b/cypress/e2e/community-edit.cy.ts @@ -0,0 +1,98 @@ +import { testA11y } from 'cypress/support/utils'; + +const COMMUNITY_EDIT_PAGE = '/communities/'.concat(Cypress.env('DSPACE_TEST_COMMUNITY')).concat('/edit'); + +beforeEach(() => { + // All tests start with visiting the Edit Community Page + cy.visit(COMMUNITY_EDIT_PAGE); + + // This page is restricted, so we will be shown the login form. Fill it out & submit. + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); +}); + +describe('Edit Community > Edit Metadata tab', () => { + it('should pass accessibility tests', () => { + // <ds-edit-community> tag must be loaded + cy.get('ds-edit-community').should('be.visible'); + + // Analyze <ds-edit-community> for accessibility issues + testA11y('ds-edit-community'); + }); +}); + +describe('Edit Community > Assign Roles tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="roles"]').click(); + + // <ds-community-roles> tag must be loaded + cy.get('ds-community-roles').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-community-roles'); + }); +}); + +describe('Edit Community > Curate tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="curate"]').click(); + + // <ds-community-curate> tag must be loaded + cy.get('ds-community-curate').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-community-curate'); + }); +}); + +describe('Edit Community > Access Control tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="access-control"]').click(); + + // <ds-community-access-control> tag must be loaded + cy.get('ds-community-access-control').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-community-access-control'); + }); +}); + +describe('Edit Community > Authorizations tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="authorizations"]').click(); + + // <ds-community-authorizations> tag must be loaded + cy.get('ds-community-authorizations').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-community-authorizations'); + }); + + it('should have an edit policy page which also passes accessibility tests', () => { + cy.visit(COMMUNITY_EDIT_PAGE.concat('/authorizations')); + + cy.get('button[title="Edit policy"]').click(); + + // <ds-resource-policy-edit> tag must be loaded + cy.get('ds-resource-policy-edit').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-resource-policy-edit'); + }); +}); + +describe('Edit Community > Delete page', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="delete-button"]').click(); + + // <ds-delete-community> tag must be loaded + cy.get('ds-delete-community').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-delete-community'); + }); +}); diff --git a/cypress/e2e/community-page.cy.ts b/cypress/e2e/community-page.cy.ts index 4a2e2f9baa5..386bb592a0a 100644 --- a/cypress/e2e/community-page.cy.ts +++ b/cypress/e2e/community-page.cy.ts @@ -9,6 +9,6 @@ describe('Community Page', () => { cy.get('ds-community-page').should('be.visible'); // Analyze <ds-community-page> for accessibility issues - testA11y('ds-community-page',); + testA11y('ds-community-page'); }); }); diff --git a/cypress/e2e/submission.cy.ts b/cypress/e2e/submission.cy.ts index 2b482d85151..97676ca25cd 100644 --- a/cypress/e2e/submission.cy.ts +++ b/cypress/e2e/submission.cy.ts @@ -31,12 +31,15 @@ describe('New Submission page', () => { testA11y('ds-submission-edit', { rules: { - // Author & Subject fields have invalid "aria-multiline" attrs, see #1272 + // Author & Subject fields have invalid "aria-multiline" attrs. + // See https://github.com/DSpace/dspace-angular/issues/1272 'aria-allowed-attr': { enabled: false }, - // All panels are accordians & fail "aria-required-children" and "nested-interactive". Seem to require updating ng-bootstrap and #2216 + // All panels are accordians & fail "aria-required-children" and "nested-interactive". + // Seem to require updating ng-bootstrap and https://github.com/DSpace/dspace-angular/issues/2216 'aria-required-children': { enabled: false }, 'nested-interactive': { enabled: false }, - // All select boxes fail to have a name / aria-label. This is a bug in ng-dynamic-forms and may require #2216 + // All select boxes fail to have a name / aria-label. + // This is a bug in ng-dynamic-forms and may require https://github.com/DSpace/dspace-angular/issues/2216 'select-name': { enabled: false }, } @@ -183,7 +186,8 @@ describe('New Submission page', () => { testA11y('ds-submission-edit', { rules: { - // All panels are accordians & fail "aria-required-children" and "nested-interactive". Seem to require updating ng-bootstrap and #2216 + // All panels are accordians & fail "aria-required-children" and "nested-interactive". + // Seem to require updating ng-bootstrap and https://github.com/DSpace/dspace-angular/issues/2216 'aria-required-children': { enabled: false }, 'nested-interactive': { enabled: false }, } diff --git a/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html index c397966fba1..d7f15ce06b4 100644 --- a/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/edit-comcol-page.component.html @@ -5,7 +5,8 @@ <h1>{{ type + '.edit.head' | translate }}</h1> <div class="my-auto"> <a class="btn btn-danger" - [routerLink]="((type === 'community') ? '/communities/' : '/collections/') + (dsoRD$ | async)?.payload.uuid + '/delete'"> + [routerLink]="((type === 'community') ? '/communities/' : '/collections/') + (dsoRD$ | async)?.payload.uuid + '/delete'" + data-test="delete-button"> <i class="fas fa-trash"></i> {{type + '.edit.delete' | translate}}</a> </div> </div> @@ -14,7 +15,8 @@ <h1>{{ type + '.edit.head' | translate }}</h1> <li *ngFor="let page of pages" class="nav-item"> <a class="nav-link" [ngClass]="{'active' : page === currentPage}" - [routerLink]="['./' + page]"> + [routerLink]="['./' + page]" + [attr.data-test]="page"> {{ type + '.edit.tabs.' + page + '.head' | translate}} </a> </li> From 9894d315a09d116fcdc536ef23a7db1e5828dc59 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 8 Dec 2023 16:09:02 -0600 Subject: [PATCH 277/282] Add Edit Collection accessibility Testing --- cypress/e2e/collection-edit.cy.ts | 86 +++++++++++++++++++++++++++++++ cypress/e2e/community-edit.cy.ts | 12 ----- 2 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 cypress/e2e/collection-edit.cy.ts diff --git a/cypress/e2e/collection-edit.cy.ts b/cypress/e2e/collection-edit.cy.ts new file mode 100644 index 00000000000..f6089acf70e --- /dev/null +++ b/cypress/e2e/collection-edit.cy.ts @@ -0,0 +1,86 @@ +import { testA11y } from 'cypress/support/utils'; + +const COLLECTION_EDIT_PAGE = '/collections/'.concat(Cypress.env('DSPACE_TEST_COLLECTION')).concat('/edit'); + +beforeEach(() => { + // All tests start with visiting the Edit Collection Page + cy.visit(COLLECTION_EDIT_PAGE); + + // This page is restricted, so we will be shown the login form. Fill it out & submit. + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); +}); + +describe('Edit Collection > Edit Metadata tab', () => { + it('should pass accessibility tests', () => { + // <ds-edit-collection> tag must be loaded + cy.get('ds-edit-collection').should('be.visible'); + + // Analyze <ds-edit-collection> for accessibility issues + testA11y('ds-edit-collection'); + }); +}); + +describe('Edit Collection > Assign Roles tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="roles"]').click(); + + // <ds-collection-roles> tag must be loaded + cy.get('ds-collection-roles').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-collection-roles'); + }); +}); + +describe('Edit Collection > Curate tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="curate"]').click(); + + // <ds-collection-curate> tag must be loaded + cy.get('ds-collection-curate').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-collection-curate'); + }); +}); + +describe('Edit Collection > Access Control tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="access-control"]').click(); + + // <ds-collection-access-control> tag must be loaded + cy.get('ds-collection-access-control').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-collection-access-control'); + }); +}); + +describe('Edit Collection > Authorizations tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="authorizations"]').click(); + + // <ds-collection-authorizations> tag must be loaded + cy.get('ds-collection-authorizations').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-collection-authorizations'); + }); +}); + +describe('Edit Collection > Delete page', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="delete-button"]').click(); + + // <ds-delete-collection> tag must be loaded + cy.get('ds-delete-collection').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-delete-collection'); + }); +}); diff --git a/cypress/e2e/community-edit.cy.ts b/cypress/e2e/community-edit.cy.ts index 06d78701f07..8fc1a7733e7 100644 --- a/cypress/e2e/community-edit.cy.ts +++ b/cypress/e2e/community-edit.cy.ts @@ -70,18 +70,6 @@ describe('Edit Community > Authorizations tab', () => { // Analyze for accessibility issues testA11y('ds-community-authorizations'); }); - - it('should have an edit policy page which also passes accessibility tests', () => { - cy.visit(COMMUNITY_EDIT_PAGE.concat('/authorizations')); - - cy.get('button[title="Edit policy"]').click(); - - // <ds-resource-policy-edit> tag must be loaded - cy.get('ds-resource-policy-edit').should('be.visible'); - - // Analyze for accessibility issues - testA11y('ds-resource-policy-edit'); - }); }); describe('Edit Community > Delete page', () => { From 00cb2f9e8a2635eaa8e5bc4c5a4234cb723f86b0 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Fri, 8 Dec 2023 16:30:22 -0600 Subject: [PATCH 278/282] Add accessibility tests (and minor fixes) for Edit Collection's Content Source tab and Item Mapper tab --- cypress/e2e/collection-edit.cy.ts | 42 +++++++++++++++++++ .../collection-item-mapper.component.html | 4 +- .../collection-source-controls.component.html | 2 +- .../collection-source.component.html | 2 +- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/collection-edit.cy.ts b/cypress/e2e/collection-edit.cy.ts index f6089acf70e..3e7ecf61410 100644 --- a/cypress/e2e/collection-edit.cy.ts +++ b/cypress/e2e/collection-edit.cy.ts @@ -33,6 +33,25 @@ describe('Edit Collection > Assign Roles tab', () => { }); }); +describe('Edit Collection > Content Source tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="source"]').click(); + + // <ds-collection-source> tag must be loaded + cy.get('ds-collection-source').should('be.visible'); + + // Check the external source checkbox (to display all fields on the page) + cy.get('#externalSourceCheck').check(); + + // Wait for the source controls to appear + cy.get('ds-collection-source-controls').should('be.visible'); + + // Analyze entire page for accessibility issues + testA11y('ds-collection-source'); + }); +}); + describe('Edit Collection > Curate tab', () => { it('should pass accessibility tests', () => { @@ -72,6 +91,29 @@ describe('Edit Collection > Authorizations tab', () => { }); }); +describe('Edit Collection > Item Mapper tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="mapper"]').click(); + + // <ds-collection-item-mapper> tag must be loaded + cy.get('ds-collection-item-mapper').should('be.visible'); + + // Analyze entire page for accessibility issues + testA11y('ds-collection-item-mapper'); + + // Click on the "Map new Items" tab + cy.get('li[data-test="mapTab"] a').click(); + + // Make sure search form is now visible + cy.get('ds-search-form').should('be.visible'); + + // Analyze entire page (again) for accessibility issues + testA11y('ds-collection-item-mapper'); + }); +}); + + describe('Edit Collection > Delete page', () => { it('should pass accessibility tests', () => { 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 649aa9b43db..77f85d5f78e 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 @@ <h2>{{'collection.edit.item-mapper.head' | translate}}</h2> <p>{{'collection.edit.item-mapper.description' | translate}}</p> <ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> - <li [ngbNavItem]="'browseTab'" role="presentation"> + <li [ngbNavItem]="'browseTab'" role="presentation" data-test="browseTab"> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.browse' | translate}}</a> <ng-template ngbNavContent> <div class="mt-2"> @@ -23,7 +23,7 @@ <h2>{{'collection.edit.item-mapper.head' | translate}}</h2> </div> </ng-template> </li> - <li [ngbNavItem]="'mapTab'" role="presentation"> + <li [ngbNavItem]="'mapTab'" role="presentation" data-test="mapTab"> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.map' | translate}}</a> <ng-template ngbNavContent> <div class="row mt-2"> diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html index 4d7b3e657ec..521c771cfaf 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source-controls/collection-source-controls.component.html @@ -1,6 +1,6 @@ <div *ngVar="(contentSource$ |async) as contentSource"> <div class="container-fluid space-children-mr" *ngIf="shouldShow"> - <h4>{{ 'collection.source.controls.head' | translate }}</h4> + <h3>{{ 'collection.source.controls.head' | translate }}</h3> <div> <span class="font-weight-bold">{{'collection.source.controls.harvest.status' | translate}}</span> <span>{{contentSource?.harvestStatus}}</span> diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html index 41e66610a85..b0c155ac957 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -26,7 +26,7 @@ <h2>{{ 'collection.edit.tabs.source.head' | translate }}</h2> for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label> </div> <ds-themed-loading *ngIf="!contentSource" [message]="'loading.content-source' | translate"></ds-themed-loading> - <h4 *ngIf="contentSource && (contentSource?.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4> + <h3 *ngIf="contentSource && (contentSource?.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h3> </div> <div class="row"> <ds-form *ngIf="formGroup && contentSource && (contentSource?.harvestType !== harvestTypeNone)" From 80492cd88a2b7d7a33465c1b5042a96433c40d24 Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 13 Dec 2023 14:56:52 -0600 Subject: [PATCH 279/282] Add Item Edit accessibility tests. Switch Item to use to one with bitstreams. Minor updates to HTML to pass accessibility tests. --- cypress.config.ts | 2 +- cypress/e2e/item-edit.cy.ts | 135 ++++++++++++++++++ .../dso-edit-metadata-value.component.html | 10 +- .../dso-edit-metadata-value.component.spec.ts | 2 +- .../edit-item-page.component.html | 1 + .../item-collection-mapper.component.html | 4 +- 6 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 cypress/e2e/item-edit.cy.ts diff --git a/cypress.config.ts b/cypress.config.ts index b1da2b47935..4143327870b 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -22,7 +22,7 @@ export default defineConfig({ // Community/collection/publication used for view/edit tests DSPACE_TEST_COMMUNITY: '0958c910-2037-42a9-81c7-dca80e3892b4', DSPACE_TEST_COLLECTION: '282164f5-d325-4740-8dd1-fa4d6d3e7200', - DSPACE_TEST_ENTITY_PUBLICATION: 'e98b0f27-5c19-49a0-960d-eb6ad5287067', + DSPACE_TEST_ENTITY_PUBLICATION: '6160810f-1e53-40db-81ef-f6621a727398', // Search term (should return results) used in search tests DSPACE_TEST_SEARCH_TERM: 'test', // Collection used for submission tests diff --git a/cypress/e2e/item-edit.cy.ts b/cypress/e2e/item-edit.cy.ts new file mode 100644 index 00000000000..b4c01a1a946 --- /dev/null +++ b/cypress/e2e/item-edit.cy.ts @@ -0,0 +1,135 @@ +import { Options } from 'cypress-axe'; +import { testA11y } from 'cypress/support/utils'; + +const ITEM_EDIT_PAGE = '/items/'.concat(Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION')).concat('/edit'); + +beforeEach(() => { + // All tests start with visiting the Edit Item Page + cy.visit(ITEM_EDIT_PAGE); + + // This page is restricted, so we will be shown the login form. Fill it out & submit. + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); +}); + +describe('Edit Item > Edit Metadata tab', () => { + it('should pass accessibility tests', () => { + cy.get('a[data-test="metadata"]').click(); + + // <ds-edit-item-page> tag must be loaded + cy.get('ds-edit-item-page').should('be.visible'); + + // Analyze <ds-edit-item-page> for accessibility issues + testA11y('ds-edit-item-page'); + }); +}); + +describe('Edit Item > Status tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="status"]').click(); + + // <ds-item-status> tag must be loaded + cy.get('ds-item-status').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-status'); + }); +}); + +describe('Edit Item > Bitstreams tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="bitstreams"]').click(); + + // <ds-item-bitstreams> tag must be loaded + cy.get('ds-item-bitstreams').should('be.visible'); + + // Table of item bitstreams must also be loaded + cy.get('div.item-bitstreams').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-bitstreams', + { + rules: { + // Currently Bitstreams page loads a pagination component per Bundle + // and they all use the same 'id="p-dad"'. + 'duplicate-id': { enabled: false }, + } + } as Options + ); + }); +}); + +describe('Edit Item > Curate tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="curate"]').click(); + + // <ds-item-curate> tag must be loaded + cy.get('ds-item-curate').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-curate'); + }); +}); + +describe('Edit Item > Relationships tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="relationships"]').click(); + + // <ds-item-relationships> tag must be loaded + cy.get('ds-item-relationships').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-relationships'); + }); +}); + +describe('Edit Item > Version History tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="versionhistory"]').click(); + + // <ds-item-version-history> tag must be loaded + cy.get('ds-item-version-history').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-version-history'); + }); +}); + +describe('Edit Item > Access Control tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="access-control"]').click(); + + // <ds-item-access-control> tag must be loaded + cy.get('ds-item-access-control').should('be.visible'); + + // Analyze for accessibility issues + testA11y('ds-item-access-control'); + }); +}); + +describe('Edit Item > Collection Mapper tab', () => { + + it('should pass accessibility tests', () => { + cy.get('a[data-test="mapper"]').click(); + + // <ds-item-collection-mapper> tag must be loaded + cy.get('ds-item-collection-mapper').should('be.visible'); + + // Analyze entire page for accessibility issues + testA11y('ds-item-collection-mapper'); + + // Click on the "Map new collections" tab + cy.get('li[data-test="mapTab"] a').click(); + + // Make sure search form is now visible + cy.get('ds-search-form').should('be.visible'); + + // Analyze entire page (again) for accessibility issues + testA11y('ds-item-collection-mapper'); + }); +}); diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index 2701ee24ab3..47449bda5c9 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -21,25 +21,25 @@ <div class="btn-group"> <div class="edit-field"> <div class="btn-group edit-buttons" [ngbTooltip]="isVirtual ? (dsoType + '.edit.metadata.edit.buttons.virtual' | translate) : null"> - <button class="btn btn-outline-primary btn-sm ng-star-inserted" id="metadata-edit-btn" *ngIf="!mdValue.editing" + <button class="btn btn-outline-primary btn-sm ng-star-inserted" data-test="metadata-edit-btn" *ngIf="!mdValue.editing" [title]="dsoType + '.edit.metadata.edit.buttons.edit' | translate" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.edit' | translate }}" [disabled]="isVirtual || mdValue.change === DsoEditMetadataChangeTypeEnum.REMOVE || (saving$ | async)" (click)="edit.emit()"> <i class="fas fa-edit fa-fw"></i> </button> - <button class="btn btn-outline-success btn-sm ng-star-inserted" id="metadata-confirm-btn" *ngIf="mdValue.editing" + <button class="btn btn-outline-success btn-sm ng-star-inserted" data-test="metadata-confirm-btn" *ngIf="mdValue.editing" [title]="dsoType + '.edit.metadata.edit.buttons.confirm' | translate" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.confirm' | translate }}" [disabled]="isVirtual || (saving$ | async)" (click)="confirm.emit(true)"> <i class="fas fa-check fa-fw"></i> </button> - <button class="btn btn-outline-danger btn-sm" id="metadata-remove-btn" + <button class="btn btn-outline-danger btn-sm" data-test="metadata-remove-btn" [title]="dsoType + '.edit.metadata.edit.buttons.remove' | translate" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.remove' | translate }}" [disabled]="isVirtual || (mdValue.change && mdValue.change !== DsoEditMetadataChangeTypeEnum.ADD) || mdValue.editing || (saving$ | async)" (click)="remove.emit()"> <i class="fas fa-trash-alt fa-fw"></i> </button> - <button class="btn btn-outline-warning btn-sm" id="metadata-undo-btn" + <button class="btn btn-outline-warning btn-sm" data-test="metadata-undo-btn" [title]="dsoType + '.edit.metadata.edit.buttons.undo' | translate" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.undo' | translate }}" [disabled]="isVirtual || (!mdValue.change && mdValue.reordered) || (!mdValue.change && !mdValue.editing) || (saving$ | async)" (click)="undo.emit()"> @@ -47,7 +47,7 @@ </button> </div> </div> - <button class="btn btn-outline-secondary ds-drag-handle btn-sm" id="metadata-drag-btn" *ngVar="(isOnlyValue || (saving$ | async)) as disabled" + <button class="btn btn-outline-secondary ds-drag-handle btn-sm" data-test="metadata-drag-btn" *ngVar="(isOnlyValue || (saving$ | async)) as disabled" cdkDragHandle [cdkDragHandleDisabled]="disabled" [ngClass]="{'disabled': disabled}" [disabled]="disabled" [title]="dsoType + '.edit.metadata.edit.buttons.drag' | translate" ngbTooltip="{{ dsoType + '.edit.metadata.edit.buttons.drag' | translate }}"> diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts index 67a6f98ac06..459095ea67b 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts @@ -149,7 +149,7 @@ describe('DsoEditMetadataValueComponent', () => { let btn: DebugElement; beforeEach(() => { - btn = fixture.debugElement.query(By.css(`#metadata-${name}-btn`)); + btn = fixture.debugElement.query(By.css(`button[data-test="metadata-${name}-btn"]`)); }); if (exists) { 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 1da10106f4f..63dadef3b1e 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 @@ -10,6 +10,7 @@ <h1 class="border-bottom">{{'item.edit.head' | translate}}</h1> class="nav-link" [ngClass]="{'active' : page.page === currentPage}" [routerLink]="['./' + page.page]" + [attr.data-test]="page.page" role="tab"> {{'item.edit.tabs.' + page.page + '.head' | translate}} </a> diff --git a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html index 1d025f65141..57287fdfe2e 100644 --- a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html +++ b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html @@ -6,7 +6,7 @@ <h2>{{'item.edit.item-mapper.head' | translate}}</h2> <p>{{'item.edit.item-mapper.description' | translate}}</p> <ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> - <li [ngbNavItem]="'browseTab'" role="presentation"> + <li [ngbNavItem]="'browseTab'" role="presentation" data-test="browseTab"> <a ngbNavLink>{{'item.edit.item-mapper.tabs.browse' | translate}}</a> <ng-template ngbNavContent> <div class="mt-2"> @@ -22,7 +22,7 @@ <h2>{{'item.edit.item-mapper.head' | translate}}</h2> </div> </ng-template> </li> - <li [ngbNavItem]="'mapTab'" role="presentation"> + <li [ngbNavItem]="'mapTab'" role="presentation" data-test="mapTab"> <a ngbNavLink>{{'item.edit.item-mapper.tabs.map' | translate}}</a> <ng-template ngbNavContent> <div class="row mt-2"> From 31bc05235ef2a6e61fd0fb784c2155e8a87d155f Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 13 Dec 2023 16:35:35 -0600 Subject: [PATCH 280/282] Add accessibility testing for admin sidebar --- cypress/e2e/admin-sidebar.cy.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 cypress/e2e/admin-sidebar.cy.ts diff --git a/cypress/e2e/admin-sidebar.cy.ts b/cypress/e2e/admin-sidebar.cy.ts new file mode 100644 index 00000000000..7612eb53132 --- /dev/null +++ b/cypress/e2e/admin-sidebar.cy.ts @@ -0,0 +1,28 @@ +import { Options } from 'cypress-axe'; +import { testA11y } from 'cypress/support/utils'; + +describe('Admin Sidebar', () => { + beforeEach(() => { + // Must login as an Admin for sidebar to appear + cy.visit('/login'); + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); + }); + + it('should be pinnable and pass accessibility tests', () => { + // Pin the sidebar open + cy.get('#sidebar-collapse-toggle').click(); + + // Click on every expandable section to open all menus + cy.get('ds-expandable-admin-sidebar-section').click({multiple: true}); + + // Analyze <ds-admin-sidebar> for accessibility + testA11y('ds-admin-sidebar', + { + rules: { + // Currently all expandable sections have nested interactive elements + // See https://github.com/DSpace/dspace-angular/issues/2178 + 'nested-interactive': { enabled: false }, + } + } as Options); + }); +}); From 0aaf3131fa4ef3b56b4f34715c417986e906cbab Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 17 Jan 2024 11:49:00 -0600 Subject: [PATCH 281/282] Move increment/decrement to i18n. Update to use "name". --- .../shared/form/number-picker/number-picker.component.html | 4 ++-- .../form/number-picker/number-picker.component.spec.ts | 4 +++- src/app/shared/form/number-picker/number-picker.component.ts | 5 ++++- src/assets/i18n/en.json5 | 4 ++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/app/shared/form/number-picker/number-picker.component.html b/src/app/shared/form/number-picker/number-picker.component.html index d4cf9e23f4b..12e29fa70e4 100644 --- a/src/app/shared/form/number-picker/number-picker.component.html +++ b/src/app/shared/form/number-picker/number-picker.component.html @@ -6,7 +6,7 @@ [disabled]="disabled" (click)="toggleUp()"> <span class="chevron"></span> - <span class="sr-only">Increment {{placeholder}}</span> + <span class="sr-only">{{'form.number-picker.increment' | translate: {field: name} }}</span> </button> <input id="{{id}}" @@ -33,6 +33,6 @@ [disabled]="disabled" (click)="toggleDown()"> <span class="chevron bottom"></span> - <span class="sr-only">Decrement {{placeholder}}</span> + <span class="sr-only">{{'form.number-picker.decrement' | translate: {field: name} }}</span> </button> </div> diff --git a/src/app/shared/form/number-picker/number-picker.component.spec.ts b/src/app/shared/form/number-picker/number-picker.component.spec.ts index bf33a6bdd0a..b6d623d70b7 100644 --- a/src/app/shared/form/number-picker/number-picker.component.spec.ts +++ b/src/app/shared/form/number-picker/number-picker.component.spec.ts @@ -7,6 +7,7 @@ import { By } from '@angular/platform-browser'; import { NumberPickerComponent } from './number-picker.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { createTestComponent } from '../../testing/utils.test'; +import { TranslateModule } from '@ngx-translate/core'; describe('NumberPickerComponent test suite', () => { @@ -23,7 +24,8 @@ describe('NumberPickerComponent test suite', () => { imports: [ FormsModule, ReactiveFormsModule, - NgbModule + NgbModule, + TranslateModule.forRoot() ], declarations: [ NumberPickerComponent, diff --git a/src/app/shared/form/number-picker/number-picker.component.ts b/src/app/shared/form/number-picker/number-picker.component.ts index 40562dd61c0..8f2de5ee542 100644 --- a/src/app/shared/form/number-picker/number-picker.component.ts +++ b/src/app/shared/form/number-picker/number-picker.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, SimpleChanges, } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; import { isEmpty } from '../../empty.util'; @Component({ @@ -31,7 +32,9 @@ export class NumberPickerComponent implements OnInit, ControlValueAccessor { startValue: number; - constructor(private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) { + constructor(private fb: UntypedFormBuilder, + private cd: ChangeDetectorRef, + private translate: TranslateService) { } ngOnInit() { diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index deea56b1d2d..d7c50b1a603 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1770,6 +1770,10 @@ "form.repeatable.sort.tip": "Drop the item in the new position", + "form.number-picker.decrement": "Decrement {{field}}", + + "form.number-picker.increment": "Increment {{field}}", + "grant-deny-request-copy.deny": "Don't send copy", "grant-deny-request-copy.email.back": "Back", From a5a89a4b985897a02a9ab4110ca0a02b8afdc6ad Mon Sep 17 00:00:00 2001 From: Tim Donohue <tim.donohue@lyrasis.org> Date: Wed, 17 Jan 2024 12:05:00 -0600 Subject: [PATCH 282/282] Add environment variable for Person collection name. Use it in submission e2e tests. --- cypress.config.ts | 4 +++- cypress/e2e/submission.cy.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cypress.config.ts b/cypress.config.ts index 4143327870b..458b035a484 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -25,9 +25,11 @@ export default defineConfig({ DSPACE_TEST_ENTITY_PUBLICATION: '6160810f-1e53-40db-81ef-f6621a727398', // Search term (should return results) used in search tests DSPACE_TEST_SEARCH_TERM: 'test', - // Collection used for submission tests + // Main Collection used for submission tests. Should be able to accept normal Item objects DSPACE_TEST_SUBMIT_COLLECTION_NAME: 'Sample Collection', DSPACE_TEST_SUBMIT_COLLECTION_UUID: '9d8334e9-25d3-4a67-9cea-3dffdef80144', + // Collection used for Person entity submission tests. MUST be configured with EntityType=Person. + DSPACE_TEST_SUBMIT_PERSON_COLLECTION_NAME: 'People', // Account used to test basic submission process DSPACE_TEST_SUBMIT_USER: 'dspacedemo+submit@gmail.com', DSPACE_TEST_SUBMIT_USER_PASSWORD: 'dspace', diff --git a/cypress/e2e/submission.cy.ts b/cypress/e2e/submission.cy.ts index 97676ca25cd..4402410f234 100644 --- a/cypress/e2e/submission.cy.ts +++ b/cypress/e2e/submission.cy.ts @@ -168,8 +168,11 @@ describe('New Submission page', () => { // This should display the <ds-create-item-parent-selector> (popup window) cy.get('ds-create-item-parent-selector').should('be.visible'); - // Click on the first Collection button to seelect a collection (actual collection doesn't matter) - cy.get('ds-authorized-collection-selector button:first-child').click(); + // Type in a known Collection name in the search box + cy.get('ds-authorized-collection-selector input[type="search"]').type(Cypress.env('DSPACE_TEST_SUBMIT_PERSON_COLLECTION_NAME')); + + // Click on the button matching that known Collection name + cy.get('ds-authorized-collection-selector button[title="'.concat(Cypress.env('DSPACE_TEST_SUBMIT_PERSON_COLLECTION_NAME')).concat('"]')).click(); // New URL should include /workspaceitems, as we've started a new submission cy.url().should('include', '/workspaceitems'); @@ -177,6 +180,9 @@ describe('New Submission page', () => { // The Submission edit form tag should be visible cy.get('ds-submission-edit').should('be.visible'); + // A Collection menu button should exist & its value should be the selected collection + cy.get('#collectionControlsMenuButton span').should('have.text', Cypress.env('DSPACE_TEST_SUBMIT_PERSON_COLLECTION_NAME')); + // 3 sections should be visible by default cy.get('div#section_personStep').should('be.visible'); cy.get('div#section_upload').should('be.visible');