Merge branch 'main' into coar-notify-7

This commit is contained in:
Alisa Ismailati
2024-01-12 11:21:15 +01:00
224 changed files with 891 additions and 496 deletions

View File

@@ -8,11 +8,6 @@ describe('Header', () => {
cy.get('ds-header').should('be.visible'); cy.get('ds-header').should('be.visible');
// Analyze <ds-header> for accessibility // Analyze <ds-header> for accessibility
testA11y({ testA11y('ds-header');
include: ['ds-header'],
exclude: [
['#search-navbar-container'] // search in navbar has duplicative ID. Will be fixed in #1174
],
});
}); });
}); });

View File

@@ -121,7 +121,7 @@
"ngx-infinite-scroll": "^15.0.0", "ngx-infinite-scroll": "^15.0.0",
"ngx-pagination": "6.0.3", "ngx-pagination": "6.0.3",
"ngx-sortablejs": "^11.1.0", "ngx-sortablejs": "^11.1.0",
"ngx-ui-switch": "^14.0.3", "ngx-ui-switch": "^14.1.0",
"nouislider": "^15.7.1", "nouislider": "^15.7.1",
"pem": "1.14.7", "pem": "1.14.7",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",

View File

@@ -1,15 +1,15 @@
<ngb-accordion #acc="ngbAccordion" [activeIds]="'browse'"> <ngb-accordion #acc="ngbAccordion" [activeIds]="'browse'">
<ngb-panel [id]="'browse'"> <ngb-panel [id]="'browse'">
<ng-template ngbPanelHeader> <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"> data-test="browse">
<button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()"
[attr.aria-expanded]="!acc.isExpanded('browse')" [attr.aria-expanded]="acc.isExpanded('browse')"
aria-controls="collapsePanels"> aria-controls="bulk-access-browse-panel-content">
{{ 'admin.access-control.bulk-access-browse.header' | translate }} {{ 'admin.access-control.bulk-access-browse.header' | translate }}
</button> </button>
<div class="text-right d-flex"> <div class="text-right d-flex gap-2">
<div class="ml-3 d-inline-block"> <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-up fa-fw"></span>
<span *ngIf="!acc.isExpanded('browse')" class="fas fa-chevron-down fa-fw"></span> <span *ngIf="!acc.isExpanded('browse')" class="fas fa-chevron-down fa-fw"></span>
</div> </div>
@@ -17,51 +17,53 @@
</div> </div>
</ng-template> </ng-template>
<ng-template ngbPanelContent> <ng-template ngbPanelContent>
<ul ngbNav #nav="ngbNav" [(activeId)]="activateId" class="nav-pills"> <div id="bulk-access-browse-panel-content">
<li [ngbNavItem]="'search'"> <ul ngbNav #nav="ngbNav" [(activeId)]="activateId" class="nav-pills">
<a ngbNavLink>{{'admin.access-control.bulk-access-browse.search.header' | translate}}</a> <li [ngbNavItem]="'search'" role="presentation">
<ng-template ngbNavContent> <a ngbNavLink>{{'admin.access-control.bulk-access-browse.search.header' | translate}}</a>
<div class="mx-n3"> <ng-template ngbNavContent>
<ds-themed-search [configuration]="'administrativeBulkAccess'" <div class="mx-n3">
[selectable]="true" <ds-themed-search [configuration]="'administrativeBulkAccess'"
[selectionConfig]="{ repeatable: true, listId: listId }" [selectable]="true"
[showThumbnails]="false"></ds-themed-search> [selectionConfig]="{ repeatable: true, listId: listId }"
</div> [showThumbnails]="false"></ds-themed-search>
</ng-template> </div>
</li> </ng-template>
<li [ngbNavItem]="'selected'"> </li>
<a ngbNavLink> <li [ngbNavItem]="'selected'" role="presentation">
{{'admin.access-control.bulk-access-browse.selected.header' | translate: {number: ((objectsSelected$ | async)?.payload?.totalElements) ? (objectsSelected$ | async)?.payload?.totalElements : '0'} }} <a ngbNavLink>
</a> {{'admin.access-control.bulk-access-browse.selected.header' | translate: {number: ((objectsSelected$ | async)?.payload?.totalElements) ? (objectsSelected$ | async)?.payload?.totalElements : '0'} }}
<ng-template ngbNavContent> </a>
<ds-pagination <ng-template ngbNavContent>
[paginationOptions]="(paginationOptions$ | async)" <ds-pagination
[pageInfoState]="(objectsSelected$|async)?.payload.pageInfo" [paginationOptions]="(paginationOptions$ | async)"
[collectionSize]="(objectsSelected$|async)?.payload?.totalElements" [pageInfoState]="(objectsSelected$|async)?.payload.pageInfo"
[objects]="(objectsSelected$|async)" [collectionSize]="(objectsSelected$|async)?.payload?.totalElements"
[showPaginator]="false" [objects]="(objectsSelected$|async)"
(prev)="pagePrev()" [showPaginator]="false"
(next)="pageNext()"> (prev)="pagePrev()"
<ul *ngIf="(objectsSelected$|async)?.hasSucceeded" class="list-unstyled ml-4"> (next)="pageNext()">
<li *ngFor='let object of (objectsSelected$|async)?.payload?.page | paginate: { itemsPerPage: (paginationOptions$ | async).pageSize, <ul *ngIf="(objectsSelected$|async)?.hasSucceeded" class="list-unstyled ml-4">
currentPage: (paginationOptions$ | async).currentPage, totalItems: (objectsSelected$|async)?.payload?.page.length }; let i = index; let last = last ' <li *ngFor='let object of (objectsSelected$|async)?.payload?.page | paginate: { itemsPerPage: (paginationOptions$ | async).pageSize,
class="mt-4 mb-4 d-flex" currentPage: (paginationOptions$ | async).currentPage, totalItems: (objectsSelected$|async)?.payload?.page.length }; let i = index; let last = last '
[attr.data-test]="'list-object' | dsBrowserOnly"> class="mt-4 mb-4 d-flex"
<ds-selectable-list-item-control [index]="i" [attr.data-test]="'list-object' | dsBrowserOnly">
[object]="object" <ds-selectable-list-item-control [index]="i"
[selectionConfig]="{ repeatable: true, listId: listId }"></ds-selectable-list-item-control> [object]="object"
<ds-listable-object-component-loader [listID]="listId" [selectionConfig]="{ repeatable: true, listId: listId }"></ds-selectable-list-item-control>
[index]="i" <ds-listable-object-component-loader [listID]="listId"
[object]="object" [index]="i"
[showThumbnails]="false" [object]="object"
[viewMode]="'list'"></ds-listable-object-component-loader> [showThumbnails]="false"
</li> [viewMode]="'list'"></ds-listable-object-component-loader>
</ul> </li>
</ds-pagination> </ul>
</ng-template> </ds-pagination>
</li> </ng-template>
</ul> </li>
<div [ngbNavOutlet]="nav" class="mt-5"></div> </ul>
<div [ngbNavOutlet]="nav" class="mt-5"></div>
</div>
</ng-template> </ng-template>
</ngb-panel> </ngb-panel>
</ngb-accordion> </ngb-accordion>

View File

@@ -1,13 +1,13 @@
<ngb-accordion #acc="ngbAccordion" [activeIds]="'settings'"> <ngb-accordion #acc="ngbAccordion" [activeIds]="'settings'">
<ngb-panel [id]="'settings'"> <ngb-panel [id]="'settings'">
<ng-template ngbPanelHeader> <ng-template ngbPanelHeader>
<div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle('settings')" data-test="settings"> <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('browse')" <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded('settings')"
aria-controls="collapsePanels"> aria-controls="bulk-access-settings-panel-content">
{{ 'admin.access-control.bulk-access-settings.header' | translate }} {{ 'admin.access-control.bulk-access-settings.header' | translate }}
</button> </button>
<div class="text-right d-flex"> <div class="text-right d-flex gap-2">
<div class="ml-3 d-inline-block"> <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-up fa-fw"></span>
<span *ngIf="!acc.isExpanded('settings')" class="fas fa-chevron-down fa-fw"></span> <span *ngIf="!acc.isExpanded('settings')" class="fas fa-chevron-down fa-fw"></span>
</div> </div>
@@ -15,7 +15,7 @@
</div> </div>
</ng-template> </ng-template>
<ng-template ngbPanelContent> <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> </ng-template>
</ngb-panel> </ngb-panel>
</ngb-accordion> </ngb-accordion>

View File

@@ -2,7 +2,7 @@
<div class="epeople-registry row"> <div class="epeople-registry row">
<div class="col-12"> <div class="col-12">
<div class="d-flex justify-content-between border-bottom mb-3"> <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> <div>
<button class="mr-auto btn btn-success addEPerson-button" <button class="mr-auto btn btn-success addEPerson-button"
@@ -13,9 +13,9 @@
</div> </div>
</div> </div>
<h3 id="search" class="border-bottom pb-2">{{labelPrefix + 'search.head' | translate}} <h2 id="search" class="border-bottom pb-2">
{{labelPrefix + 'search.head' | translate}}
</h3> </h2>
<form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between">
<div> <div>
<select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope"> <select name="scope" id="scope" formControlName="scope" class="form-control" aria-label="Search scope">

View File

@@ -5,11 +5,11 @@
<div *ngIf="epersonService.getActiveEPerson() | async; then editHeader; else createHeader"></div> <div *ngIf="epersonService.getActiveEPerson() | async; then editHeader; else createHeader"></div>
<ng-template #createHeader> <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>
<ng-template #editHeader> <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> </ng-template>
<ds-form [formId]="formId" <ds-form [formId]="formId"
@@ -45,7 +45,7 @@
<ds-themed-loading [showMessage]="false" *ngIf="!formGroup"></ds-themed-loading> <ds-themed-loading [showMessage]="false" *ngIf="!formGroup"></ds-themed-loading>
<div *ngIf="epersonService.getActiveEPerson() | async"> <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> <ds-themed-loading [showMessage]="false" *ngIf="!(groups | async)"></ds-themed-loading>

View File

@@ -5,11 +5,11 @@
<div *ngIf="groupDataService.getActiveGroup() | async; then editHeader; else createHeader"></div> <div *ngIf="groupDataService.getActiveGroup() | async; then editHeader; else createHeader"></div>
<ng-template #createHeader> <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>
<ng-template #editHeader> <ng-template #editHeader>
<h2 class="border-bottom pb-2"> <h1 class="border-bottom pb-2">
<span <span
*dsContextHelp="{ *dsContextHelp="{
content: 'admin.access-control.groups.form.tooltip.editGroupPage', content: 'admin.access-control.groups.form.tooltip.editGroupPage',
@@ -20,7 +20,7 @@
> >
{{messagePrefix + '.head.edit' | translate}} {{messagePrefix + '.head.edit' | translate}}
</span> </span>
</h2> </h1>
</ng-template> </ng-template>
<ds-alert *ngIf="groupBeingEdited?.permanent" [type]="AlertTypeEnum.Warning" <ds-alert *ngIf="groupBeingEdited?.permanent" [type]="AlertTypeEnum.Warning"
@@ -39,9 +39,8 @@
<button (click)="onCancel()" type="button" <button (click)="onCancel()" type="button"
class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button> class="btn btn-outline-secondary"><i class="fas fa-arrow-left"></i> {{messagePrefix + '.return' | translate}}</button>
</div> </div>
<div after *ngIf="(canEdit$ | async) && !groupBeingEdited.permanent" 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" <button (click)="delete()" class="btn btn-danger delete-button" type="button">
(click)="delete()" type="button">
<i class="fa fa-trash"></i> {{ messagePrefix + '.actions.delete' | translate}} <i class="fa fa-trash"></i> {{ messagePrefix + '.actions.delete' | translate}}
</button> </button>
</div> </div>

View File

@@ -1,7 +1,7 @@
<ng-container> <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" <ds-pagination *ngIf="(ePeopleMembersOfGroup | async)?.totalElements > 0"
[paginationOptions]="config" [paginationOptions]="config"
@@ -55,7 +55,7 @@
{{messagePrefix + '.no-members-yet' | translate}} {{messagePrefix + '.no-members-yet' | translate}}
</div> </div>
<h4 id="search" class="border-bottom pb-2"> <h3 id="search" class="border-bottom pb-2">
<span <span
*dsContextHelp="{ *dsContextHelp="{
content: 'admin.access-control.groups.form.tooltip.editGroup.addEpeople', content: 'admin.access-control.groups.form.tooltip.editGroup.addEpeople',
@@ -66,7 +66,7 @@
> >
{{messagePrefix + '.search.head' | translate}} {{messagePrefix + '.search.head' | translate}}
</span> </span>
</h4> </h3>
<form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between"> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between">
<div class="flex-grow-1 mr-3"> <div class="flex-grow-1 mr-3">

View File

@@ -2,7 +2,7 @@
<div class="groups-registry row"> <div class="groups-registry row">
<div class="col-12"> <div class="col-12">
<div class="d-flex justify-content-between border-bottom mb-3"> <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> <div>
<button class="mr-auto btn btn-success" <button class="mr-auto btn btn-success"
[routerLink]="'create'"> [routerLink]="'create'">
@@ -12,7 +12,7 @@
</div> </div>
</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"> <form [formGroup]="searchForm" (ngSubmit)="search(searchForm.value)" class="d-flex justify-content-between">
<div class="flex-grow-1 mr-3"> <div class="flex-grow-1 mr-3">
<div class="form-group input-group"> <div class="form-group input-group">

View File

@@ -1,4 +1,4 @@
<div class="container"> <div class="container">
<h2>{{'admin.curation-tasks.header' |translate }}</h2> <h1>{{'admin.curation-tasks.header' |translate }}</h1>
<ds-curation-form></ds-curation-form> <ds-curation-form></ds-curation-form>
</div> </div>

View File

@@ -1,5 +1,5 @@
<div class="container"> <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> <p>{{'admin.metadata-import.page.help' | translate}}</p>
<div class="form-group"> <div class="form-group">
<div class="form-check"> <div class="form-check">

View File

@@ -14,7 +14,11 @@ import { AdminQualityAssuranceTopicsPageResolver } from './admin-quality-assuran
import { AdminQualityAssuranceEventsPageResolver } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.resolver'; 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 { 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 { 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';
import {
SourceDataResolver
} from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-data.resolver';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -40,7 +44,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon
component: AdminQualityAssuranceTopicsPageComponent, component: AdminQualityAssuranceTopicsPageComponent,
pathMatch: 'full', pathMatch: 'full',
resolve: { resolve: {
breadcrumb: I18nBreadcrumbResolver, breadcrumb: QualityAssuranceBreadcrumbResolver,
openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver
}, },
data: { data: {
@@ -86,7 +90,7 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon
component: AdminQualityAssuranceEventsPageComponent, component: AdminQualityAssuranceEventsPageComponent,
pathMatch: 'full', pathMatch: 'full',
resolve: { resolve: {
breadcrumb: I18nBreadcrumbResolver, breadcrumb: QualityAssuranceBreadcrumbResolver,
openaireQualityAssuranceEventsParams: AdminQualityAssuranceEventsPageResolver openaireQualityAssuranceEventsParams: AdminQualityAssuranceEventsPageResolver
}, },
data: { data: {
@@ -105,6 +109,9 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon
AdminQualityAssuranceSourcePageResolver, AdminQualityAssuranceSourcePageResolver,
AdminQualityAssuranceTopicsPageResolver, AdminQualityAssuranceTopicsPageResolver,
AdminQualityAssuranceEventsPageResolver, AdminQualityAssuranceEventsPageResolver,
AdminQualityAssuranceSourcePageResolver,
QualityAssuranceBreadcrumbResolver,
QualityAssuranceBreadcrumbService
] ]
}) })
/** /**

View File

@@ -7,7 +7,7 @@ import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifi
import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-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 { 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 { 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({ @NgModule({
imports: [ imports: [
@@ -15,7 +15,7 @@ import {SuggestionNotificationsModule} from '../../suggestion-notifications/sugg
SharedModule, SharedModule,
CoreModule.forRoot(), CoreModule.forRoot(),
AdminNotificationsRoutingModule, AdminNotificationsRoutingModule,
SuggestionNotificationsModule NotificationsModule
], ],
declarations: [ declarations: [
AdminNotificationsSuggestionTargetsPageComponent, AdminNotificationsSuggestionTargetsPageComponent,

View File

@@ -3,13 +3,15 @@ import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot, Router } from '@a
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { PaginatedList } from '../../../core/data/paginated-list.model'; import { PaginatedList } from '../../../core/data/paginated-list.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 { QualityAssuranceSourceService } from '../../../suggestion-notifications/qa/source/quality-assurance-source.service'; 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. * This class represents a resolver that retrieve the route data before the route is activated.
*/ */
@Injectable() @Injectable()
export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSourceObject[]>> { export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSourceObject[]>> {
private pageSize = environment.qualityAssuranceConfig.pageSize;
/** /**
* Initialize the effect class variables. * Initialize the effect class variables.
* @param {QualityAssuranceSourceService} qualityAssuranceSourceService * @param {QualityAssuranceSourceService} qualityAssuranceSourceService
@@ -25,7 +27,7 @@ export class SourceDataResolver implements Resolve<Observable<QualityAssuranceSo
* @returns Observable<QualityAssuranceSourceObject[]> * @returns Observable<QualityAssuranceSourceObject[]>
*/ */
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<QualityAssuranceSourceObject[]> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<QualityAssuranceSourceObject[]> {
return this.qualityAssuranceSourceService.getSources(5,0).pipe( return this.qualityAssuranceSourceService.getSources(this.pageSize, 0).pipe(
map((sources: PaginatedList<QualityAssuranceSourceObject>) => { map((sources: PaginatedList<QualityAssuranceSourceObject>) => {
if (sources.page.length === 1) { if (sources.page.length === 1) {
this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]); this.router.navigate([this.getResolvedUrl(route) + '/' + sources.page[0].id]);

View File

@@ -1,11 +1,11 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12 mb-4"> <div class="col-12 mb-4">
<h2 id="sub-header" <h1 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 }}</h1>
<ds-bitstream-format-form (updatedFormat)="createBitstreamFormat($event)"></ds-bitstream-format-form> <ds-bitstream-format-form (updatedFormat)="createBitstreamFormat($event)"></ds-bitstream-format-form>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,7 +2,7 @@
<div class="bitstream-formats row"> <div class="bitstream-formats row">
<div class="col-12"> <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="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> <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 @@
<table id="formats" class="table table-striped table-hover"> <table id="formats" class="table table-striped table-hover">
<thead> <thead>
<tr> <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.id' | translate}}</th>
<th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th> <th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th>
<th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th> <th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th>
@@ -31,6 +31,7 @@
<td> <td>
<label class="mb-0"> <label class="mb-0">
<input type="checkbox" <input type="checkbox"
[attr.aria-label]="'admin.registries.bitstream-formats.select' | translate"
[checked]="isSelected(bitstreamFormat) | async" [checked]="isSelected(bitstreamFormat) | async"
(change)="selectBitStreamFormat(bitstreamFormat, $event)" (change)="selectBitStreamFormat(bitstreamFormat, $event)"
> >

View File

@@ -1,11 +1,11 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12 mb-4"> <div class="col-12 mb-4">
<h2 id="sub-header" <h1 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} }}</h1>
<ds-bitstream-format-form [bitstreamFormat]="(bitstreamFormatRD$ | async)?.payload" (updatedFormat)="updateFormat($event)"></ds-bitstream-format-form> <ds-bitstream-format-form [bitstreamFormat]="(bitstreamFormatRD$ | async)?.payload" (updatedFormat)="updateFormat($event)"></ds-bitstream-format-form>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -34,22 +34,21 @@
</div> </div>
<div class="navbar-nav"> <div class="navbar-nav">
<div class="sidebar-section" id="sidebar-collapse-toggle"> <div class="sidebar-section" id="sidebar-collapse-toggle">
<a class="nav-item nav-link sidebar-section d-flex flex-row flex-nowrap" <button class="nav-item nav-link sidebar-section d-flex flex-row flex-nowrap border-0" type="button"
href="javascript:void(0);"
(click)="toggle($event)" (click)="toggle($event)"
(keyup.space)="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" <i *ngIf="(menuCollapsed | async)" class="fas fa-fw fa-angle-double-right"
[title]="'menu.section.icon.pin' | translate"></i> [title]="'menu.section.icon.pin' | translate"></i>
<i *ngIf="!(menuCollapsed | async)" class="fas fa-fw fa-angle-double-left" <i *ngIf="!(menuCollapsed | async)" class="fas fa-fw fa-angle-double-left"
[title]="'menu.section.icon.unpin' | translate"></i> [title]="'menu.section.icon.unpin' | translate"></i>
</div> </span>
<div class="sidebar-collapsible"> <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.pin' | translate }}</span>
<span *ngIf="!(menuCollapsed | async)" class="section-header-text">{{'menu.section.unpin' | translate }}</span> <span *ngIf="!(menuCollapsed | async)" class="section-header-text">{{'menu.section.unpin' | translate }}</span>
</div> </span>
</a> </button>
</div> </div>
</div> </div>
</nav> </nav>

View File

@@ -143,7 +143,7 @@ describe('AdminSidebarComponent', () => {
describe('when the collapse link is clicked', () => { describe('when the collapse link is clicked', () => {
beforeEach(() => { beforeEach(() => {
spyOn(menuService, 'toggleMenu'); 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', { sidebarToggler.triggerEventHandler('click', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }

View File

@@ -1,5 +1,5 @@
<div class="container"> <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"> <div class="pt-3">
<button (click)="back()" class="btn btn-outline-secondary"> <button (click)="back()" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> {{'bitstream.download.page.back' | translate}} <i class="fas fa-arrow-left"></i> {{'bitstream.download.page.back' | translate}}

View File

@@ -8,7 +8,7 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <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> </div>
</div> </div>

View File

@@ -1,4 +1,5 @@
<div class="container"> <div class="container">
<h1>{{ ('browse.taxonomy_' + vocabularyName + '.title') | translate }}</h1>
<div class="mb-3"> <div class="mb-3">
<ds-vocabulary-treeview [vocabularyOptions]=vocabularyOptions <ds-vocabulary-treeview [vocabularyOptions]=vocabularyOptions
[multiSelect]="true" [multiSelect]="true"

View File

@@ -6,7 +6,7 @@
<p>{{'collection.edit.item-mapper.description' | translate}}</p> <p>{{'collection.edit.item-mapper.description' | translate}}</p>
<ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> <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> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.browse' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="mt-2"> <div class="mt-2">
@@ -23,7 +23,7 @@
</div> </div>
</ng-template> </ng-template>
</li> </li>
<li [ngbNavItem]="'mapTab'"> <li [ngbNavItem]="'mapTab'" role="presentation">
<a ngbNavLink>{{'collection.edit.item-mapper.tabs.map' | translate}}</a> <a ngbNavLink>{{'collection.edit.item-mapper.tabs.map' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row mt-2"> <div class="row mt-2">

View File

@@ -2,7 +2,7 @@
<div class="row"> <div class="row">
<ng-container *ngVar="(dsoRD$ | async)?.payload as dso"> <ng-container *ngVar="(dsoRD$ | async)?.payload as dso">
<div class="col-12 pb-4"> <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> <p class="pb-2">{{ 'collection.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p>
<div class="form-group row"> <div class="form-group row">
<div class="col text-right space-children-mr"> <div class="col text-right space-children-mr">

View File

@@ -1,5 +1,5 @@
<div class="container"> <div class="container">
<h3>{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}</h3> <h2>{{'collection.curate.header' |translate:{collection: (collectionName$ |async)} }}</h2>
<ds-curation-form <ds-curation-form
[dsoHandle]="(dsoRD$|async)?.payload.handle" [dsoHandle]="(dsoRD$|async)?.payload.handle"
></ds-curation-form> ></ds-curation-form>

View File

@@ -18,7 +18,7 @@
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.metadata.save-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.metadata.save-button" | translate}}</span>
</button> </button>
</div> </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"> <div *ngIf="contentSource" class="form-check mb-4">
<input type="checkbox" class="form-check-input" id="externalSourceCheck" <input type="checkbox" class="form-check-input" id="externalSourceCheck"
[checked]="(contentSource?.harvestType !== harvestTypeNone)" (change)="changeExternalSource()"> [checked]="(contentSource?.harvestType !== harvestTypeNone)" (change)="changeExternalSource()">

View File

@@ -2,7 +2,7 @@
<div class="row"> <div class="row">
<div class="col-12" *ngVar="(itemRD$ | async) as itemRD"> <div class="col-12" *ngVar="(itemRD$ | async) as itemRD">
<ng-container *ngIf="itemRD?.hasSucceeded"> <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> <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> <button [routerLink]="getCollectionEditUrl(collection)" class="btn btn-outline-secondary">{{ 'collection.edit.template.cancel' | translate }}</button>
</ng-container> </ng-container>

View File

@@ -2,7 +2,7 @@
<div class="row"> <div class="row">
<ng-container *ngVar="(dsoRD$ | async)?.payload as dso"> <ng-container *ngVar="(dsoRD$ | async)?.payload as dso">
<div class="col-12 pb-4"> <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> <p class="pb-2">{{ 'community.delete.text' | translate:{ dso: dsoNameService.getName(dso) } }}</p>
<div class="form-group row"> <div class="form-group row">
<div class="col text-right space-children-mr"> <div class="col text-right space-children-mr">

View File

@@ -1,5 +1,5 @@
<div class="container"> <div class="container">
<h3>{{'community.curate.header' |translate:{community: (communityName$ |async)} }}</h3> <h2>{{'community.curate.header' |translate:{community: (communityName$ |async)} }}</h2>
<ds-curation-form <ds-curation-form
[dsoHandle]="(dsoRD$|async)?.payload.handle" [dsoHandle]="(dsoRD$|async)?.payload.handle"
></ds-curation-form> ></ds-curation-form>

View File

@@ -50,7 +50,7 @@ export class DSONameService {
} }
}, },
OrgUnit: (dso: DSpaceObject): string => { OrgUnit: (dso: DSpaceObject): string => {
return dso.firstMetadataValue('organization.legalName'); return dso.firstMetadataValue('organization.legalName') || this.translateService.instant('dso.name.untitled');
}, },
Default: (dso: DSpaceObject): string => { Default: (dso: DSpaceObject): string => {
// If object doesn't have dc.title metadata use name property // If object doesn't have dc.title metadata use name property
@@ -106,7 +106,7 @@ export class DSONameService {
} }
return `${familyName}, ${givenName}`; return `${familyName}, ${givenName}`;
} else if (entityType === 'OrgUnit') { } 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'); return this.firstMetadataValue(object, dso, 'dc.title') || dso.name || this.translateService.instant('dso.name.untitled');
} }

View File

@@ -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 (param) {
return this[param];
},
sourceId: 'testSourceId',
topicId: 'testTopicId'
}
};
qualityAssuranceBreadcrumbService = {};
resolver = new QualityAssuranceBreadcrumbResolver(qualityAssuranceBreadcrumbService);
});
it('should resolve the breadcrumb config', () => {
const resolvedConfig = resolver.resolve(route as any, {url: fullPath + 'testSourceId'} as any);
const expectedConfig = { provider: qualityAssuranceBreadcrumbService, key: expectedKey, url: fullPath };
expect(resolvedConfig).toEqual(expectedConfig);
});
});
});

View File

@@ -0,0 +1,32 @@
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');
let key = sourceId;
if (topicId) {
key += `:${topicId}`;
}
const fullPath = state.url;
const url = fullPath.substr(0, fullPath.indexOf(sourceId));
return { provider: this.breadcrumbService, key, url };
}
}

View File

@@ -0,0 +1,40 @@
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 = {
instant: (str) => str,
};
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)]
});
});
});
});

View File

@@ -0,0 +1,53 @@
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';
/**
* 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: QualityAssuranceTopicDataService,
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(topicId).pipe(
getFirstCompletedRemoteData(),
map((topic) => {
return [new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url),
new Breadcrumb(sourceId, `${url}${sourceId}`),
new Breadcrumb(topicId, undefined)];
})
);
} else {
return observableOf([new Breadcrumb(this.translationService.instant(this.QUALITY_ASSURANCE_BREADCRUMB_KEY), url),
new Breadcrumb(sourceId, `${url}${sourceId}`)]);
}
}
}

View File

@@ -157,9 +157,9 @@ import { SequenceService } from './shared/sequence.service';
import { CoreState } from './core-state.model'; import { CoreState } from './core-state.model';
import { GroupDataService } from './eperson/group-data.service'; import { GroupDataService } from './eperson/group-data.service';
import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model'; import { SubmissionAccessesModel } from './config/models/config-submission-accesses.model';
import { QualityAssuranceTopicObject } from './suggestion-notifications/qa/models/quality-assurance-topic.model'; import { QualityAssuranceTopicObject } from './notifications/qa/models/quality-assurance-topic.model';
import { QualityAssuranceEventObject } from './suggestion-notifications/qa/models/quality-assurance-event.model'; import { QualityAssuranceEventObject } from './notifications/qa/models/quality-assurance-event.model';
import { QualityAssuranceSourceObject } from './suggestion-notifications/qa/models/quality-assurance-source.model'; import { QualityAssuranceSourceObject } from './notifications/qa/models/quality-assurance-source.model';
import { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model'; import { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model';
import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model'; import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model';
import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model'; import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model';

View File

@@ -34,5 +34,6 @@ export enum FeatureID {
CanEditItem = 'canEditItem', CanEditItem = 'canEditItem',
CanRegisterDOI = 'canRegisterDOI', CanRegisterDOI = 'canRegisterDOI',
CanSubscribe = 'canSubscribeDso', CanSubscribe = 'canSubscribeDso',
CoarLdnEnabled = 'coarLdnEnabled' CoarLdnEnabled = 'coarLdnEnabled',
CanSeeQA = 'canSeeQA'
} }

View File

@@ -22,7 +22,7 @@ export interface QualityAssuranceEventMessageObject {
/** /**
* The interface representing the Quality Assurance event message * The interface representing the Quality Assurance event message
*/ */
export interface OpenaireQualityAssuranceEventMessageObject { export interface SourceQualityAssuranceEventMessageObject {
/** /**
* The type of 'value' * The type of 'value'
*/ */
@@ -69,9 +69,9 @@ export interface OpenaireQualityAssuranceEventMessageObject {
title: string; title: string;
/** /**
* The OPENAIRE ID. * The Source ID.
*/ */
openaireId: string; sourceId: string;
/** /**
* The PID href. * The PID href.
@@ -136,7 +136,7 @@ export class QualityAssuranceEventObject implements CacheableObject {
* The suggestion data. Data may vary depending on the source * The suggestion data. Data may vary depending on the source
*/ */
@autoserialize @autoserialize
message: OpenaireQualityAssuranceEventMessageObject; message: SourceQualityAssuranceEventMessageObject;
/** /**
* The type of this ConfigObject * The type of this ConfigObject

View File

@@ -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="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> <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" <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> [dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea>
<div class="d-flex" *ngIf="mdRepresentation"> <div class="d-flex" *ngIf="mdRepresentation">
<a class="mr-2" target="_blank" [routerLink]="mdRepresentationItemRoute$ | async">{{ mdRepresentationName$ | async }}</a> <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="ds-flex-cell ds-lang-cell" role="cell">
<div class="dont-break-out preserve-line-breaks" *ngIf="!mdValue.editing">{{ mdValue.newValue.language }}</div> <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" <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)" /> [dsDebounce]="300" (onDebounce)="confirm.emit(false)" />
</div> </div>
<div class="text-center ds-flex-cell ds-edit-cell" role="cell"> <div class="text-center ds-flex-cell ds-edit-cell" role="cell">

View File

@@ -62,21 +62,22 @@
<a class="text-white" <a class="text-white"
href="https://www.lyrasis.org/">{{ 'footer.link.lyrasis' | translate}}</a> href="https://www.lyrasis.org/">{{ 'footer.link.lyrasis' | translate}}</a>
</p> </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> <li>
<a class="text-white" href="javascript:void(0);" <button class="btn btn-link text-white" type="button" (click)="showCookieSettings()">
(click)="showCookieSettings()">{{ 'footer.link.cookies' | translate}}</a> {{ 'footer.link.cookies' | translate}}
</button>
</li> </li>
<li *ngIf="showPrivacyPolicy"> <li *ngIf="showPrivacyPolicy">
<a class="text-white" <a class="btn text-white"
routerLink="info/privacy">{{ 'footer.link.privacy-policy' | translate}}</a> routerLink="info/privacy">{{ 'footer.link.privacy-policy' | translate}}</a>
</li> </li>
<li *ngIf="showEndUserAgreement"> <li *ngIf="showEndUserAgreement">
<a class="text-white" <a class="btn text-white"
routerLink="info/end-user-agreement">{{ 'footer.link.end-user-agreement' | translate}}</a> routerLink="info/end-user-agreement">{{ 'footer.link.end-user-agreement' | translate}}</a>
</li> </li>
<li *ngIf="showSendFeedback$ | async"> <li *ngIf="showSendFeedback$ | async">
<a class="text-white" <a class="btn text-white"
routerLink="info/feedback">{{ 'footer.link.feedback' | translate}}</a> routerLink="info/feedback">{{ 'footer.link.feedback' | translate}}</a>
</li> </li>
</ul> </ul>

View File

@@ -43,9 +43,19 @@
li { li {
display: inline-flex; display: inline-flex;
a { a, .btn-link {
padding: 0 calc(var(--bs-spacer) / 2); padding: 0 calc(var(--bs-spacer) / 2);
color: inherit 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) { &:not(:last-child) {

View File

@@ -1,16 +1,16 @@
<div *ngFor="let entry of healthInfoComponent | dsObjNgFor" data-test="collapse"> <div *ngFor="let entry of healthInfoComponent | dsObjNgFor" data-test="collapse">
<div *ngIf="entry && !isPlainProperty(entry.value)" class="mb-3 border-bottom"> <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" <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 }} {{ entry.key | titlecase }}
</button> </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-down"></span>
<span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span> <span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span>
</div> </div>
</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 border-0">
<div class="card-body"> <div class="card-body">
<ds-health-info-component [healthInfoComponent]="entry.value" <ds-health-info-component [healthInfoComponent]="entry.value"

View File

@@ -2,14 +2,14 @@
<ngb-accordion #acc="ngbAccordion" [activeIds]="activeId"> <ngb-accordion #acc="ngbAccordion" [activeIds]="activeId">
<ngb-panel [id]="entry.key" *ngFor="let entry of healthInfoResponse | dsObjNgFor"> <ngb-panel [id]="entry.key" *ngFor="let entry of healthInfoResponse | dsObjNgFor">
<ng-template ngbPanelHeader> <ng-template ngbPanelHeader>
<div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="info-component"> <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)" <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded(entry.key)"
aria-controls="collapsePanels"> [attr.aria-controls]="'health-info-' + entry.key + '-content'">
{{ getPanelLabel(entry.key) | titlecase }} {{ getPanelLabel(entry.key) | titlecase }}
</button> </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> <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-up fa-fw"></span>
<span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span> <span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span>
</div> </div>
@@ -17,8 +17,9 @@
</div> </div>
</ng-template> </ng-template>
<ng-template ngbPanelContent> <ng-template ngbPanelContent>
<ds-health-info-component [healthInfoComponentName]="entry.key" <ds-health-info-component [healthInfoComponentName]="entry.key" [healthInfoComponent]="entry.value"
[healthInfoComponent]="entry.value"></ds-health-info-component> [id]="'health-info-' + entry.key + '-content'">
</ds-health-info-component>
</ng-template> </ng-template>
</ngb-panel> </ngb-panel>
</ngb-accordion> </ngb-accordion>

View File

@@ -2,7 +2,7 @@
<h2>{{'health-page.heading' | translate}}</h2> <h2>{{'health-page.heading' | translate}}</h2>
<div *ngIf="(healthResponse | async) && (healthInfoResponse | async)"> <div *ngIf="(healthResponse | async) && (healthInfoResponse | async)">
<ul ngbNav #nav="ngbNav" [activeId]="'status'" class="nav-tabs"> <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> <a ngbNavLink>{{'health-page.status-tab' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div id="status"> <div id="status">
@@ -10,7 +10,7 @@
</div> </div>
</ng-template> </ng-template>
</li> </li>
<li [ngbNavItem]="'info'"> <li [ngbNavItem]="'info'" role="presentation">
<a ngbNavLink>{{'health-page.info-tab' | translate}}</a> <a ngbNavLink>{{'health-page.info-tab' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div id="info"> <div id="info">
@@ -21,7 +21,7 @@
</ul> </ul>
<div [ngbNavOutlet]="nav" class="mt-2"></div> <div [ngbNavOutlet]="nav" class="mt-2"></div>
</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> </div>

View File

@@ -5,6 +5,7 @@ import { take } from 'rxjs/operators';
import { HealthService } from './health.service'; import { HealthService } from './health.service';
import { HealthInfoResponse, HealthResponse } from './models/health-component.model'; import { HealthInfoResponse, HealthResponse } from './models/health-component.model';
import { AlertType } from '../shared/alert/alert-type';
@Component({ @Component({
selector: 'ds-health-page', selector: 'ds-health-page',
@@ -33,6 +34,8 @@ export class HealthPageComponent implements OnInit {
*/ */
healthInfoResponseInitialised: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); healthInfoResponseInitialised: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
readonly AlertType = AlertType;
constructor(private healthDataService: HealthService) { constructor(private healthDataService: HealthService) {
} }

View File

@@ -1,16 +1,16 @@
<ng-container *ngIf="healthComponent?.components"> <ng-container *ngIf="healthComponent?.components">
<div *ngFor="let entry of healthComponent?.components | dsObjNgFor" class="mb-3 border-bottom" data-test="collapse"> <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" <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 }} {{ entry.key | titlecase }}
</button> </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-down"></span>
<span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span> <span *ngIf="!collapse.collapsed" class="fas fa-chevron-up"></span>
</div> </div>
</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 border-0">
<div class="card-body"> <div class="card-body">
<ds-health-component [healthComponent]="entry.value" <ds-health-component [healthComponent]="entry.value"

View File

@@ -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-accordion #acc="ngbAccordion" [activeIds]="activeId">
<ngb-panel [id]="entry.key" *ngFor="let entry of healthResponse.components | dsObjNgFor"> <ngb-panel [id]="entry.key" *ngFor="let entry of healthResponse.components | dsObjNgFor">
<ng-template ngbPanelHeader> <ng-template ngbPanelHeader>
<div class="w-100 d-flex justify-content-between collapse-toggle" ngbPanelToggle (click)="acc.toggle(entry.key)" data-test="component"> <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)" <button type="button" class="btn btn-link p-0" (click)="$event.preventDefault()" [attr.aria-expanded]="acc.isExpanded(entry.key)"
aria-controls="collapsePanels"> [attr.aria-controls]="'health-panel-' + entry.key + '-content'">
{{ getPanelLabel(entry.key) | titlecase }} {{ getPanelLabel(entry.key) | titlecase }}
</button> </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> <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-up fa-fw"></span>
<span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span> <span *ngIf="!acc.isExpanded(entry.key)" class="fas fa-chevron-down fa-fw"></span>
</div> </div>
@@ -17,9 +20,9 @@
</div> </div>
</ng-template> </ng-template>
<ng-template ngbPanelContent> <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> </ng-template>
</ngb-panel> </ngb-panel>
</ngb-accordion> </ngb-accordion>

View File

@@ -1,12 +1,12 @@
<ng-container [ngSwitch]="status"> <ng-container [ngSwitch]="status">
<i *ngSwitchCase="HealthStatus.UP" <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> ngbTooltip="{{'health-page.status.ok.info' | translate}}" container="body" ></i>
<i *ngSwitchCase="HealthStatus.UP_WITH_ISSUES" <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> ngbTooltip="{{'health-page.status.warning.info' | translate}}" container="body"></i>
<i *ngSwitchCase="HealthStatus.DOWN" <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> ngbTooltip="{{'health-page.status.error.info' | translate}}" container="body"></i>
</ng-container> </ng-container>

View File

@@ -0,0 +1,3 @@
:host {
display: flex;
}

View File

@@ -1,7 +1,7 @@
<div class="row row-offcanvas row-offcanvas-right"> <div class="row row-offcanvas row-offcanvas-right">
<div class="col-xs-12 col-sm-12 col-md-9"> <div class="col-xs-12 col-sm-12 col-md-9">
<form class="primary" [formGroup]="feedbackForm" (ngSubmit)="createFeedback()"> <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> <p>{{ 'info.feedback.info' | translate }}</p>
<fieldset class="col p-0"> <fieldset class="col p-0">
<div class="row"> <div class="row">

View File

@@ -1,5 +1,5 @@
<div class="container"> <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"> <div *ngIf="canDownload$|async" class="alert alert-success">
<span>{{'bitstream-request-a-copy.alert.canDownload1' | translate}}</span> <span>{{'bitstream-request-a-copy.alert.canDownload1' | translate}}</span>
<a [routerLink]="getBitstreamLink()">{{'bitstream-request-a-copy.alert.canDownload2'| translate}}</a> <a [routerLink]="getBitstreamLink()">{{'bitstream-request-a-copy.alert.canDownload2'| translate}}</a>

View File

@@ -2,7 +2,7 @@
<ng-container *ngIf="bundles"> <ng-container *ngIf="bundles">
<div class="row"> <div class="row">
<div class="col-12 mb-2"> <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"> <ng-container *ngVar="(itemRD$ | async)?.payload as item">
<div *ngIf="item"> <div *ngIf="item">
<span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span> <span class="font-weight-bold">{{'item.bitstreams.upload.item' | translate}}</span>

View File

@@ -1,14 +1,16 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <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"> <div class="pt-2">
<ul class="nav nav-tabs justify-content-start" role="tablist"> <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)" <a *ngIf="(page.enabled | async)"
[attr.aria-selected]="page.page === currentPage"
class="nav-link" class="nav-link"
[ngClass]="{'active' : page.page === currentPage}" [ngClass]="{'active' : page.page === currentPage}"
[routerLink]="['./' + page.page]"> [routerLink]="['./' + page.page]"
role="tab">
{{'item.edit.tabs.' + page.page + '.head' | translate}} {{'item.edit.tabs.' + page.page + '.head' | translate}}
</a> </a>
<span [ngbTooltip]="'item.edit.tabs.disabled.tooltip' | translate"> <span [ngbTooltip]="'item.edit.tabs.disabled.tooltip' | translate">

View File

@@ -1,21 +1,25 @@
<div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles"> <div class="item-bitstreams" *ngVar="(bundles$ | async) as bundles">
<div class="button-row top d-flex mt-2 space-children-mr"> <div class="button-row top d-flex mt-2 space-children-mr">
<button class="mr-auto btn btn-success" <button class="mr-auto btn btn-success"
[attr.aria-label]="'item.edit.bitstreams.upload-button' | translate"
[routerLink]="[itemPageRoute, 'bitstreams', 'new']"><i [routerLink]="[itemPageRoute, 'bitstreams', 'new']"><i
class="fas fa-upload"></i> class="fas fa-upload"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.upload-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.upload-button" | translate}}</span>
</button> </button>
<button class="btn btn-warning" *ngIf="isReinstatable() | async" <button class="btn btn-warning" *ngIf="isReinstatable() | async"
[attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate"
(click)="reinstate()"><i (click)="reinstate()"><i
class="fas fa-undo-alt"></i> class="fas fa-undo-alt"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span>
</button> </button>
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting" <button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting"
[attr.aria-label]="'item.edit.bitstreams.save-button' | translate"
(click)="submit()"><i (click)="submit()"><i
class="fas fa-save"></i> class="fas fa-save"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span>
</button> </button>
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)" <button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
[attr.aria-label]="'item.edit.bitstreams.discard-button' | translate"
[disabled]="!(hasChanges() | async) || submitting" [disabled]="!(hasChanges() | async) || submitting"
(click)="discard()"><i (click)="discard()"><i
class="fas fa-times"></i> class="fas fa-times"></i>
@@ -49,16 +53,19 @@
<div class="button-row bottom"> <div class="button-row bottom">
<div class="mt-4 float-right space-children-mr ml-gap"> <div class="mt-4 float-right space-children-mr ml-gap">
<button class="btn btn-warning" *ngIf="isReinstatable() | async" <button class="btn btn-warning" *ngIf="isReinstatable() | async"
[attr.aria-label]="'item.edit.bitstreams.reinstate-button' | translate"
(click)="reinstate()"><i (click)="reinstate()"><i
class="fas fa-undo-alt"></i> class="fas fa-undo-alt"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.reinstate-button" | translate}}</span>
</button> </button>
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting" <button class="btn btn-primary" [disabled]="!(hasChanges() | async) || submitting"
[attr.aria-label]="'item.edit.bitstreams.save-button' | translate"
(click)="submit()"><i (click)="submit()"><i
class="fas fa-save"></i> class="fas fa-save"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.bitstreams.save-button" | translate}}</span>
</button> </button>
<button class="btn btn-danger" *ngIf="!(isReinstatable() | async)" <button class="btn btn-danger" *ngIf="!(isReinstatable() | async)"
[attr.aria-label]="'item.edit.bitstreams.discard-button' | translate"
[disabled]="!(hasChanges() | async) || submitting" [disabled]="!(hasChanges() | async) || submitting"
(click)="discard()"><i (click)="discard()"><i
class="fas fa-times"></i> class="fas fa-times"></i>

View File

@@ -10,6 +10,7 @@
<div class="btn-group bundle-action-buttons"> <div class="btn-group bundle-action-buttons">
<button [routerLink]="[itemPageRoute, 'bitstreams', 'new']" <button [routerLink]="[itemPageRoute, 'bitstreams', 'new']"
[queryParams]="{bundle: bundle.id}" [queryParams]="{bundle: bundle.id}"
[attr.aria-label]="'item.edit.bitstreams.bundle.edit.buttons.upload' | translate"
class="btn btn-outline-success btn-sm" class="btn btn-outline-success btn-sm"
title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}"> title="{{'item.edit.bitstreams.bundle.edit.buttons.upload' | translate}}">
<i class="fas fa-upload fa-fw"></i> <i class="fas fa-upload fa-fw"></i>

View File

@@ -26,21 +26,25 @@
<div class="text-center w-100"> <div class="text-center w-100">
<div class="btn-group relationship-action-buttons"> <div class="btn-group relationship-action-buttons">
<a *ngIf="bitstreamDownloadUrl != null" [routerLink]="bitstreamDownloadUrl" <a *ngIf="bitstreamDownloadUrl != null" [routerLink]="bitstreamDownloadUrl"
class="btn btn-outline-primary btn-sm" [attr.aria-label]="'item.edit.bitstreams.edit.buttons.download' | translate"
title="{{'item.edit.bitstreams.edit.buttons.download' | translate}}" class="btn btn-outline-primary btn-sm"
[attr.data-test]="'download-button' | dsBrowserOnly"> title="{{'item.edit.bitstreams.edit.buttons.download' | translate}}"
[attr.data-test]="'download-button' | dsBrowserOnly">
<i class="fas fa-download fa-fw"></i> <i class="fas fa-download fa-fw"></i>
</a> </a>
<button [routerLink]="['/bitstreams/', bitstream.id, 'edit']" class="btn btn-outline-primary btn-sm" <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}}"> title="{{'item.edit.bitstreams.edit.buttons.edit' | translate}}">
<i class="fas fa-edit fa-fw"></i> <i class="fas fa-edit fa-fw"></i>
</button> </button>
<button [disabled]="!canRemove()" (click)="remove()" <button [disabled]="!canRemove()" (click)="remove()"
[attr.aria-label]="'item.edit.bitstreams.edit.buttons.remove' | translate"
class="btn btn-outline-danger btn-sm" class="btn btn-outline-danger btn-sm"
title="{{'item.edit.bitstreams.edit.buttons.remove' | translate}}"> title="{{'item.edit.bitstreams.edit.buttons.remove' | translate}}">
<i class="fas fa-trash-alt fa-fw"></i> <i class="fas fa-trash-alt fa-fw"></i>
</button> </button>
<button [disabled]="!canUndo()" (click)="undo()" <button [disabled]="!canUndo()" (click)="undo()"
[attr.aria-label]="'item.edit.bitstreams.edit.buttons.undo' | translate"
class="btn btn-outline-warning btn-sm" class="btn btn-outline-warning btn-sm"
title="{{'item.edit.bitstreams.edit.buttons.undo' | translate}}"> title="{{'item.edit.bitstreams.edit.buttons.undo' | translate}}">
<i class="fas fa-undo-alt fa-fw"></i> <i class="fas fa-undo-alt fa-fw"></i>

View File

@@ -6,7 +6,7 @@
<p>{{'item.edit.item-mapper.description' | translate}}</p> <p>{{'item.edit.item-mapper.description' | translate}}</p>
<ul ngbNav (navChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbNav" class="nav-tabs"> <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> <a ngbNavLink>{{'item.edit.item-mapper.tabs.browse' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="mt-2"> <div class="mt-2">
@@ -22,7 +22,7 @@
</div> </div>
</ng-template> </ng-template>
</li> </li>
<li [ngbNavItem]="'mapTab'"> <li [ngbNavItem]="'mapTab'" role="presentation">
<a ngbNavLink>{{'item.edit.item-mapper.tabs.map' | translate}}</a> <a ngbNavLink>{{'item.edit.item-mapper.tabs.map' | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row mt-2"> <div class="row mt-2">

View File

@@ -1,5 +1,5 @@
<div class="container mt-3"> <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 <ds-curation-form
*ngIf="dsoRD$ | async as dsoRD" *ngIf="dsoRD$ | async as dsoRD"
[dsoHandle]="dsoRD?.payload.handle" [dsoHandle]="dsoRD?.payload.handle"

View File

@@ -2,7 +2,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<h2>{{headerMessage | translate: {id: item.handle} }}</h2> <h1>{{headerMessage | translate: {id: item.handle} }}</h1>
<p>{{descriptionMessage | translate}}</p> <p>{{descriptionMessage | translate}}</p>
<ds-modify-item-overview [item]="item"></ds-modify-item-overview> <ds-modify-item-overview [item]="item"></ds-modify-item-overview>

View File

@@ -171,7 +171,7 @@ describe('ItemDeleteComponent', () => {
}); });
it('should render a page with messages based on the \'delete\' messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.delete.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;
expect(description.innerHTML).toContain('item.edit.delete.description'); expect(description.innerHTML).toContain('item.edit.delete.description');

View File

@@ -1,7 +1,7 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <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> <p>{{'item.edit.move.description' | translate}}</p>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">

View File

@@ -80,7 +80,7 @@ describe('ItemPrivateComponent', () => {
}); });
it('should render a page with messages based on the \'private\' messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.private.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;
expect(description.innerHTML).toContain('item.edit.private.description'); expect(description.innerHTML).toContain('item.edit.private.description');

View File

@@ -74,7 +74,7 @@ describe('ItemPublicComponent', () => {
}); });
it('should render a page with messages based on the \'public\' messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.public.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;
expect(description.innerHTML).toContain('item.edit.public.description'); expect(description.innerHTML).toContain('item.edit.public.description');

View File

@@ -76,7 +76,7 @@ describe('ItemReinstateComponent', () => {
}); });
it('should render a page with messages based on the \'reinstate\' messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.reinstate.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;
expect(description.innerHTML).toContain('item.edit.reinstate.description'); expect(description.innerHTML).toContain('item.edit.reinstate.description');

View File

@@ -1,10 +1,10 @@
<h5> <h2 class="h4">
{{getRelationshipMessageKey() | async | translate}} {{getRelationshipMessageKey() | async | translate}}
<button class="ml-2 btn btn-success" [disabled]="(hasChanges | async)" (click)="openLookup()"> <button class="ml-2 btn btn-success" [disabled]="(hasChanges | async)" (click)="openLookup()">
<i class="fas fa-plus"></i> <i class="fas fa-plus"></i>
<span class="d-none d-sm-inline">&nbsp;{{"item.edit.relationships.edit.buttons.add" | translate}}</span> <span class="d-none d-sm-inline">&nbsp;{{"item.edit.relationships.edit.buttons.add" | translate}}</span>
</button> </button>
</h5> </h2>
<ng-container *ngVar="updates$ | async as updates"> <ng-container *ngVar="updates$ | async as updates">
<ng-container *ngIf="updates && !(loading$ | async)"> <ng-container *ngIf="updates && !(loading$ | async)">
<ng-container *ngVar="updates | dsObjectValues as updateValues"> <ng-container *ngVar="updates | dsObjectValues as updateValues">

View File

@@ -74,7 +74,7 @@ describe('ItemWithdrawComponent', () => {
}); });
it('should render a page with messages based on the \'withdraw\' messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.withdraw.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;
expect(description.innerHTML).toContain('item.edit.withdraw.description'); expect(description.innerHTML).toContain('item.edit.withdraw.description');

View File

@@ -1,7 +1,7 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<h2>{{headerMessage | translate: {id: item.handle} }}</h2> <h1>{{headerMessage | translate: {id: item.handle} }}</h1>
<p>{{descriptionMessage | translate}}</p> <p>{{descriptionMessage | translate}}</p>
<ds-modify-item-overview [item]="item"></ds-modify-item-overview> <ds-modify-item-overview [item]="item"></ds-modify-item-overview>
<div class="space-children-mr"> <div class="space-children-mr">

View File

@@ -111,7 +111,7 @@ describe('AbstractSimpleItemActionComponent', () => {
}); });
it('should render a page with messages based on the provided messageKey', () => { 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'); expect(header.innerHTML).toContain('item.edit.myEditAction.header');
const description = fixture.debugElement.query(By.css('p')).nativeElement; const description = fixture.debugElement.query(By.css('p')).nativeElement;

View File

@@ -1,7 +1,7 @@
<ds-metadata-field-wrapper [label]="label | translate"> <ds-metadata-field-wrapper [label]="label | translate">
<div *ngVar="(originals$ | async)?.payload as originals"> <div *ngVar="(originals$ | async)?.payload as originals">
<div *ngIf="hasValuesInBundle(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" <ds-pagination *ngIf="originals?.page?.length > 0"
[hideGear]="true" [hideGear]="true"
[hidePagerWhenSinglePage]="true" [hidePagerWhenSinglePage]="true"
@@ -44,7 +44,7 @@
</div> </div>
<div *ngVar="(licenses$ | async)?.payload as licenses"> <div *ngVar="(licenses$ | async)?.payload as licenses">
<div *ngIf="hasValuesInBundle(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" <ds-pagination *ngIf="licenses?.page?.length > 0"
[hideGear]="true" [hideGear]="true"
[hidePagerWhenSinglePage]="true" [hidePagerWhenSinglePage]="true"

View File

@@ -1,5 +1,5 @@
<div class="container mb-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> <ng-container *ngIf="(isLinkedToOrcid() | async); then orcidLinked; else orcidNotLinked"></ng-container>
</div> </div>

View File

@@ -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> <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"> <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> <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-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> <ds-orcid-queue *ngIf="isLinkedToOrcid()" [item]="(item | async)"></ds-orcid-queue>
</ng-container> </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>

View File

@@ -1,6 +1,6 @@
<ng-container *ngIf="relationTypes.length > 1"> <ng-container *ngIf="relationTypes.length > 1">
<ul ngbNav #tabs="ngbNav" [destroyOnHide]="true" [activeId]="activeTab$ | async" (navChange)="onTabChange($event)" class="nav-tabs"> <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> <a ngbNavLink>{{'item.page.relationships.' + relationType.label | translate}}</a>
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="mt-4"> <div class="mt-4">

View File

@@ -1,7 +1,7 @@
<div *ngVar="(versionsRD$ | async)?.payload as versions"> <div *ngVar="(versionsRD$ | async)?.payload as versions">
<div *ngVar="(versionRD$ | async)?.payload as itemVersion"> <div *ngVar="(versionRD$ | async)?.payload as itemVersion">
<div class="mb-2" *ngIf="versions?.page?.length > 0 || displayWhenEmpty"> <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"> <ds-alert [type]="AlertTypeEnum.Info" *ngIf="itemVersion">
{{ "item.version.history.selected.alert" | translate : {version: itemVersion.version} }} {{ "item.version.history.selected.alert" | translate : {version: itemVersion.version} }}
</ds-alert> </ds-alert>
@@ -98,8 +98,9 @@
<ng-container *ngIf="isThisBeingEdited(version); then editSummary else showSummary"></ng-container> <ng-container *ngIf="isThisBeingEdited(version); then editSummary else showSummary"></ng-container>
<ng-template #showSummary>{{version?.summary}}</ng-template> <ng-template #showSummary>{{version?.summary}}</ng-template>
<ng-template #editSummary> <ng-template #editSummary>
<input class="form-control" type="text" [(ngModel)]="versionBeingEditedSummary" <input [attr.aria-label]="'item.version.history.table.action.editSummary' | translate"
(keyup.enter)="onSummarySubmit()"/> [(ngModel)]="versionBeingEditedSummary" (keyup.enter)="onSummarySubmit()"
class="form-control" type="text"/>
</ng-template> </ng-template>
</div> </div>

View File

@@ -556,13 +556,17 @@ export class MenuResolver implements Resolve<boolean> {
* Create menu sections dependent on whether or not the current user is a site administrator * Create menu sections dependent on whether or not the current user is a site administrator
*/ */
createSiteAdministratorMenuSections() { createSiteAdministratorMenuSections() {
this.authorizationService.isAuthorized(FeatureID.AdministratorOf).subscribe((authorized) => { combineLatest([
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
this.authorizationService.isAuthorized(FeatureID.CanSeeQA)
])
.subscribe(([authorized, canSeeQA]) => {
const menuList = [ const menuList = [
/* Notifications */ /* Notifications */
{ {
id: 'notifications', id: 'notifications',
active: false, active: false,
visible: authorized, visible: authorized && canSeeQA,
model: { model: {
type: MenuItemType.TEXT, type: MenuItemType.TEXT,
text: 'menu.section.notifications' text: 'menu.section.notifications'

View File

@@ -1,5 +1,6 @@
<div class="add" *ngIf="!(moreThanOne$ | async)"> <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" (click)="openPage(singleEntity)" role="button"
title="{{'mydspace.new-submission-external' | translate}}"> title="{{'mydspace.new-submission-external' | translate}}">
<i class="fa fa-file-import" aria-hidden="true"></i> <i class="fa fa-file-import" aria-hidden="true"></i>
@@ -10,7 +11,7 @@
*ngIf="(moreThanOne$ | async)"> *ngIf="(moreThanOne$ | async)">
<button class="btn btn-lg btn-outline-primary mt-1 ml-2" id="dropdownImport" ngbDropdownToggle <button class="btn btn-lg btn-outline-primary mt-1 ml-2" id="dropdownImport" ngbDropdownToggle
type="button" [disabled]="!(initialized$|async)" 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" [attr.data-test]="'import-dropdown' | dsBrowserOnly"
title="{{'mydspace.new-submission-external' | translate}}"> title="{{'mydspace.new-submission-external' | translate}}">
<i class="fa fa-file-import" aria-hidden="true"></i> <i class="fa fa-file-import" aria-hidden="true"></i>

View File

@@ -1,5 +1,6 @@
<div class="add" *ngIf="!(moreThanOne$ | async)"> <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> <i class="fa fa-plus-circle" aria-hidden="true"></i>
</button> </button>
</div> </div>
@@ -8,7 +9,7 @@
*ngIf="(moreThanOne$ | async)"> *ngIf="(moreThanOne$ | async)">
<button class="btn btn-lg btn-primary mt-1 ml-2" id="dropdownSubmission" ngbDropdownToggle <button class="btn btn-lg btn-primary mt-1 ml-2" id="dropdownSubmission" ngbDropdownToggle
type="button" [disabled]="!(initialized$|async)" 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" [attr.data-test]="'submission-dropdown' | dsBrowserOnly"
title="{{'mydspace.new-submission' | translate}}"> title="{{'mydspace.new-submission' | translate}}">
<i class="fa fa-plus-circle" aria-hidden="true"></i> <i class="fa fa-plus-circle" aria-hidden="true"></i>

View File

@@ -5,13 +5,13 @@
(keydown.space)="$event.preventDefault()" (keydown.space)="$event.preventDefault()"
(mouseenter)="activateSection($event)" (mouseenter)="activateSection($event)"
(mouseleave)="deactivateSection($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" [class.disabled]="section.model?.disabled"
id="browseDropdown" (click)="toggleSection($event)" (click)="toggleSection($event)"
data-toggle="dropdown"> data-toggle="dropdown">
<ng-container <ng-container
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></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)" <ul @slide *ngIf="(active | async)" (click)="deactivateSection($event)"
class="m-0 shadow-none border-top-0 dropdown-menu show"> class="m-0 shadow-none border-top-0 dropdown-menu show">
<li *ngFor="let subSection of (subSections$ | async)"> <li *ngFor="let subSection of (subSections$ | async)">

View File

@@ -5,6 +5,15 @@
justify-content: center; justify-content: center;
} }
.btn.nav-link {
text-align: left;
border: none;
&:active, &:focus {
box-shadow: none !important;
}
}
.dropdown-menu { .dropdown-menu {
background-color: var(--ds-expandable-navbar-bg); background-color: var(--ds-expandable-navbar-bg);
overflow: hidden; overflow: hidden;

View File

@@ -152,7 +152,7 @@ describe('ExpandableNavbarSectionComponent', () => {
describe('when a click occurs on the section header', () => { describe('when a click occurs on the section header', () => {
beforeEach(() => { beforeEach(() => {
spyOn(menuService, 'toggleActiveSection'); 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', { sidebarToggler.triggerEventHandler('click', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }
@@ -195,7 +195,7 @@ describe('ExpandableNavbarSectionComponent', () => {
describe('when the mouse enters the section header', () => { describe('when the mouse enters the section header', () => {
beforeEach(() => { beforeEach(() => {
spyOn(menuService, 'activateSection'); 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', { sidebarToggler.triggerEventHandler('mouseenter', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }
@@ -210,7 +210,7 @@ describe('ExpandableNavbarSectionComponent', () => {
describe('when the mouse leaves the section header', () => { describe('when the mouse leaves the section header', () => {
beforeEach(() => { beforeEach(() => {
spyOn(menuService, 'deactivateSection'); 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', { sidebarToggler.triggerEventHandler('mouseleave', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }
@@ -225,7 +225,7 @@ describe('ExpandableNavbarSectionComponent', () => {
describe('when a click occurs on the section header link', () => { describe('when a click occurs on the section header link', () => {
beforeEach(() => { beforeEach(() => {
spyOn(menuService, 'toggleActiveSection'); 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', { sidebarToggler.triggerEventHandler('click', {
preventDefault: () => {/**/ preventDefault: () => {/**/
} }

View File

@@ -37,8 +37,8 @@ nav.navbar {
} }
} }
.navbar-nav { .navbar-nav ::ng-deep {
::ng-deep a.nav-link { a.nav-link, .btn.nav-link {
color: var(--ds-navbar-link-color); color: var(--ds-navbar-link-color);
&:hover, &:focus { &:hover, &:focus {

View File

@@ -2,7 +2,7 @@ import { QualityAssuranceSourceEffects } from './qa/source/quality-assurance-sou
import { QualityAssuranceTopicsEffects } from './qa/topics/quality-assurance-topics.effects'; import { QualityAssuranceTopicsEffects } from './qa/topics/quality-assurance-topics.effects';
import {SuggestionTargetsEffects} from './reciter-suggestions/suggestion-targets/suggestion-targets.effects'; import {SuggestionTargetsEffects} from './reciter-suggestions/suggestion-targets/suggestion-targets.effects';
export const suggestionNotificationsEffects = [ export const notificationsEffects = [
QualityAssuranceTopicsEffects, QualityAssuranceTopicsEffects,
QualityAssuranceSourceEffects, QualityAssuranceSourceEffects,
SuggestionTargetsEffects SuggestionTargetsEffects

Some files were not shown because too many files have changed in this diff Show More