mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
CST-12180
This commit is contained in:
@@ -1,34 +1,34 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
import {RouterModule} from '@angular/router';
|
||||||
import { I18nBreadcrumbResolver } from 'src/app/core/breadcrumbs/i18n-breadcrumb.resolver';
|
import {I18nBreadcrumbResolver} from 'src/app/core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
|
import {LdnServicesOverviewComponent} from './ldn-services-directory/ldn-services-directory.component';
|
||||||
import { LdnServiceNewComponent } from './ldn-service-new/ldn-service-new.component';
|
import {LdnServiceNewComponent} from './ldn-service-new/ldn-service-new.component';
|
||||||
import { LdnServiceFormEditComponent } from './ldn-service-form-edit/ldn-service-form-edit.component';
|
import {LdnServiceFormEditComponent} from './ldn-service-form-edit/ldn-service-form-edit.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
component: LdnServicesOverviewComponent,
|
component: LdnServicesOverviewComponent,
|
||||||
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
||||||
data: {title: 'ldn-registered-services.title', breadcrumbKey: 'ldn-registered-services.new'},
|
data: {title: 'ldn-registered-services.title', breadcrumbKey: 'ldn-registered-services.new'},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'new',
|
path: 'new',
|
||||||
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
||||||
component: LdnServiceNewComponent,
|
component: LdnServiceNewComponent,
|
||||||
data: {title: 'ldn-register-new-service.title', breadcrumbKey: 'ldn-register-new-service'}
|
data: {title: 'ldn-register-new-service.title', breadcrumbKey: 'ldn-register-new-service'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'edit/:serviceId',
|
path: 'edit/:serviceId',
|
||||||
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
resolve: {breadcrumb: I18nBreadcrumbResolver},
|
||||||
component: LdnServiceFormEditComponent,
|
component: LdnServiceFormEditComponent,
|
||||||
data: {title: 'ldn-edit-service.title', breadcrumbKey: 'ldn-edit-service'}
|
data: {title: 'ldn-edit-service.title', breadcrumbKey: 'ldn-edit-service'}
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AdminLdnServicesRoutingModule {
|
export class AdminLdnServicesRoutingModule {
|
||||||
|
|
||||||
|
@@ -1,29 +1,29 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import { AdminLdnServicesRoutingModule } from './admin-ldn-services-routing.module';
|
import {AdminLdnServicesRoutingModule} from './admin-ldn-services-routing.module';
|
||||||
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
|
import {LdnServicesOverviewComponent} from './ldn-services-directory/ldn-services-directory.component';
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import {SharedModule} from '../../shared/shared.module';
|
||||||
import { LdnServiceNewComponent } from './ldn-service-new/ldn-service-new.component';
|
import {LdnServiceNewComponent} from './ldn-service-new/ldn-service-new.component';
|
||||||
import { LdnServiceFormComponent } from './ldn-service-form/ldn-service-form.component';
|
import {LdnServiceFormComponent} from './ldn-service-form/ldn-service-form.component';
|
||||||
import { LdnServiceFormEditComponent } from './ldn-service-form-edit/ldn-service-form-edit.component';
|
import {LdnServiceFormEditComponent} from './ldn-service-form-edit/ldn-service-form-edit.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
import { LdnItemfiltersService } from './ldn-services-data/ldn-itemfilters-data.service';
|
import {LdnItemfiltersService} from './ldn-services-data/ldn-itemfilters-data.service';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
AdminLdnServicesRoutingModule,
|
AdminLdnServicesRoutingModule,
|
||||||
FormsModule
|
FormsModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
LdnServicesOverviewComponent,
|
LdnServicesOverviewComponent,
|
||||||
LdnServiceNewComponent,
|
LdnServiceNewComponent,
|
||||||
LdnServiceFormComponent,
|
LdnServiceFormComponent,
|
||||||
LdnServiceFormEditComponent,
|
LdnServiceFormEditComponent,
|
||||||
],
|
],
|
||||||
providers: [LdnItemfiltersService]
|
providers: [LdnItemfiltersService]
|
||||||
})
|
})
|
||||||
export class AdminLdnServicesModule {
|
export class AdminLdnServicesModule {
|
||||||
}
|
}
|
||||||
|
@@ -1,281 +1,412 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<form (ngSubmit)="onSubmit()" [formGroup]="formModel">
|
<form (ngSubmit)="onSubmit()" [formGroup]="formModel">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<h2 class="flex-grow-1">{{ 'ldn-edit-registered-service.title' | translate }}</h2>
|
<h2 class="flex-grow-1">{{ 'ldn-edit-registered-service.title' | translate }}</h2>
|
||||||
|
</div>
|
||||||
|
<!-- In the toggle section -->
|
||||||
|
<div class="toggle-switch-container">
|
||||||
|
<label class="status-label font-weight-bold" for="enabled">{{ 'ldn-service-status' | translate }}</label>
|
||||||
|
<div>
|
||||||
|
<input formControlName="enabled" hidden id="enabled" name="enabled" type="checkbox">
|
||||||
|
<div (click)="toggleEnabled()" [class.checked]="formModel.get('enabled').value" class="toggle-switch">
|
||||||
|
<div class="slider"></div>
|
||||||
</div>
|
</div>
|
||||||
<!-- In the toggle section -->
|
</div>
|
||||||
<div class="toggle-switch-container">
|
</div>
|
||||||
<label class="status-label" for="enabled">{{ 'ldn-service-status' | translate }}</label>
|
<!-- In the Name section -->
|
||||||
<div>
|
<div class="mb-5">
|
||||||
<input formControlName="enabled" hidden id="enabled" name="enabled" type="checkbox">
|
<label for="name" class="font-weight-bold">{{ 'ldn-new-service.form.label.name' | translate }}</label>
|
||||||
<div (click)="toggleEnabled()" [class.checked]="formModel.get('enabled').value" class="toggle-switch">
|
<input [class.invalid-field]="formModel.get('name').invalid && formModel.get('name').touched"
|
||||||
<div class="slider"></div>
|
[placeholder]="'ldn-new-service.form.placeholder.name' | translate" class="form-control"
|
||||||
|
formControlName="name"
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('name').invalid && formModel.get('name').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.name' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the description section -->
|
||||||
|
<div class="mb-5 mt-5 d-flex flex-column">
|
||||||
|
<label for="description" class="font-weight-bold">{{ 'ldn-new-service.form.label.description' | translate }}</label>
|
||||||
|
<textarea [placeholder]="'ldn-new-service.form.placeholder.description' | translate"
|
||||||
|
class="form-control" formControlName="description" id="description" name="description"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the url section -->
|
||||||
|
<div class="mb-5 mt-5">
|
||||||
|
<label for="url" class="font-weight-bold">{{ 'ldn-new-service.form.label.url' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('url').invalid && formModel.get('url').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.url' | translate" class="form-control"
|
||||||
|
formControlName="url"
|
||||||
|
id="url"
|
||||||
|
name="url"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('url').invalid && formModel.get('url').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.url' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the ldnUrl section -->
|
||||||
|
<div class="mb-5 mt-5">
|
||||||
|
<label for="ldnUrl" class="font-weight-bold">{{ 'ldn-new-service.form.label.ldnUrl' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.ldnUrl' | translate" class="form-control"
|
||||||
|
formControlName="ldnUrl"
|
||||||
|
id="ldnUrl"
|
||||||
|
name="ldnUrl"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.ldnurl' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the score section -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="score" class="font-weight-bold">{{ 'ldn-new-service.form.label.score' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('score').invalid && formModel.get('score').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.score' | translate" formControlName="score"
|
||||||
|
id="score"
|
||||||
|
name="score"
|
||||||
|
class="form-control"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('score').invalid && formModel.get('score').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.score' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the Inbound Patterns Labels section -->
|
||||||
|
<div class="row mb-1 mt-5">
|
||||||
|
<div class="col">
|
||||||
|
<label class="font-weight-bold">{{ 'ldn-new-service.form.label.inboundPattern' | translate }} </label>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="!!(formModel.get('notifyServiceInboundPatterns')['controls'][0]?.value?.pattern)">
|
||||||
|
<div class="col">
|
||||||
|
<label class="font-weight-bold">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<label class="font-weight-bold">{{ 'ldn-new-service.form.label.automatic' | translate }}</label>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the Inbound Patterns section -->
|
||||||
|
<div *ngFor="let patternGroup of formModel.get('notifyServiceInboundPatterns')['controls']; let i = index"
|
||||||
|
[class.marked-for-deletion]="markedForDeletionInboundPattern.includes(i)"
|
||||||
|
formGroupName="notifyServiceInboundPatterns">
|
||||||
|
|
||||||
|
<ng-container [formGroupName]="i">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row mb-1">
|
||||||
|
<div class="col">
|
||||||
|
<div #inboundPatternDropdown="ngbDropdown" class="w-80" display="dynamic"
|
||||||
|
id="additionalInboundPattern{{i}}"
|
||||||
|
ngbDropdown placement="bottom-start">
|
||||||
|
<div class="position-relative right-addon" role="combobox">
|
||||||
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
ngbDropdownToggle></i>
|
||||||
|
<input
|
||||||
|
(click)="inboundPatternDropdown.open();"
|
||||||
|
[readonly]="true"
|
||||||
|
class="form-control w-80 scrollable-dropdown-input"
|
||||||
|
formControlName="patternLabel"
|
||||||
|
id="inboundPatternDropdownButton"
|
||||||
|
ngbDropdownAnchor
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
<div aria-labelledby="inboundPatternDropdownButton"
|
||||||
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
|
ngbDropdownMenu>
|
||||||
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectInboundPattern(pattern, i); $event.stopPropagation()"
|
||||||
|
*ngFor="let pattern of inboundPatterns; let internalIndex = index"
|
||||||
|
[title]="'ldn-service.form.pattern.' + pattern + '.description' | translate"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
ngbDropdownItem
|
||||||
|
type="button">
|
||||||
|
<div>{{ 'ldn-service.form.pattern.' + pattern + '.label' | translate }}</div>
|
||||||
|
<div
|
||||||
|
class="small-text">{{ 'ldn-service.form.pattern.' + pattern + '.description' | translate }}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="col">
|
||||||
<label for="name">{{ 'ldn-new-service.form.label.name' | translate }}</label>
|
<ng-container
|
||||||
<input [class.invalid-field]="formModel.get('name').invalid && formModel.get('name').touched"
|
*ngIf="!!(formModel.get('notifyServiceInboundPatterns')['controls'][i].value.pattern)">
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.name' | translate" formControlName="name" id="name"
|
<div #inboundItemfilterDropdown="ngbDropdown" class="w-100" id="constraint{{i}}" ngbDropdown
|
||||||
name="name"
|
placement="bottom-start">
|
||||||
type="text">
|
<div class="position-relative right-addon" role="combobox">
|
||||||
</div>
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
ngbDropdownToggle></i>
|
||||||
<div class="mb-4">
|
<input
|
||||||
|
(click)="inboundItemfilterDropdown.open();"
|
||||||
</div>
|
[readonly]="true"
|
||||||
|
[value]="selectedInboundItemfilters"
|
||||||
<!-- In the description section -->
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
<div class="mb-2 d-flex flex-column">
|
formControlName="constraint"
|
||||||
<label for="description">{{ 'ldn-new-service.form.label.description' | translate }}</label>
|
id="inboundItemfilterDropdown"
|
||||||
<textarea [placeholder]="'ldn-new-service.form.placeholder.description' | translate"
|
ngbDropdownAnchor
|
||||||
formControlName="description" id="description" name="description"></textarea>
|
type="text"
|
||||||
</div>
|
/>
|
||||||
|
<div aria-labelledby="inboundItemfilterDropdownButton"
|
||||||
<div class="mb-4">
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
|
ngbDropdownMenu>
|
||||||
</div>
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectInboundItemFilter(constraint.id, i); $event.stopPropagation()"
|
||||||
<!-- In the url section -->
|
*ngFor="let constraint of (itemfiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||||
<div class="mb-2">
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
<label for="url">{{ 'ldn-new-service.form.label.url' | translate }}</label>
|
ngbDropdownItem
|
||||||
<input [class.invalid-field]="formModel.get('url').invalid && formModel.get('url').touched"
|
type="button">
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.url' | translate" formControlName="url" id="url"
|
<div>{{ constraint.id }}</div>
|
||||||
name="url"
|
</button>
|
||||||
type="text">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In the ldnUrl section -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="ldnUrl">{{ 'ldn-new-service.form.label.ldnUrl' | translate }}</label>
|
|
||||||
<input [class.invalid-field]="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched"
|
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.ldnUrl' | translate" formControlName="ldnUrl"
|
|
||||||
id="ldnUrl"
|
|
||||||
name="ldnUrl"
|
|
||||||
type="text">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<label>{{ 'ldn-new-service.form.label.inboundPattern' | translate }} </label>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<label class="label-box">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm1 ">
|
|
||||||
<label class="label-box-2">{{ 'ldn-new-service.form.label.automatic' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngFor="let patternGroup of formModel.get('notifyServiceInboundPatterns')['controls']; let i = index"
|
|
||||||
formGroupName="notifyServiceInboundPatterns">
|
|
||||||
|
|
||||||
<ng-container [formGroupName]="i">
|
|
||||||
|
|
||||||
|
|
||||||
<div [class.marked-for-deletion]="markedForDeletionInboundPattern.includes(i)" class="row mb-1">
|
|
||||||
<div class="col">
|
|
||||||
<select #inboundPattern formControlName="pattern" id="additionalInboundPattern{{i}}"
|
|
||||||
name="additionalInboundPattern{{i}}" required>
|
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.inboundPattern' | translate }}</option>
|
|
||||||
<option *ngFor="let pattern of inboundPatterns"
|
|
||||||
[ngValue]="pattern.name">{{ pattern.name }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<ng-container *ngIf="inboundPattern.value">
|
|
||||||
<select formControlName="constraint" id="constraint{{i}}" name="constraint{{i}}">
|
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.selectedItemFilter' | translate }}</option>
|
|
||||||
<option *ngFor="let itemFilter of (itemfiltersRD$ | async)?.payload?.page"
|
|
||||||
[value]="itemFilter.id">{{ itemFilter.id }}</option>
|
|
||||||
</select>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div [style.visibility]="inboundPattern.value ? 'visible' : 'hidden'" class="col-sm1">
|
|
||||||
<input formControlName="automatic" hidden id="automatic{{i}}" name="automatic{{i}}"
|
|
||||||
type="checkbox">
|
|
||||||
<div (click)="toggleAutomatic(i)"
|
|
||||||
[class.checked]="formModel.get('notifyServiceInboundPatterns.' + i + '.automatic').value"
|
|
||||||
class="toggle-switch">
|
|
||||||
<div class="slider"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-sm-1 btn-group">
|
|
||||||
<button (click)="markForInboundPatternDeletion(i)" class="btn btn-outline-dark trash-button" type="button">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
<button (click)="unmarkForInboundPatternDeletion(i)" *ngIf="markedForDeletionInboundPattern.includes(i)" class="btn btn-outline-dark undo-button"
|
|
||||||
type="button">
|
|
||||||
<i class="fas fa-undo"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
[style.visibility]="formModel.get('notifyServiceInboundPatterns')['controls'][i].value.pattern ? 'visible' : 'hidden'"
|
||||||
|
class="col-sm-1">
|
||||||
|
<input formControlName="automatic" hidden id="automatic{{i}}" name="automatic{{i}}"
|
||||||
|
type="checkbox">
|
||||||
|
<div (click)="toggleAutomatic(i)"
|
||||||
|
[class.checked]="formModel.get('notifyServiceInboundPatterns.' + i + '.automatic').value"
|
||||||
|
class="toggle-switch">
|
||||||
|
<div class="slider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button (click)="markForInboundPatternDeletion(i)" class="btn btn-outline-dark trash-button"
|
||||||
|
type="button">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button (click)="unmarkForInboundPatternDeletion(i)"
|
||||||
|
*ngIf="markedForDeletionInboundPattern.includes(i)"
|
||||||
|
class="btn btn-warning "
|
||||||
|
type="button">
|
||||||
|
<i class="fas fa-undo"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<span (click)="addInboundPattern()"
|
<span (click)="addInboundPattern()"
|
||||||
class="add-pattern-link mb-2">{{ 'ldn-new-service.form.label.addPattern' | translate }}</span>
|
class="add-pattern-link mb-2">{{ 'ldn-new-service.form.label.addPattern' | translate }}</span>
|
||||||
|
|
||||||
<div class="mb-4">
|
<!-- In the Outbound Patterns Labels section -->
|
||||||
|
<div class="row mb-1 mt-5">
|
||||||
|
<div class="col">
|
||||||
|
<label class="font-weight-bold">{{ 'ldn-new-service.form.label.outboundPattern' | translate }} </label>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="!!(formModel.get('notifyServiceOutboundPatterns')['controls'][0]?.value?.pattern)">
|
||||||
|
<div class="col">
|
||||||
|
<label class="font-weight-bold">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="col-sm-1 ">
|
||||||
|
<label class="label-box-2" style="visibility: hidden;">
|
||||||
|
{{ 'ldn-new-service.form.label.automatic' | translate }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 ">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<!-- In the Outbound Patterns section -->
|
||||||
<div class="col">
|
<div *ngFor="let patternGroup of formModel.get('notifyServiceOutboundPatterns')['controls']; let i = index"
|
||||||
<label>{{ 'ldn-new-service.form.label.outboundPattern' | translate }}</label>
|
[class.marked-for-deletion]="markedForDeletionOutboundPattern.includes(i)"
|
||||||
</div>
|
formGroupName="notifyServiceOutboundPatterns">
|
||||||
<div class="col">
|
|
||||||
<label class="label-box-3">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1 ">
|
|
||||||
<label class="label-box-2"></label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1 ">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngFor="let patternGroup of formModel.get('notifyServiceOutboundPatterns')['controls']; let i = index"
|
<ng-container [formGroupName]="i">
|
||||||
formGroupName="notifyServiceOutboundPatterns">
|
|
||||||
|
|
||||||
<ng-container [formGroupName]="i">
|
<div class="row mb-1">
|
||||||
|
<div class="col">
|
||||||
<!-- Input elements in a separate row -->
|
<div #outboundPatternDropdown="ngbDropdown" class="w-100" id="additionalOutboundPattern{{i}}"
|
||||||
<div [class.marked-for-deletion]="markedForDeletionOutboundPattern.includes(i)" class="row mb-1">
|
ngbDropdown
|
||||||
<div class="col">
|
placement="bottom-start">
|
||||||
<select #outboundPattern formControlName="pattern" id="additionalOutboundPattern{{i}}"
|
<div class="position-relative right-addon" role="combobox">
|
||||||
name="additionalOutboundPattern{{i}}"
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
required>
|
ngbDropdownToggle></i>
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.outboundPattern' | translate }}</option>
|
<input
|
||||||
<option *ngFor="let pattern of outboundPatterns"
|
(click)="outboundPatternDropdown.open();"
|
||||||
[ngValue]="pattern.name">{{ pattern.name }}</option>
|
[readonly]="true"
|
||||||
</select>
|
[value]="selectedOutboundPatterns"
|
||||||
</div>
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
<div class="col">
|
formControlName="patternLabel"
|
||||||
<ng-container *ngIf="outboundPattern.value">
|
id="outboundPatternDropdownButton"
|
||||||
<select formControlName="constraint" id="constraint{{i}}" name="constraint{{i}}">
|
ngbDropdownAnchor
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.selectedItemFilter' | translate }}</option>
|
type="text"
|
||||||
<option *ngFor="let itemFilter of (itemfiltersRD$ | async)?.payload?.page"
|
/>
|
||||||
[value]="itemFilter.id">{{ itemFilter.id }}</option>
|
<div aria-labelledby="outboundPatternDropdownButton"
|
||||||
</select>
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
</ng-container>
|
ngbDropdownMenu>
|
||||||
</div>
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectOutboundPattern(pattern, i); $event.stopPropagation()"
|
||||||
<div [style.visibility]="'hidden'" class="col-sm1">
|
*ngFor="let pattern of outboundPatterns; let internalIndex = index"
|
||||||
<input hidden id="automatic{{i}}" name="automatic{{i}}" type="checkbox">
|
[title]="'ldn-service.form.pattern.' + pattern + '.description' | translate"
|
||||||
<div
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
class="toggle-switch">
|
ngbDropdownItem
|
||||||
<div class="slider"></div>
|
type="button">
|
||||||
</div>
|
<div>{{ 'ldn-service.form.pattern.' + pattern + '.label' | translate }}</div>
|
||||||
</div>
|
<div
|
||||||
|
class="small-text">{{ 'ldn-service.form.pattern.' + pattern + '.description' | translate }}</div>
|
||||||
<div class="col-sm-1 btn-group">
|
</button>
|
||||||
<button (click)="markForOutboundPatternDeletion(i)" class="btn btn-outline-dark trash-button" type="button">
|
</div>
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
<button (click)="unmarkForOutboundPatternDeletion(i)" *ngIf="markedForDeletionOutboundPattern.includes(i)" class="btn btn-outline-dark undo-button"
|
|
||||||
type="button">
|
|
||||||
<i class="fas fa-undo"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<span
|
|
||||||
(click)="addOutboundPattern()"
|
|
||||||
class="add-pattern-link mb-2">{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="mb-5">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div aria-label="Basic example" class="submission-form-footer mt-1 mb-1 position-sticky" role="group">
|
|
||||||
<button class="btn btn-primary" type="submit">
|
|
||||||
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
<div class="d-flex">
|
|
||||||
<button (click)="this.openResetFormModal(this.resetFormModal)" class="btn btn-danger" type="button">
|
|
||||||
<span><i class="fas fa-trash"></i> {{ 'submission.general.discard.submit' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<ng-container
|
||||||
|
*ngIf="!!(formModel.get('notifyServiceOutboundPatterns')['controls'][i].value.pattern)">
|
||||||
|
<div #outboundItemfilterDropdown="ngbDropdown" class="w-100" id="constraint{{i}}"
|
||||||
|
ngbDropdown
|
||||||
|
placement="bottom-start">
|
||||||
|
<div class="position-relative right-addon" role="combobox">
|
||||||
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
ngbDropdownToggle></i>
|
||||||
|
<input
|
||||||
|
(click)="outboundItemfilterDropdown.open();"
|
||||||
|
[readonly]="true"
|
||||||
|
[value]="selectedOutboundItemfilters"
|
||||||
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
|
formControlName="constraint"
|
||||||
|
id="outboundItemfilterDropdown"
|
||||||
|
ngbDropdownAnchor
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
<div aria-labelledby="outboundItemfilterDropdownButton"
|
||||||
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
|
ngbDropdownMenu>
|
||||||
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectOutboundItemFilter(constraint.id, i); $event.stopPropagation()"
|
||||||
|
*ngFor="let constraint of (itemfiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
ngbDropdownItem
|
||||||
|
type="button">
|
||||||
|
<div>{{ constraint.id }}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [style.visibility]="'hidden'" class="col-sm-1">
|
||||||
|
<input hidden id="automatic{{i}}" name="automatic{{i}}" type="checkbox">
|
||||||
|
<div
|
||||||
|
class="toggle-switch">
|
||||||
|
<div class="slider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button (click)="markForOutboundPatternDeletion(i)"
|
||||||
|
class="btn btn-outline-dark trash-button" type="button">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
<button (click)="unmarkForOutboundPatternDeletion(i)"
|
||||||
|
*ngIf="markedForDeletionOutboundPattern.includes(i)"
|
||||||
|
class="btn btn-warning "
|
||||||
|
type="button">
|
||||||
|
<i class="fas fa-undo"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
(click)="addOutboundPattern()"
|
||||||
|
class="add-pattern-link mb-4">{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="submission-form-footer my-1 position-sticky d-flex justify-content-between" role="group">
|
||||||
|
<button (click)="openResetFormModal(resetFormModal)" class="btn btn-danger" type="button">
|
||||||
|
<span><i class="fas fa-trash"></i> {{ 'submission.general.discard.submit' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #confirmModal>
|
<ng-template #confirmModal>
|
||||||
|
<div class="modal-header">
|
||||||
|
<div>
|
||||||
|
<h4>{{'service.overview.edit.modal' | translate }}</h4>
|
||||||
|
</div>
|
||||||
|
<button (click)="closeModal()" aria-label="Close"
|
||||||
|
class="close" type="button">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
<div class="modal-header">
|
{{ 'service.overview.edit.body' | translate }}
|
||||||
<div>
|
</div>
|
||||||
<h4>{{'service.overview.edit.modal' | translate }}</h4>
|
<div class="mt-4">
|
||||||
</div>
|
<button (click)="closeModal()" class="btn btn-danger mr-2"
|
||||||
<button (click)="closeModal()" aria-label="Close"
|
id="delete-confirm">{{ 'service.detail.return' | translate }}
|
||||||
class="close" type="button">
|
</button>
|
||||||
<span aria-hidden="true">×</span>
|
<button (click)="patchService()"
|
||||||
</button>
|
class="btn btn-primary">{{ 'service.detail.update' | translate }}
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
<div class="modal-body">
|
|
||||||
<div>
|
|
||||||
{{ 'service.overview.edit.body' | translate }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
<button (click)="closeModal()" class="btn btn-danger mr-2"
|
|
||||||
id="delete-confirm">{{ 'service.detail.return' | translate }}
|
|
||||||
</button>
|
|
||||||
<button (click)="this.patchService()"
|
|
||||||
class="btn btn-primary custom-btn">{{ 'service.detail.update' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #resetFormModal>
|
<ng-template #resetFormModal>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div>
|
<div>
|
||||||
<h4>{{'service.overview.reset-form.modal' | translate }}</h4>
|
<h4>{{'service.overview.reset-form.modal' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="closeModal()" aria-label="Close"
|
<button (click)="closeModal()" aria-label="Close"
|
||||||
class="close" type="button">
|
class="close" type="button">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div>
|
|
||||||
{{ 'service.overview.reset-form.body' | translate }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
<button (click)="closeModal()" class="mr-2 btn btn-danger"
|
|
||||||
id="reset-delete">{{ 'service.overview.reset-form.reset-confirm' | translate }}
|
|
||||||
</button>
|
|
||||||
<button (click)="resetFormAndLeave()"
|
|
||||||
class="btn btn-primary custom-btn"
|
|
||||||
id="reset-confirm">{{ 'service.overview.reset-form.reset-return' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
|
{{ 'service.overview.reset-form.body' | translate }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<button (click)="closeModal()" class="mr-2 btn btn-danger"
|
||||||
|
id="reset-delete">{{ 'service.overview.reset-form.reset-confirm' | translate }}
|
||||||
|
</button>
|
||||||
|
<button (click)="resetFormAndLeave()"
|
||||||
|
class="btn btn-primary"
|
||||||
|
id="reset-confirm">{{ 'service.overview.reset-form.reset-return' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
@import '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.scss';
|
||||||
|
@import '../../../shared/form/form.component.scss';
|
||||||
|
|
||||||
form {
|
form {
|
||||||
max-width: 800px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
@@ -30,7 +31,6 @@ textarea {
|
|||||||
.add-pattern-link {
|
.add-pattern-link {
|
||||||
color: #0048ff;
|
color: #0048ff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.remove-pattern-link {
|
.remove-pattern-link {
|
||||||
@@ -49,6 +49,12 @@ textarea {
|
|||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: red;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -95,6 +101,11 @@ textarea {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.small-text {
|
||||||
|
font-size: 0.7em;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
@@ -113,11 +124,6 @@ textarea {
|
|||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
form button.btn.btn-primary[type="submit"] {
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submission-form-footer {
|
.submission-form-footer {
|
||||||
border-radius: var(--bs-card-border-radius);
|
border-radius: var(--bs-card-border-radius);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -127,7 +133,7 @@ form button.btn.btn-primary[type="submit"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.marked-for-deletion {
|
.marked-for-deletion {
|
||||||
background-color: #ffcccc;
|
background-color: lighten($red, 30%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,23 +1,80 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
import { LdnServiceFormEditComponent } from './ldn-service-form-edit.component';
|
import {NgbDropdownModule, NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import {LdnServiceFormEditComponent} from './ldn-service-form-edit.component';
|
||||||
|
import {ChangeDetectorRef, EventEmitter} from '@angular/core';
|
||||||
|
import {FormBuilder, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
|
import {TranslateModule, TranslateService} from '@ngx-translate/core';
|
||||||
|
import {PaginationService} from 'ngx-pagination';
|
||||||
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
|
import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service';
|
||||||
|
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
|
||||||
|
import {RouterStub} from '../../../shared/testing/router.stub';
|
||||||
|
import {MockActivatedRoute} from '../../../shared/mocks/active-router.mock';
|
||||||
|
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service.stub';
|
||||||
|
import {of} from 'rxjs';
|
||||||
|
import {RouteService} from '../../../core/services/route.service';
|
||||||
|
import {provideMockStore} from '@ngrx/store/testing';
|
||||||
|
|
||||||
describe('LdnServiceFormEditComponent', () => {
|
describe('LdnServiceFormEditComponent', () => {
|
||||||
let component: LdnServiceFormEditComponent;
|
let component: LdnServiceFormEditComponent;
|
||||||
let fixture: ComponentFixture<LdnServiceFormEditComponent>;
|
let fixture: ComponentFixture<LdnServiceFormEditComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
let ldnServicesService: any;
|
||||||
await TestBed.configureTestingModule({
|
let ldnItemfiltersService: any;
|
||||||
declarations: [LdnServiceFormEditComponent]
|
let cdRefStub: any;
|
||||||
})
|
let modalService: any;
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(LdnServiceFormEditComponent);
|
const translateServiceStub = {
|
||||||
component = fixture.componentInstance;
|
get: () => of('translated-text'),
|
||||||
fixture.detectChanges();
|
instant: () => 'translated-text',
|
||||||
|
onLangChange: new EventEmitter(),
|
||||||
|
onTranslationChange: new EventEmitter(),
|
||||||
|
onDefaultLangChange: new EventEmitter()
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
ldnServicesService = {
|
||||||
|
update: () => ({}),
|
||||||
|
};
|
||||||
|
ldnItemfiltersService = {
|
||||||
|
findAll: () => of(['item1', 'item2']),
|
||||||
|
};
|
||||||
|
cdRefStub = Object.assign({
|
||||||
|
detectChanges: () => fixture.detectChanges()
|
||||||
});
|
});
|
||||||
|
modalService = {
|
||||||
|
open: () => {/*comment*/
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
it('should create', () => {
|
await TestBed.configureTestingModule({
|
||||||
expect(component).toBeTruthy();
|
imports: [ReactiveFormsModule, TranslateModule.forRoot(), NgbDropdownModule],
|
||||||
});
|
declarations: [LdnServiceFormEditComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: LdnServicesService, useValue: ldnServicesService},
|
||||||
|
{provide: LdnItemfiltersService, useValue: ldnItemfiltersService},
|
||||||
|
{provide: Router, useValue: new RouterStub()},
|
||||||
|
{provide: ActivatedRoute, useValue: new MockActivatedRoute()},
|
||||||
|
{provide: ChangeDetectorRef, useValue: cdRefStub},
|
||||||
|
{provide: NgbModal, useValue: modalService},
|
||||||
|
{provide: NotificationsService, useValue: NotificationsServiceStub},
|
||||||
|
{provide: TranslateService, useValue: translateServiceStub},
|
||||||
|
{provide: PaginationService, useValue: {}},
|
||||||
|
FormBuilder,
|
||||||
|
RouteService,
|
||||||
|
provideMockStore({}),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(LdnServiceFormEditComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,409 +1,579 @@
|
|||||||
import { ChangeDetectorRef, Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
import {ChangeDetectorRef, Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core';
|
||||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
|
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import { LdnServicesService } from '../ldn-services-data/ldn-services-data.service';
|
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
|
||||||
import { notifyPatterns } from '../ldn-services-patterns/ldn-service-coar-patterns';
|
import {notifyPatterns} from '../ldn-services-patterns/ldn-service-coar-patterns';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
import { LdnService } from '../ldn-services-model/ldn-services.model';
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
import { RemoteData } from 'src/app/core/data/remote-data';
|
import {RemoteData} from 'src/app/core/data/remote-data';
|
||||||
import { Operation } from 'fast-json-patch';
|
import {Operation} from 'fast-json-patch';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
|
||||||
import { LdnItemfiltersService } from '../ldn-services-data/ldn-itemfilters-data.service';
|
import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service';
|
||||||
import { Itemfilter } from '../ldn-services-model/ldn-service-itemfilters';
|
import {Itemfilter} from '../ldn-services-model/ldn-service-itemfilters';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
import { Observable } from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
import {PaginationService} from '../../../core/pagination/pagination.service';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import {FindListOptions} from '../../../core/data/find-list-options.model';
|
||||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
import {PaginationComponentOptions} from '../../../shared/pagination/pagination-component-options.model';
|
||||||
|
import {NotifyServicePattern} from '../ldn-services-model/ldn-service-patterns.model';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component for editing LDN service through a form that allows to edit the properties of the selected service
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-ldn-service-form-edit',
|
selector: 'ds-ldn-service-form-edit',
|
||||||
templateUrl: './ldn-service-form-edit.component.html',
|
templateUrl: './ldn-service-form-edit.component.html',
|
||||||
styleUrls: ['./ldn-service-form-edit.component.scss'],
|
styleUrls: ['./ldn-service-form-edit.component.scss'],
|
||||||
animations: [
|
animations: [
|
||||||
trigger('toggleAnimation', [
|
trigger('toggleAnimation', [
|
||||||
state('true', style({})),
|
state('true', style({})),
|
||||||
state('false', style({})),
|
state('false', style({})),
|
||||||
transition('true <=> false', animate('300ms ease-in')),
|
transition('true <=> false', animate('300ms ease-in')),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class LdnServiceFormEditComponent implements OnInit {
|
export class LdnServiceFormEditComponent implements OnInit {
|
||||||
formModel: FormGroup;
|
formModel: FormGroup;
|
||||||
@ViewChild('confirmModal', {static: true}) confirmModal: TemplateRef<any>;
|
@ViewChild('confirmModal', {static: true}) confirmModal: TemplateRef<any>;
|
||||||
@ViewChild('resetFormModal', {static: true}) resetFormModal: TemplateRef<any>;
|
@ViewChild('resetFormModal', {static: true}) resetFormModal: TemplateRef<any>;
|
||||||
|
|
||||||
public inboundPatterns: object[] = notifyPatterns;
|
public inboundPatterns: string[] = notifyPatterns;
|
||||||
public outboundPatterns: object[] = notifyPatterns;
|
public outboundPatterns: string[] = notifyPatterns;
|
||||||
itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
||||||
config: FindListOptions = Object.assign(new FindListOptions(), {
|
config: FindListOptions = Object.assign(new FindListOptions(), {
|
||||||
elementsPerPage: 20
|
elementsPerPage: 20
|
||||||
|
});
|
||||||
|
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||||
|
id: 'po',
|
||||||
|
pageSize: 20
|
||||||
|
});
|
||||||
|
@Input() public name: string;
|
||||||
|
@Input() public description: string;
|
||||||
|
@Input() public url: string;
|
||||||
|
@Input() public ldnUrl: string;
|
||||||
|
@Input() public score: number;
|
||||||
|
@Input() public inboundPattern: string;
|
||||||
|
@Input() public outboundPattern: string;
|
||||||
|
@Input() public constraint: string;
|
||||||
|
@Input() public automatic: boolean;
|
||||||
|
@Input() public headerKey: string;
|
||||||
|
markedForDeletionInboundPattern: number[] = [];
|
||||||
|
markedForDeletionOutboundPattern: number[] = [];
|
||||||
|
selectedOutboundPatterns: string[];
|
||||||
|
selectedInboundItemfilters: string[];
|
||||||
|
selectedOutboundItemfilters: string[];
|
||||||
|
selectedInboundPatterns: string[];
|
||||||
|
protected serviceId: string;
|
||||||
|
private deletedInboundPatterns: number[] = [];
|
||||||
|
private deletedOutboundPatterns: number[] = [];
|
||||||
|
private modalRef: any;
|
||||||
|
private service: LdnService;
|
||||||
|
private selectPatternDefaultLabeli18Key = 'ldn-service.form.label.placeholder.default-select';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected ldnServicesService: LdnServicesService,
|
||||||
|
private ldnItemfiltersService: LdnItemfiltersService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private cdRef: ChangeDetectorRef,
|
||||||
|
protected modalService: NgbModal,
|
||||||
|
private notificationService: NotificationsService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
protected paginationService: PaginationService
|
||||||
|
) {
|
||||||
|
|
||||||
|
this.formModel = this.formBuilder.group({
|
||||||
|
id: [''],
|
||||||
|
name: ['', Validators.required],
|
||||||
|
description: ['', Validators.required],
|
||||||
|
url: ['', Validators.required],
|
||||||
|
ldnUrl: ['', Validators.required],
|
||||||
|
score: ['', [Validators.required, Validators.pattern('^0*(\.[0-9]+)?$|^1(\.0+)?$')]], inboundPattern: [''],
|
||||||
|
outboundPattern: [''],
|
||||||
|
constraintPattern: [''],
|
||||||
|
enabled: [''],
|
||||||
|
notifyServiceInboundPatterns: this.formBuilder.array([this.createInboundPatternFormGroup()]),
|
||||||
|
notifyServiceOutboundPatterns: this.formBuilder.array([this.createOutboundPatternFormGroup()]),
|
||||||
|
type: LDN_SERVICE.value,
|
||||||
});
|
});
|
||||||
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
}
|
||||||
id: 'po',
|
|
||||||
pageSize: 20
|
ngOnInit(): void {
|
||||||
|
this.route.params.subscribe((params) => {
|
||||||
|
this.serviceId = params.serviceId;
|
||||||
|
if (this.serviceId) {
|
||||||
|
this.fetchServiceData(this.serviceId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
@Input() public name: string;
|
this.setItemfilters();
|
||||||
@Input() public description: string;
|
}
|
||||||
@Input() public url: string;
|
|
||||||
@Input() public ldnUrl: string;
|
|
||||||
@Input() public inboundPattern: string;
|
|
||||||
@Input() public outboundPattern: string;
|
|
||||||
@Input() public constraint: string;
|
|
||||||
@Input() public automatic: boolean;
|
|
||||||
@Input() public headerKey: string;
|
|
||||||
markedForDeletionInboundPattern: number[] = [];
|
|
||||||
markedForDeletionOutboundPattern: number[] = [];
|
|
||||||
protected serviceId: string;
|
|
||||||
private originalInboundPatterns: any[] = [];
|
|
||||||
private originalOutboundPatterns: any[] = [];
|
|
||||||
private deletedInboundPatterns: number[] = [];
|
|
||||||
private deletedOutboundPatterns: number[] = [];
|
|
||||||
private modalRef: any;
|
|
||||||
private service: LdnService;
|
|
||||||
|
|
||||||
constructor(
|
/**
|
||||||
protected ldnServicesService: LdnServicesService,
|
* Sets item filters using LDN item filters service
|
||||||
private ldnItemfiltersService: LdnItemfiltersService,
|
*/
|
||||||
private formBuilder: FormBuilder,
|
setItemfilters() {
|
||||||
private router: Router,
|
this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe(
|
||||||
private route: ActivatedRoute,
|
getFirstCompletedRemoteData());
|
||||||
private cdRef: ChangeDetectorRef,
|
}
|
||||||
protected modalService: NgbModal,
|
|
||||||
private notificationService: NotificationsService,
|
|
||||||
private translateService: TranslateService,
|
|
||||||
protected paginationService: PaginationService
|
|
||||||
) {
|
|
||||||
|
|
||||||
this.formModel = this.formBuilder.group({
|
/**
|
||||||
id: [''],
|
* Fetches LDN service data by ID and updates the form
|
||||||
name: ['', Validators.required],
|
* @param serviceId - The ID of the LDN service
|
||||||
description: ['', Validators.required],
|
*/
|
||||||
url: ['', Validators.required],
|
fetchServiceData(serviceId: string): void {
|
||||||
ldnUrl: ['', Validators.required],
|
this.ldnServicesService.findById(serviceId).pipe(
|
||||||
inboundPattern: [''],
|
getFirstCompletedRemoteData()
|
||||||
outboundPattern: [''],
|
).subscribe(
|
||||||
constraintPattern: [''],
|
(data: RemoteData<LdnService>) => {
|
||||||
enabled: [''],
|
if (data.hasSucceeded) {
|
||||||
notifyServiceInboundPatterns: this.formBuilder.array([this.createInboundPatternFormGroup()]),
|
this.service = data.payload;
|
||||||
notifyServiceOutboundPatterns: this.formBuilder.array([this.createOutboundPatternFormGroup()]),
|
|
||||||
type: LDN_SERVICE.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
this.formModel.patchValue({
|
||||||
this.route.params.subscribe((params) => {
|
id: this.service.id,
|
||||||
this.serviceId = params.serviceId;
|
name: this.service.name,
|
||||||
if (this.serviceId) {
|
description: this.service.description,
|
||||||
this.fetchServiceData(this.serviceId);
|
url: this.service.url,
|
||||||
}
|
score: this.service.score, ldnUrl: this.service.ldnUrl,
|
||||||
});
|
type: this.service.type,
|
||||||
this.setItemfilters();
|
enabled: this.service.enabled
|
||||||
}
|
});
|
||||||
|
this.filterPatternObjectsAndPickLabel('notifyServiceInboundPatterns', false);
|
||||||
setItemfilters() {
|
this.filterPatternObjectsAndPickLabel('notifyServiceOutboundPatterns', true);
|
||||||
this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe(
|
|
||||||
getFirstCompletedRemoteData());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fetchServiceData(serviceId: string): void {
|
|
||||||
this.ldnServicesService.findById(serviceId).pipe(
|
|
||||||
getFirstCompletedRemoteData()
|
|
||||||
).subscribe(
|
|
||||||
(data: RemoteData<LdnService>) => {
|
|
||||||
if (data.hasSucceeded) {
|
|
||||||
this.service = data.payload;
|
|
||||||
|
|
||||||
this.formModel.patchValue({
|
|
||||||
id: this.service.id,
|
|
||||||
name: this.service.name,
|
|
||||||
description: this.service.description,
|
|
||||||
url: this.service.url,
|
|
||||||
ldnUrl: this.service.ldnUrl,
|
|
||||||
type: this.service.type,
|
|
||||||
enabled: this.service.enabled
|
|
||||||
});
|
|
||||||
|
|
||||||
const inboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
|
||||||
inboundPatternsArray.clear();
|
|
||||||
|
|
||||||
this.service.notifyServiceInboundPatterns.forEach((pattern: any) => {
|
|
||||||
const patternFormGroup = this.initializeInboundPatternFormGroup();
|
|
||||||
patternFormGroup.patchValue(pattern);
|
|
||||||
inboundPatternsArray.push(patternFormGroup);
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
const outboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
|
||||||
outboundPatternsArray.clear();
|
|
||||||
|
|
||||||
this.service.notifyServiceOutboundPatterns.forEach((pattern: any) => {
|
|
||||||
const patternFormGroup = this.initializeOutboundPatternFormGroup();
|
|
||||||
patternFormGroup.patchValue(pattern);
|
|
||||||
outboundPatternsArray.push(patternFormGroup);
|
|
||||||
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
});
|
|
||||||
this.originalInboundPatterns = [...this.service.notifyServiceInboundPatterns];
|
|
||||||
this.originalOutboundPatterns = [...this.service.notifyServiceOutboundPatterns];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
generatePatchOperations(): any[] {
|
|
||||||
const patchOperations: any[] = [];
|
|
||||||
|
|
||||||
this.createReplaceOperation(patchOperations, 'name', '/name');
|
|
||||||
this.createReplaceOperation(patchOperations, 'description', '/description');
|
|
||||||
this.createReplaceOperation(patchOperations, 'ldnUrl', '/ldnurl');
|
|
||||||
this.createReplaceOperation(patchOperations, 'url', '/url');
|
|
||||||
|
|
||||||
this.handlePatterns(patchOperations, 'notifyServiceInboundPatterns');
|
|
||||||
this.handlePatterns(patchOperations, 'notifyServiceOutboundPatterns');
|
|
||||||
|
|
||||||
this.deletedInboundPatterns.forEach(index => {
|
|
||||||
const removeOperation: Operation = {
|
|
||||||
op: 'remove',
|
|
||||||
path: `notifyServiceInboundPatterns[${index}]`
|
|
||||||
};
|
|
||||||
patchOperations.push(removeOperation);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.deletedOutboundPatterns.forEach(index => {
|
|
||||||
const removeOperation: Operation = {
|
|
||||||
op: 'remove',
|
|
||||||
path: `notifyServiceOutboundPatterns[${index}]`
|
|
||||||
};
|
|
||||||
patchOperations.push(removeOperation);
|
|
||||||
});
|
|
||||||
|
|
||||||
return patchOperations;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
this.openConfirmModal(this.confirmModal);
|
|
||||||
}
|
|
||||||
|
|
||||||
addInboundPattern() {
|
|
||||||
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
|
||||||
notifyServiceInboundPatternsArray.push(this.createInboundPatternFormGroup());
|
|
||||||
}
|
|
||||||
|
|
||||||
addOutboundPattern() {
|
|
||||||
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
|
||||||
notifyServiceOutboundPatternsArray.push(this.createOutboundPatternFormGroup());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toggleAutomatic(i: number) {
|
|
||||||
const automaticControl = this.formModel.get(`notifyServiceInboundPatterns.${i}.automatic`);
|
|
||||||
if (automaticControl) {
|
|
||||||
automaticControl.setValue(!automaticControl.value);
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters pattern objects, initializes form groups, assigns labels, and adds them to the specified form array so the correct string is shown in the dropdown..
|
||||||
|
* @param formArrayName - The name of the form array to be populated
|
||||||
|
* @param isOutbound - A boolean indicating whether the patterns are outbound (true) or inbound (false)
|
||||||
|
*/
|
||||||
|
filterPatternObjectsAndPickLabel(formArrayName: string, isOutbound: boolean) {
|
||||||
|
const PatternsArray = this.formModel.get(formArrayName) as FormArray;
|
||||||
|
PatternsArray.clear();
|
||||||
|
let servicesToUse;
|
||||||
|
if (isOutbound) {
|
||||||
|
servicesToUse = this.service.notifyServiceOutboundPatterns;
|
||||||
|
} else {
|
||||||
|
servicesToUse = this.service.notifyServiceInboundPatterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleEnabled() {
|
servicesToUse.forEach((patternObj: NotifyServicePattern) => {
|
||||||
const newStatus = !this.formModel.get('enabled').value;
|
let patternFormGroup;
|
||||||
|
if (isOutbound) {
|
||||||
|
patternFormGroup = this.initializeOutboundPatternFormGroup();
|
||||||
|
} else {
|
||||||
|
patternFormGroup = this.initializeInboundPatternFormGroup();
|
||||||
|
}
|
||||||
|
const newPatternObjWithLabel = Object.assign(new NotifyServicePattern(), {
|
||||||
|
...patternObj,
|
||||||
|
patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternObj?.pattern + '.label')
|
||||||
|
});
|
||||||
|
patternFormGroup.patchValue(newPatternObjWithLabel);
|
||||||
|
|
||||||
const patchOperation: Operation = {
|
PatternsArray.push(patternFormGroup);
|
||||||
op: 'replace',
|
this.cdRef.detectChanges();
|
||||||
path: '/enabled',
|
});
|
||||||
value: newStatus,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ldnServicesService.patch(this.service, [patchOperation]).pipe(
|
|
||||||
getFirstCompletedRemoteData()
|
|
||||||
).subscribe(
|
|
||||||
() => {
|
|
||||||
|
|
||||||
this.formModel.get('enabled').setValue(newStatus);
|
}
|
||||||
this.cdRef.detectChanges();
|
|
||||||
}
|
/**
|
||||||
);
|
* Generates an array of patch operations based on form changes
|
||||||
|
* @returns Array of patch operations
|
||||||
|
*/
|
||||||
|
generatePatchOperations(): any[] {
|
||||||
|
const patchOperations: any[] = [];
|
||||||
|
|
||||||
|
this.createReplaceOperation(patchOperations, 'name', '/name');
|
||||||
|
this.createReplaceOperation(patchOperations, 'description', '/description');
|
||||||
|
this.createReplaceOperation(patchOperations, 'ldnUrl', '/ldnurl');
|
||||||
|
this.createReplaceOperation(patchOperations, 'url', '/url');
|
||||||
|
this.createReplaceOperation(patchOperations, 'score', '/score');
|
||||||
|
|
||||||
|
this.handlePatterns(patchOperations, 'notifyServiceInboundPatterns');
|
||||||
|
this.handlePatterns(patchOperations, 'notifyServiceOutboundPatterns');
|
||||||
|
|
||||||
|
|
||||||
|
this.deletedInboundPatterns.forEach(index => {
|
||||||
|
const removeOperation: Operation = {
|
||||||
|
op: 'remove',
|
||||||
|
path: `notifyServiceInboundPatterns[${index}]`
|
||||||
|
};
|
||||||
|
patchOperations.push(removeOperation);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.deletedOutboundPatterns.forEach(index => {
|
||||||
|
const removeOperation: Operation = {
|
||||||
|
op: 'remove',
|
||||||
|
path: `notifyServiceOutboundPatterns[${index}]`
|
||||||
|
};
|
||||||
|
patchOperations.push(removeOperation);
|
||||||
|
});
|
||||||
|
|
||||||
|
return patchOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits the form by opening the confirmation modal
|
||||||
|
*/
|
||||||
|
onSubmit() {
|
||||||
|
this.openConfirmModal(this.confirmModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new inbound pattern form group to the array of inbound patterns in the form
|
||||||
|
*/
|
||||||
|
addInboundPattern() {
|
||||||
|
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||||
|
notifyServiceInboundPatternsArray.push(this.createInboundPatternFormGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new outbound pattern form group to the array of outbound patterns in the form
|
||||||
|
*/
|
||||||
|
addOutboundPattern() {
|
||||||
|
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
||||||
|
notifyServiceOutboundPatternsArray.push(this.createOutboundPatternFormGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an outbound pattern by updating its values based on the provided pattern value and index
|
||||||
|
* @param patternValue - The selected pattern value
|
||||||
|
* @param index - The index of the outbound pattern in the array
|
||||||
|
*/
|
||||||
|
selectOutboundPattern(patternValue: string, index: number): void {
|
||||||
|
const patternArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray);
|
||||||
|
patternArray.controls[index].patchValue({pattern: patternValue});
|
||||||
|
patternArray.controls[index].patchValue({patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternValue + '.label')});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an outbound item filter by updating its value based on the provided filter value and index
|
||||||
|
* @param filterValue - The selected filter value
|
||||||
|
* @param index - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
selectOutboundItemFilter(filterValue: string, index: number) {
|
||||||
|
const filterArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray);
|
||||||
|
filterArray.controls[index].patchValue({constraint: filterValue});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an inbound pattern by updating its values based on the provided pattern value and index
|
||||||
|
* @param patternValue - The selected pattern value
|
||||||
|
* @param index - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
selectInboundPattern(patternValue: string, index: number): void {
|
||||||
|
const patternArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray);
|
||||||
|
patternArray.controls[index].patchValue({pattern: patternValue});
|
||||||
|
patternArray.controls[index].patchValue({patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternValue + '.label')});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an inbound item filter by updating its value based on the provided filter value and index
|
||||||
|
* @param filterValue - The selected filter value
|
||||||
|
* @param index - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
selectInboundItemFilter(filterValue: string, index: number): void {
|
||||||
|
const filterArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray);
|
||||||
|
filterArray.controls[index].patchValue({constraint: filterValue});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the automatic property of an inbound pattern at the specified index
|
||||||
|
* @param i - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
toggleAutomatic(i: number) {
|
||||||
|
const automaticControl = this.formModel.get(`notifyServiceInboundPatterns.${i}.automatic`);
|
||||||
|
if (automaticControl) {
|
||||||
|
automaticControl.setValue(!automaticControl.value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the enabled status of the LDN service by sending a patch request
|
||||||
|
*/
|
||||||
|
toggleEnabled() {
|
||||||
|
const newStatus = !this.formModel.get('enabled').value;
|
||||||
|
|
||||||
closeModal() {
|
const patchOperation: Operation = {
|
||||||
this.modalRef.close();
|
op: 'replace',
|
||||||
|
path: '/enabled',
|
||||||
|
value: newStatus,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ldnServicesService.patch(this.service, [patchOperation]).pipe(
|
||||||
|
getFirstCompletedRemoteData()
|
||||||
|
).subscribe(
|
||||||
|
() => {
|
||||||
|
|
||||||
|
this.formModel.get('enabled').setValue(newStatus);
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
openConfirmModal(content) {
|
/**
|
||||||
this.modalRef = this.modalService.open(content);
|
* Closes the modal
|
||||||
}
|
*/
|
||||||
|
closeModal() {
|
||||||
|
this.modalRef.close();
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
openResetFormModal(content) {
|
/**
|
||||||
this.modalRef = this.modalService.open(content);
|
* Opens a confirmation modal with the specified content
|
||||||
}
|
* @param content - The content to be displayed in the modal
|
||||||
|
*/
|
||||||
|
openConfirmModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
patchService() {
|
/**
|
||||||
this.deleteMarkedInboundPatterns();
|
* Opens a reset form modal with the specified content
|
||||||
this.deleteMarkedOutboundPatterns();
|
* @param content - The content to be displayed in the modal
|
||||||
const patchOperations = this.generatePatchOperations();
|
*/
|
||||||
|
openResetFormModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patches the LDN service by retrieving and sending patch operations geenrated in generatePatchOperations()
|
||||||
|
*/
|
||||||
|
patchService() {
|
||||||
|
this.deleteMarkedInboundPatterns();
|
||||||
|
this.deleteMarkedOutboundPatterns();
|
||||||
|
|
||||||
|
const patchOperations = this.generatePatchOperations();
|
||||||
|
|
||||||
|
|
||||||
this.ldnServicesService.patch(this.service, patchOperations).pipe(
|
this.ldnServicesService.patch(this.service, patchOperations).pipe(
|
||||||
getFirstCompletedRemoteData()
|
getFirstCompletedRemoteData()
|
||||||
).subscribe(
|
).subscribe(
|
||||||
() => {
|
(rd: RemoteData<LdnService>) => {
|
||||||
|
if (rd.hasSucceeded) {
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
this.sendBack();
|
this.sendBack();
|
||||||
this.notificationService.success(this.translateService.get('admin.registries.services-formats.modify.success.head'),
|
this.notificationService.success(this.translateService.get('admin.registries.services-formats.modify.success.head'),
|
||||||
this.translateService.get('admin.registries.services-formats.modify.success.content'));
|
this.translateService.get('admin.registries.services-formats.modify.success.content'));
|
||||||
}
|
} else {
|
||||||
);
|
this.notificationService.error(this.translateService.get('admin.registries.services-formats.modify.failure.head'),
|
||||||
|
this.translateService.get('admin.registries.services-formats.modify.failure.content'));
|
||||||
}
|
this.closeModal();
|
||||||
|
|
||||||
resetFormAndLeave() {
|
|
||||||
this.sendBack();
|
|
||||||
this.closeModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
markForInboundPatternDeletion(index: number) {
|
|
||||||
if (!this.markedForDeletionInboundPattern.includes(index)) {
|
|
||||||
this.markedForDeletionInboundPattern.push(index);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
unmarkForInboundPatternDeletion(index: number) {
|
/**
|
||||||
const i = this.markedForDeletionInboundPattern.indexOf(index);
|
* Resets the form and navigates back to the LDN services page
|
||||||
if (i !== -1) {
|
*/
|
||||||
this.markedForDeletionInboundPattern.splice(i, 1);
|
resetFormAndLeave() {
|
||||||
|
this.sendBack();
|
||||||
|
this.closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the specified inbound pattern for deletion
|
||||||
|
* @param index - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
markForInboundPatternDeletion(index: number) {
|
||||||
|
if (!this.markedForDeletionInboundPattern.includes(index)) {
|
||||||
|
this.markedForDeletionInboundPattern.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmarks the specified inbound pattern for deletion
|
||||||
|
* @param index - The index of the inbound pattern in the array
|
||||||
|
*/
|
||||||
|
unmarkForInboundPatternDeletion(index: number) {
|
||||||
|
const i = this.markedForDeletionInboundPattern.indexOf(index);
|
||||||
|
if (i !== -1) {
|
||||||
|
this.markedForDeletionInboundPattern.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the specified outbound pattern for deletion
|
||||||
|
* @param index - The index of the outbound pattern in the array
|
||||||
|
*/
|
||||||
|
markForOutboundPatternDeletion(index: number) {
|
||||||
|
if (!this.markedForDeletionOutboundPattern.includes(index)) {
|
||||||
|
this.markedForDeletionOutboundPattern.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmarks the specified outbound pattern for deletion
|
||||||
|
* @param index - The index of the outbound pattern in the array
|
||||||
|
*/
|
||||||
|
unmarkForOutboundPatternDeletion(index: number) {
|
||||||
|
const i = this.markedForDeletionOutboundPattern.indexOf(index);
|
||||||
|
if (i !== -1) {
|
||||||
|
this.markedForDeletionOutboundPattern.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes marked inbound patterns from the form model
|
||||||
|
*/
|
||||||
|
deleteMarkedInboundPatterns() {
|
||||||
|
this.markedForDeletionInboundPattern.sort((a, b) => b - a);
|
||||||
|
const patternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||||
|
|
||||||
|
for (const index of this.markedForDeletionInboundPattern) {
|
||||||
|
if (index >= 0 && index < patternsArray.length) {
|
||||||
|
const patternGroup = patternsArray.at(index) as FormGroup;
|
||||||
|
const patternValue = patternGroup.value;
|
||||||
|
if (patternValue.isNew) {
|
||||||
|
patternsArray.removeAt(index);
|
||||||
|
} else {
|
||||||
|
this.deletedInboundPatterns.push(index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
markForOutboundPatternDeletion(index: number) {
|
this.markedForDeletionInboundPattern = [];
|
||||||
if (!this.markedForDeletionOutboundPattern.includes(index)) {
|
}
|
||||||
this.markedForDeletionOutboundPattern.push(index);
|
|
||||||
|
/**
|
||||||
|
* Deletes marked outbound patterns from the form model
|
||||||
|
*/
|
||||||
|
deleteMarkedOutboundPatterns() {
|
||||||
|
this.markedForDeletionOutboundPattern.sort((a, b) => b - a);
|
||||||
|
const patternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
||||||
|
|
||||||
|
for (const index of this.markedForDeletionOutboundPattern) {
|
||||||
|
if (index >= 0 && index < patternsArray.length) {
|
||||||
|
const patternGroup = patternsArray.at(index) as FormGroup;
|
||||||
|
const patternValue = patternGroup.value;
|
||||||
|
if (patternValue.isNew) {
|
||||||
|
patternsArray.removeAt(index);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.deletedOutboundPatterns.push(index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarkForOutboundPatternDeletion(index: number) {
|
this.markedForDeletionOutboundPattern = [];
|
||||||
const i = this.markedForDeletionOutboundPattern.indexOf(index);
|
}
|
||||||
if (i !== -1) {
|
|
||||||
this.markedForDeletionOutboundPattern.splice(i, 1);
|
/**
|
||||||
|
* Creates a replace operation and adds it to the patch operations if the form control is dirty
|
||||||
|
* @param patchOperations - The array to store patch operations
|
||||||
|
* @param formControlName - The name of the form control
|
||||||
|
* @param path - The JSON Patch path for the operation
|
||||||
|
*/
|
||||||
|
private createReplaceOperation(patchOperations: any[], formControlName: string, path: string): void {
|
||||||
|
if (this.formModel.get(formControlName).dirty) {
|
||||||
|
patchOperations.push({
|
||||||
|
op: 'replace',
|
||||||
|
path,
|
||||||
|
value: this.formModel.get(formControlName).value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles patterns in the form array, checking if an add or replace operations is required
|
||||||
|
* @param patchOperations - The array to store patch operations
|
||||||
|
* @param formArrayName - The name of the form array
|
||||||
|
*/
|
||||||
|
private handlePatterns(patchOperations: any[], formArrayName: string): void {
|
||||||
|
const patternsArray = this.formModel.get(formArrayName) as FormArray;
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < patternsArray.length; i++) {
|
||||||
|
const patternGroup = patternsArray.at(i) as FormGroup;
|
||||||
|
|
||||||
|
const patternValue = patternGroup.value;
|
||||||
|
if (patternGroup.touched) {
|
||||||
|
delete patternValue?.patternLabel;
|
||||||
|
if (patternValue.isNew) {
|
||||||
|
delete patternValue.isNew;
|
||||||
|
const addOperation = {
|
||||||
|
op: 'add',
|
||||||
|
path: `${formArrayName}/-`,
|
||||||
|
value: patternValue,
|
||||||
|
};
|
||||||
|
patchOperations.push(addOperation);
|
||||||
|
} else {
|
||||||
|
const replaceOperation = {
|
||||||
|
op: 'replace',
|
||||||
|
path: `${formArrayName}[${i}]`,
|
||||||
|
value: patternValue,
|
||||||
|
};
|
||||||
|
patchOperations.push(replaceOperation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deleteMarkedInboundPatterns() {
|
/**
|
||||||
this.markedForDeletionInboundPattern.sort((a, b) => b - a);
|
* Navigates back to the LDN services page
|
||||||
const patternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
*/
|
||||||
|
private sendBack() {
|
||||||
|
this.router.navigateByUrl('admin/ldn/services');
|
||||||
|
}
|
||||||
|
|
||||||
for (const index of this.markedForDeletionInboundPattern) {
|
/**
|
||||||
if (index >= 0 && index < patternsArray.length) {
|
* Creates a form group for outbound patterns
|
||||||
const patternGroup = patternsArray.at(index) as FormGroup;
|
* @returns The form group for outbound patterns
|
||||||
const patternValue = patternGroup.value;
|
*/
|
||||||
if (patternValue.isNew) {
|
private createOutboundPatternFormGroup(): FormGroup {
|
||||||
patternsArray.removeAt(index);
|
return this.formBuilder.group({
|
||||||
} else {
|
pattern: '',
|
||||||
this.deletedInboundPatterns.push(index);
|
patternLabel: this.translateService.instant(this.selectPatternDefaultLabeli18Key),
|
||||||
}
|
constraint: '',
|
||||||
}
|
isNew: true,
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.markedForDeletionInboundPattern = [];
|
/**
|
||||||
}
|
* Creates a form group for inbound patterns
|
||||||
|
* @returns The form group for inbound patterns
|
||||||
|
*/
|
||||||
|
private createInboundPatternFormGroup(): FormGroup {
|
||||||
|
return this.formBuilder.group({
|
||||||
|
pattern: '',
|
||||||
|
patternLabel: this.translateService.instant(this.selectPatternDefaultLabeli18Key),
|
||||||
|
constraint: '',
|
||||||
|
automatic: false,
|
||||||
|
isNew: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an existing form group for outbound patterns
|
||||||
|
* @returns The initialized form group for outbound patterns
|
||||||
|
*/
|
||||||
|
private initializeOutboundPatternFormGroup(): FormGroup {
|
||||||
|
return this.formBuilder.group({
|
||||||
|
pattern: '',
|
||||||
|
patternLabel: '',
|
||||||
|
constraint: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
deleteMarkedOutboundPatterns() {
|
/**
|
||||||
this.markedForDeletionOutboundPattern.sort((a, b) => b - a);
|
* Initializes an existing form group for inbound patterns
|
||||||
const patternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
* @returns The initialized form group for inbound patterns
|
||||||
|
*/
|
||||||
for (const index of this.markedForDeletionOutboundPattern) {
|
private initializeInboundPatternFormGroup(): FormGroup {
|
||||||
if (index >= 0 && index < patternsArray.length) {
|
return this.formBuilder.group({
|
||||||
const patternGroup = patternsArray.at(index) as FormGroup;
|
pattern: '',
|
||||||
const patternValue = patternGroup.value;
|
patternLabel: '',
|
||||||
if (patternValue.isNew) {
|
constraint: '',
|
||||||
patternsArray.removeAt(index);
|
automatic: '',
|
||||||
} else {
|
});
|
||||||
|
}
|
||||||
this.deletedOutboundPatterns.push(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.markedForDeletionOutboundPattern = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private createReplaceOperation(patchOperations: any[], formControlName: string, path: string): void {
|
|
||||||
if (this.formModel.get(formControlName).dirty) {
|
|
||||||
patchOperations.push({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value: this.formModel.get(formControlName).value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private handlePatterns(patchOperations: any[], formArrayName: string): void {
|
|
||||||
const patternsArray = this.formModel.get(formArrayName) as FormArray;
|
|
||||||
|
|
||||||
for (let i = 0; i < patternsArray.length; i++) {
|
|
||||||
const patternGroup = patternsArray.at(i) as FormGroup;
|
|
||||||
const patternValue = patternGroup.value;
|
|
||||||
|
|
||||||
if (patternGroup.dirty) {
|
|
||||||
if (patternValue.isNew) {
|
|
||||||
delete patternValue.isNew;
|
|
||||||
const addOperation = {
|
|
||||||
op: 'add',
|
|
||||||
path: `${formArrayName}/-`,
|
|
||||||
value: patternValue,
|
|
||||||
};
|
|
||||||
patchOperations.push(addOperation);
|
|
||||||
} else {
|
|
||||||
const replaceOperation = {
|
|
||||||
op: 'replace',
|
|
||||||
path: `${formArrayName}[${i}]`,
|
|
||||||
value: patternValue,
|
|
||||||
};
|
|
||||||
patchOperations.push(replaceOperation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sendBack() {
|
|
||||||
this.router.navigateByUrl('admin/ldn/services');
|
|
||||||
}
|
|
||||||
|
|
||||||
private createOutboundPatternFormGroup(): FormGroup {
|
|
||||||
return this.formBuilder.group({
|
|
||||||
pattern: '',
|
|
||||||
constraint: '',
|
|
||||||
isNew: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private createInboundPatternFormGroup(): FormGroup {
|
|
||||||
return this.formBuilder.group({
|
|
||||||
pattern: '',
|
|
||||||
constraint: '',
|
|
||||||
automatic: false,
|
|
||||||
isNew: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeOutboundPatternFormGroup(): FormGroup {
|
|
||||||
return this.formBuilder.group({
|
|
||||||
pattern: '',
|
|
||||||
constraint: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeInboundPatternFormGroup(): FormGroup {
|
|
||||||
return this.formBuilder.group({
|
|
||||||
pattern: '',
|
|
||||||
constraint: '',
|
|
||||||
automatic: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,266 +1,386 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<form (ngSubmit)="onSubmit()" [formGroup]="formModel">
|
<form (ngSubmit)="onSubmit()" [formGroup]="formModel">
|
||||||
<div class="d-flex">
|
<div class="d-flex mb-5">
|
||||||
<h2 class="flex-grow-1">{{ 'ldn-create-service.title' | translate }}</h2>
|
<h2 class="flex-grow-1">{{ 'ldn-create-service.title' | translate }}</h2>
|
||||||
|
</div>
|
||||||
|
<!-- In the name section -->
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="name">{{ 'ldn-new-service.form.label.name' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('name').invalid && formModel.get('name').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.name' | translate" class="form-control"
|
||||||
|
formControlName="name"
|
||||||
|
id="name"
|
||||||
|
name="name"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('name').invalid && formModel.get('name').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.name' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the description section -->
|
||||||
|
<div class="mb-5 mt-5 d-flex flex-column">
|
||||||
|
<label for="description">{{ 'ldn-new-service.form.label.description' | translate }}</label>
|
||||||
|
<textarea [placeholder]="'ldn-new-service.form.placeholder.description' | translate"
|
||||||
|
class="form-control" formControlName="description" id="description" name="description"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- In the url section -->
|
||||||
|
<div class="mb-5 mt-5">
|
||||||
|
<label for="url">{{ 'ldn-new-service.form.label.url' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('url').invalid && formModel.get('url').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.url' | translate" class="form-control"
|
||||||
|
formControlName="url"
|
||||||
|
id="url"
|
||||||
|
name="url"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('url').invalid && formModel.get('url').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.url' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- In the ldnUrl section -->
|
||||||
|
<div class="mb-5 mt-5">
|
||||||
|
<label for="ldnUrl">{{ 'ldn-new-service.form.label.ldnUrl' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.ldnUrl' | translate" class="form-control"
|
||||||
|
formControlName="ldnUrl"
|
||||||
|
id="ldnUrl"
|
||||||
|
name="ldnUrl"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.ldnurl' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- In the score section -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="score">{{ 'ldn-new-service.form.label.score' | translate }}</label>
|
||||||
|
<input [class.invalid-field]="formModel.get('score').invalid && formModel.get('score').touched"
|
||||||
|
[placeholder]="'ldn-new-service.form.placeholder.score' | translate" formControlName="score"
|
||||||
|
id="score"
|
||||||
|
name="score"
|
||||||
|
class="form-control"
|
||||||
|
type="text">
|
||||||
|
<div *ngIf="formModel.get('score').invalid && formModel.get('score').touched" class="error-text">
|
||||||
|
{{ 'ldn-new-service.form.error.score' | translate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the Inbound Patterns Labels section -->
|
||||||
|
<div class="row mb-2 mt-5">
|
||||||
|
<div class="col">
|
||||||
|
<label>{{ 'ldn-new-service.form.label.inboundPattern' | translate }} </label>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="!!(formModel.get('notifyServiceInboundPatterns')['controls'][0]?.value?.pattern)">
|
||||||
|
<div class="col">
|
||||||
|
<label>{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
||||||
</div>
|
</div>
|
||||||
<!-- In the name section -->
|
<div class="col-sm-1">
|
||||||
<div class="mb-2">
|
<label class="">{{ 'ldn-new-service.form.label.automatic' | translate }}</label>
|
||||||
<label for="name">{{ 'ldn-new-service.form.label.name' | translate }}</label>
|
|
||||||
<input [class.invalid-field]="formModel.get('name').invalid && formModel.get('name').touched"
|
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.name' | translate" formControlName="name" id="name"
|
|
||||||
name="name"
|
|
||||||
type="text">
|
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="col-sm-1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<!-- In the Inbound Patterns section -->
|
||||||
|
<div *ngFor="let patternGroup of formModel.get('notifyServiceInboundPatterns')['controls']; let i = index"
|
||||||
</div>
|
formGroupName="notifyServiceInboundPatterns">
|
||||||
|
|
||||||
<!-- In the description section -->
|
<ng-container [formGroupName]="i">
|
||||||
<div class="mb-2 d-flex flex-column">
|
|
||||||
<label for="description">{{ 'ldn-new-service.form.label.description' | translate }}</label>
|
|
||||||
<textarea [placeholder]="'ldn-new-service.form.placeholder.description' | translate"
|
|
||||||
formControlName="description" id="description" name="description"></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In the url section -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="url">{{ 'ldn-new-service.form.label.url' | translate }}</label>
|
|
||||||
<input [class.invalid-field]="formModel.get('url').invalid && formModel.get('url').touched"
|
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.url' | translate" formControlName="url" id="url"
|
|
||||||
name="url"
|
|
||||||
type="text">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In the ldnUrl section -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="ldnUrl">{{ 'ldn-new-service.form.label.ldnUrl' | translate }}</label>
|
|
||||||
<input [class.invalid-field]="formModel.get('ldnUrl').invalid && formModel.get('ldnUrl').touched"
|
|
||||||
[placeholder]="'ldn-new-service.form.placeholder.ldnUrl' | translate" formControlName="ldnUrl"
|
|
||||||
id="ldnUrl"
|
|
||||||
name="ldnUrl"
|
|
||||||
type="text">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In the Inbound Patterns section -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<label>{{ 'ldn-new-service.form.label.inboundPattern' | translate }} </label>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<label class="label-box">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm1 ">
|
|
||||||
<label class="label-box-2">{{ 'ldn-new-service.form.label.automatic' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngFor="let patternGroup of formModel.get('notifyServiceInboundPatterns')['controls']; let i = index"
|
|
||||||
formGroupName="notifyServiceInboundPatterns">
|
|
||||||
|
|
||||||
<ng-container [formGroupName]="i">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row mb-1">
|
<div class="row mb-1">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<select #inboundPattern formControlName="pattern" id="additionalInboundPattern{{i}}"
|
<div #inboundPatternDropdown="ngbDropdown" class="w-100" id="additionalInboundPattern{{i}}" ngbDropdown
|
||||||
name="additionalInboundPattern{{i}}" required>
|
placement="bottom-start">
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.inboundPattern' | translate }}</option>
|
<div class="position-relative right-addon" role="combobox">
|
||||||
<option *ngFor="let pattern of inboundPatterns"
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
[ngValue]="pattern.name">{{ pattern.name }}</option>
|
ngbDropdownToggle>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
</i>
|
||||||
<div class="col">
|
<input
|
||||||
<ng-container *ngIf="inboundPattern.value">
|
(click)="inboundPatternDropdown.open();"
|
||||||
<select formControlName="constraint" id="constraint{{i}}" name="constraint{{i}}">
|
[readonly]="true"
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.selectedItemFilter' | translate }}</option>
|
[value]="selectedInboundPatterns"
|
||||||
<option *ngFor="let itemFilter of (itemfiltersRD$ | async)?.payload?.page"
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
[value]="itemFilter.id">{{ itemFilter.id }}</option>
|
formControlName="patternLabel"
|
||||||
</select>
|
id="inboundPatternDropdownButton"
|
||||||
</ng-container>
|
ngbDropdownAnchor
|
||||||
</div>
|
type="text"
|
||||||
|
/>
|
||||||
<div [style.visibility]="inboundPattern.value ? 'visible' : 'hidden'" class="col-sm-1">
|
<div aria-labelledby="inboundPatternDropdownButton"
|
||||||
<input formControlName="automatic" hidden id="automatic{{i}}" name="automatic{{i}}"
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
type="checkbox">
|
ngbDropdownMenu>
|
||||||
<div (click)="toggleAutomatic(i)"
|
<div class="scrollable-menu" role="listbox">
|
||||||
[class.checked]="formModel.get('notifyServiceInboundPatterns.' + i + '.automatic').value"
|
<button (click)="selectInboundPattern(pattern, i); $event.stopPropagation()"
|
||||||
class="toggle-switch">
|
*ngFor="let pattern of inboundPatterns"
|
||||||
<div class="slider"></div>
|
[title]="'ldn-service.form.pattern.' + pattern + '.description' | translate"
|
||||||
</div>
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
</div>
|
ngbDropdownItem
|
||||||
|
type="button">
|
||||||
<div class="col-sm-1">
|
<div>{{ 'ldn-service.form.pattern.' + pattern + '.label' | translate }}</div>
|
||||||
<button (click)="removeInboundPattern(i)" class="btn btn-outline-dark trash-button">
|
<div
|
||||||
<i class="fas fa-trash"></i>
|
class="small-text">{{ 'ldn-service.form.pattern.' + pattern + '.description' | translate }}</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<span (click)="addInboundPattern()"
|
|
||||||
class="add-pattern-link mb-2">{{ 'ldn-new-service.form.label.addPattern' | translate }}</span>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In the Outbound Patterns section -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<label>{{ 'ldn-new-service.form.label.outboundPattern' | translate }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
</div>
|
||||||
<label class="label-box">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1 ">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1 ">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngFor="let patternGroup of formModel.get('notifyServiceOutboundPatterns')['controls']; let i = index"
|
|
||||||
formGroupName="notifyServiceOutboundPatterns">
|
|
||||||
|
|
||||||
<ng-container [formGroupName]="i">
|
<div class="col">
|
||||||
|
<ng-container
|
||||||
<!-- Input elements in a separate row -->
|
*ngIf="!!(formModel.get('notifyServiceInboundPatterns')['controls'][i].value.pattern)">
|
||||||
<div class="row mb-1">
|
<div #inboundItemfilterDropdown="ngbDropdown" class="w-100" id="constraint{{i}}" ngbDropdown
|
||||||
<div class="col">
|
placement="bottom-start">
|
||||||
<select #outboundPattern formControlName="pattern" id="additionalOutboundPattern{{i}}"
|
<div class="position-relative right-addon" role="combobox">
|
||||||
name="additionalOutboundPattern{{i}}"
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
required>
|
ngbDropdownToggle></i>
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.outboundPattern' | translate }}</option>
|
<input
|
||||||
<option *ngFor="let pattern of outboundPatterns"
|
(click)="inboundItemfilterDropdown.open();"
|
||||||
[ngValue]="pattern.name">{{ pattern.name }}</option>
|
[readonly]="true"
|
||||||
</select>
|
[value]="selectedInboundItemfilters"
|
||||||
</div>
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
<div class="col">
|
formControlName="constraint"
|
||||||
<ng-container *ngIf="outboundPattern.value">
|
id="inboundItemfilterDropdown"
|
||||||
<select formControlName="constraint" id="constraint{{i}}" name="constraint{{i}}">
|
ngbDropdownAnchor
|
||||||
<option value="">{{ 'ldn-new-service.form.label.placeholder.selectedItemFilter' | translate }}</option>
|
type="text"
|
||||||
<option *ngFor="let itemFilter of (itemfiltersRD$ | async)?.payload?.page"
|
/>
|
||||||
[value]="itemFilter.id">{{ itemFilter.id }}</option>
|
<div aria-labelledby="inboundItemfilterDropdownButton"
|
||||||
</select>
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
</ng-container>
|
ngbDropdownMenu>
|
||||||
</div>
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectInboundItemFilter(constraint.id, i); $event.stopPropagation() "
|
||||||
<div [style.visibility]="'hidden'" class="col-sm1">
|
*ngFor="let constraint of (itemfiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||||
<input hidden id="automatic{{i}}" name="automatic{{i}}" type="checkbox">
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
<div
|
ngbDropdownItem
|
||||||
class="toggle-switch">
|
type="button">
|
||||||
<div class="slider"></div>
|
<div>{{ constraint.id }}</div>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-1">
|
|
||||||
<button (click)="removeOutboundPattern(i)" class="btn btn-outline-dark trash-button">
|
|
||||||
<i class="fas fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div
|
||||||
|
[style.visibility]="formModel.get('notifyServiceInboundPatterns')['controls'][i]?.value?.pattern ? 'visible' : 'hidden'"
|
||||||
|
class="col-sm-1">
|
||||||
|
<input formControlName="automatic" hidden id="automatic{{i}}" name="automatic{{i}}"
|
||||||
|
type="checkbox">
|
||||||
|
<div (click)="toggleAutomatic(i)"
|
||||||
|
[class.checked]="formModel.get('notifyServiceInboundPatterns.' + i + '.automatic').value"
|
||||||
|
class="toggle-switch">
|
||||||
|
<div class="slider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<span (click)="addOutboundPattern()"
|
<div class="col-sm-1">
|
||||||
class="add-pattern-link">{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
<button (click)="removeInboundPattern(i)" class="btn btn-outline-dark trash-button">
|
||||||
</span>
|
<i class="fas fa-trash"></i>
|
||||||
<div class="mb-4">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div aria-label="Basic example" class="submission-form-footer mt-1 mb-1 position-sticky" role="group">
|
|
||||||
<button class="btn btn-primary" type="submit">
|
|
||||||
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
|
||||||
</button>
|
</button>
|
||||||
<div class="d-flex">
|
</div>
|
||||||
<button (click)="this.openResetFormModal(this.resetFormModal)" class="btn btn-danger" type="button">
|
|
||||||
<span><i class="fas fa-trash"></i> {{ 'submission.general.discard.submit' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span (click)="addInboundPattern()"
|
||||||
|
class="add-pattern-link mb-4">{{ 'ldn-new-service.form.label.addPattern' | translate }}</span>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
<!-- In the Outbound Patterns Labels section -->
|
||||||
|
<div class="row mb-1 mt-5">
|
||||||
|
<div class="col">
|
||||||
|
<label>{{ 'ldn-new-service.form.label.outboundPattern' | translate }}</label>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="!!(formModel.get('notifyServiceOutboundPatterns')['controls'][0]?.value?.pattern)">
|
||||||
|
<div class="col">
|
||||||
|
<label class="">{{ 'ldn-new-service.form.label.ItemFilter' | translate }}</label>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In the Outbound Patterns section -->
|
||||||
|
<div *ngFor="let patternGroup of formModel.get('notifyServiceOutboundPatterns')['controls']; let i = index"
|
||||||
|
formGroupName="notifyServiceOutboundPatterns">
|
||||||
|
|
||||||
|
<ng-container [formGroupName]="i">
|
||||||
|
|
||||||
|
<div class="row mb-1">
|
||||||
|
<div class="col">
|
||||||
|
<div #outboundPatternDropdown="ngbDropdown" class="w-100" id="additionalOutboundPattern{{i}}"
|
||||||
|
ngbDropdown
|
||||||
|
placement="bottom-start">
|
||||||
|
<div class="position-relative right-addon" role="combobox">
|
||||||
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
ngbDropdownToggle></i>
|
||||||
|
<input
|
||||||
|
(click)="outboundPatternDropdown.open();"
|
||||||
|
[readonly]="true"
|
||||||
|
[value]="selectedOutboundPatterns"
|
||||||
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
|
formControlName="patternLabel"
|
||||||
|
id="outboundPatternDropdownButton"
|
||||||
|
ngbDropdownAnchor
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
<div aria-labelledby="outboundPatternDropdownButton"
|
||||||
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
|
ngbDropdownMenu>
|
||||||
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectOutboundPattern(pattern, i); $event.stopPropagation()"
|
||||||
|
*ngFor="let pattern of outboundPatterns"
|
||||||
|
[title]="'ldn-service.form.pattern.' + pattern + '.description' | translate"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
ngbDropdownItem
|
||||||
|
type="button">
|
||||||
|
<div>{{ 'ldn-service.form.pattern.' + pattern + '.label' | translate }}</div>
|
||||||
|
<div
|
||||||
|
class="small-text">{{ 'ldn-service.form.pattern.' + pattern + '.description' | translate }}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<ng-container
|
||||||
|
*ngIf="!!(formModel.get('notifyServiceOutboundPatterns')['controls'][i].value.pattern)">
|
||||||
|
<div #outboundItemfilterDropdown="ngbDropdown" class="w-100" id="constraint{{i}}"
|
||||||
|
ngbDropdown
|
||||||
|
placement="bottom-start">
|
||||||
|
<div class="position-relative right-addon" role="combobox">
|
||||||
|
<i aria-hidden="true" class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
ngbDropdownToggle></i>
|
||||||
|
<input
|
||||||
|
(click)="outboundItemfilterDropdown.open();"
|
||||||
|
[readonly]="true"
|
||||||
|
[value]="selectedOutboundItemfilters"
|
||||||
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
|
formControlName="constraint"
|
||||||
|
id="outboundItemfilterDropdown"
|
||||||
|
ngbDropdownAnchor
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
<div aria-labelledby="outboundItemfilterDropdownButton"
|
||||||
|
class="dropdown-menu scrollable-dropdown-menu w-100 "
|
||||||
|
ngbDropdownMenu>
|
||||||
|
<div class="scrollable-menu" role="listbox">
|
||||||
|
<button (click)="selectOutboundItemFilter(constraint.id, i); $event.stopPropagation()"
|
||||||
|
*ngFor="let constraint of (itemfiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
ngbDropdownItem
|
||||||
|
type="button">
|
||||||
|
<div>{{ constraint.id }}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [style.visibility]="'hidden'" class="col-sm-1">
|
||||||
|
<input hidden id="automatic{{i}}" name="automatic{{i}}"
|
||||||
|
type="checkbox">
|
||||||
|
<div
|
||||||
|
class="toggle-switch">
|
||||||
|
<div class="slider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-1">
|
||||||
|
<button (click)="removeOutboundPattern(i)" class="btn btn-outline-dark trash-button">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div (click)="addOutboundPattern()"
|
||||||
|
class="add-pattern-link mb-4">{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="submission-form-footer my-1 position-sticky d-flex justify-content-between" role="group">
|
||||||
|
<button (click)="this.openResetFormModal(this.resetFormModal)" class="btn btn-danger" type="button">
|
||||||
|
<span><i class="fas fa-trash"></i> {{ 'submission.general.discard.submit' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary" type="submit">
|
||||||
|
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #confirmModal>
|
<ng-template #confirmModal>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div>
|
<div>
|
||||||
<h4>{{'service.overview.create.modal' | translate }}</h4>
|
<h4>{{'service.overview.create.modal' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="closeModal()" aria-label="Close"
|
<button (click)="closeModal()" aria-label="Close"
|
||||||
class="close" type="button">
|
class="close" type="button">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div>
|
|
||||||
{{ 'service.create.body' | translate }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
<button (click)="closeModal()" class="btn btn-danger"
|
|
||||||
id="delete-confirm">{{ 'service.refuse.create' | translate }}
|
|
||||||
</button>
|
|
||||||
<button (click)="createService()"
|
|
||||||
class="btn btn-primary mr-2 custom-btn">{{ 'service.confirm.create' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
|
{{ 'service.overview.create.body' | translate }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<button (click)="closeModal()" class="btn btn-danger mr-2 "
|
||||||
|
id="delete-confirm">{{ 'service.refuse.create' | translate }}
|
||||||
|
</button>
|
||||||
|
<button (click)="createService()"
|
||||||
|
class="btn btn-primary">{{ 'service.confirm.create' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #resetFormModal>
|
<ng-template #resetFormModal>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div>
|
<div>
|
||||||
<h4>{{'service.create.reset-form.modal' | translate }}</h4>
|
<h4>{{'service.overview.reset-form.modal' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="closeModal()" aria-label="Close"
|
<button (click)="closeModal()" aria-label="Close"
|
||||||
class="close" type="button">
|
class="close" type="button">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div>
|
|
||||||
{{ 'service.create.reset-form.body' | translate }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
<button (click)="resetFormAndLeave()"
|
|
||||||
class="btn btn-primary mr-2 custom-btn"
|
|
||||||
id="reset-confirm">{{ 'service.overview.reset-form.reset-return' | translate }}
|
|
||||||
</button>
|
|
||||||
<button (click)="closeModal()" class="btn btn-danger"
|
|
||||||
id="reset-delete">{{ 'service.overview.reset-form.reset-confirm' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
|
{{ 'service.overview.reset-form.body' | translate }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<button (click)="resetFormAndLeave()"
|
||||||
|
class="btn btn-primary mr-2"
|
||||||
|
id="reset-confirm">{{ 'service.overview.reset-form.reset-return' | translate }}
|
||||||
|
</button>
|
||||||
|
<button (click)="closeModal()" class="btn btn-danger"
|
||||||
|
id="reset-delete">{{ 'service.overview.reset-form.reset-confirm' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,8 +1,13 @@
|
|||||||
|
@import '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.scss';
|
||||||
|
@import '../../../shared/form/form.component.scss';
|
||||||
|
|
||||||
form {
|
form {
|
||||||
max-width: 800px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
@@ -30,7 +35,6 @@ textarea {
|
|||||||
.add-pattern-link {
|
.add-pattern-link {
|
||||||
color: #0048ff;
|
color: #0048ff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.remove-pattern-link {
|
.remove-pattern-link {
|
||||||
@@ -39,6 +43,11 @@ textarea {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.small-text {
|
||||||
|
font-size: 0.7em;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
.status-checkbox {
|
.status-checkbox {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
@@ -49,6 +58,12 @@ textarea {
|
|||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
color: red;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -99,24 +114,6 @@ textarea {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-box {
|
|
||||||
margin-left: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-box-2 {
|
|
||||||
margin-left: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-box-3 {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form button.btn.btn-primary[type="submit"] {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submission-form-footer {
|
.submission-form-footer {
|
||||||
border-radius: var(--bs-card-border-radius);
|
border-radius: var(--bs-card-border-radius);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@@ -1,25 +1,88 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
import { LdnServiceFormComponent } from './ldn-service-form.component';
|
import {LdnServiceFormComponent} from './ldn-service-form.component';
|
||||||
|
import {FormBuilder, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
import {NgbDropdownModule, NgbModal, NgbModalModule} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import {TranslateModule, TranslateService} from '@ngx-translate/core';
|
||||||
|
import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service';
|
||||||
|
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
|
||||||
|
import {NotificationsService} from 'src/app/shared/notifications/notifications.service';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
import {RouterStub} from 'src/app/shared/testing/router.stub';
|
||||||
|
import {createPaginatedList} from 'src/app/shared/testing/utils.test';
|
||||||
|
import {Itemfilter} from '../ldn-services-model/ldn-service-itemfilters';
|
||||||
|
import {createSuccessfulRemoteDataObject$} from 'src/app/shared/remote-data.utils';
|
||||||
|
import {of} from 'rxjs';
|
||||||
|
import {EventEmitter} from '@angular/core';
|
||||||
|
|
||||||
describe('LdnServiceFormComponent', () => {
|
describe('LdnServiceFormComponent', () => {
|
||||||
let component: LdnServiceFormComponent;
|
let component: LdnServiceFormComponent;
|
||||||
let fixture: ComponentFixture<LdnServiceFormComponent>;
|
let fixture: ComponentFixture<LdnServiceFormComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
let ldnServicesService: any;
|
||||||
await TestBed.configureTestingModule({
|
let ldnItemfiltersService: any;
|
||||||
declarations: [LdnServiceFormComponent]
|
let notificationsService: any;
|
||||||
})
|
|
||||||
.compileComponents();
|
const itemFiltersRdPL$ = createSuccessfulRemoteDataObject$(createPaginatedList([new Itemfilter()]));
|
||||||
|
|
||||||
|
const translateServiceStub = {
|
||||||
|
get: () => of('translated-text'),
|
||||||
|
instant: () => 'translated-text',
|
||||||
|
onLangChange: new EventEmitter(),
|
||||||
|
onTranslationChange: new EventEmitter(),
|
||||||
|
onDefaultLangChange: new EventEmitter()
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
ldnItemfiltersService = jasmine.createSpyObj('ldnItemfiltersService', {
|
||||||
|
findAll: jasmine.createSpy('findAll'),
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
ldnServicesService = jasmine.createSpyObj('ldnServicesService', {
|
||||||
fixture = TestBed.createComponent(LdnServiceFormComponent);
|
create: jasmine.createSpy('create'),
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
notificationsService = jasmine.createSpyObj('notificationsService', {
|
||||||
expect(component).toBeTruthy();
|
success: jasmine.createSpy('success'),
|
||||||
|
error: jasmine.createSpy('error'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
RouterTestingModule,
|
||||||
|
NgbModalModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
NgbDropdownModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{provide: LdnItemfiltersService, useValue: ldnItemfiltersService},
|
||||||
|
{provide: LdnServicesService, useValue: ldnServicesService},
|
||||||
|
{provide: NotificationsService, useValue: notificationsService},
|
||||||
|
{provide: TranslateService, useValue: translateServiceStub},
|
||||||
|
{provide: Router, useValue: new RouterStub()},
|
||||||
|
{
|
||||||
|
provide: NgbModal, useValue: {
|
||||||
|
open: () => {/*comment*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FormBuilder
|
||||||
|
],
|
||||||
|
declarations: [LdnServiceFormComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LdnServiceFormComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
ldnItemfiltersService.findAll.and.returnValue(itemFiltersRdPL$);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,222 +1,369 @@
|
|||||||
import {
|
import {ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild} from '@angular/core';
|
||||||
ChangeDetectorRef,
|
import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
Component,
|
import {Router} from '@angular/router';
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
TemplateRef,
|
|
||||||
ViewChild
|
|
||||||
} from '@angular/core';
|
|
||||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
import { LdnServicesService } from '../ldn-services-data/ldn-services-data.service';
|
|
||||||
import { notifyPatterns } from '../ldn-services-patterns/ldn-service-coar-patterns';
|
|
||||||
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
|
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
|
||||||
import { LdnService } from '../ldn-services-model/ldn-services.model';
|
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
|
||||||
import { Itemfilter } from '../ldn-services-model/ldn-service-itemfilters';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
|
||||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
|
||||||
import { LdnItemfiltersService } from '../ldn-services-data/ldn-itemfilters-data.service';
|
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
|
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
|
||||||
|
import {notifyPatterns} from '../ldn-services-patterns/ldn-service-coar-patterns';
|
||||||
|
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
|
||||||
|
import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||||
|
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
|
||||||
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
|
import {Itemfilter} from '../ldn-services-model/ldn-service-itemfilters';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {FindListOptions} from '../../../core/data/find-list-options.model';
|
||||||
|
import {PaginationComponentOptions} from '../../../shared/pagination/pagination-component-options.model';
|
||||||
|
import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service';
|
||||||
|
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Angular component representing the form for creating or editing LDN services.
|
||||||
|
* This component handles the creation, validation, and submission of LDN service data.
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-ldn-service-form',
|
selector: 'ds-ldn-service-form',
|
||||||
templateUrl: './ldn-service-form.component.html',
|
templateUrl: './ldn-service-form.component.html',
|
||||||
styleUrls: ['./ldn-service-form.component.scss'],
|
styleUrls: ['./ldn-service-form.component.scss'],
|
||||||
animations: [
|
animations: [
|
||||||
trigger('toggleAnimation', [
|
trigger('toggleAnimation', [
|
||||||
state('true', style({})),
|
state('true', style({})),
|
||||||
state('false', style({})),
|
state('false', style({})),
|
||||||
transition('true <=> false', animate('300ms ease-in')),
|
transition('true <=> false', animate('300ms ease-in')),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class LdnServiceFormComponent implements OnInit {
|
export class LdnServiceFormComponent implements OnInit {
|
||||||
formModel: FormGroup;
|
formModel: FormGroup;
|
||||||
@ViewChild('confirmModal', {static: true}) confirmModal: TemplateRef<any>;
|
@ViewChild('confirmModal', {static: true}) confirmModal: TemplateRef<any>;
|
||||||
@ViewChild('resetFormModal', {static: true}) resetFormModal: TemplateRef<any>;
|
@ViewChild('resetFormModal', {static: true}) resetFormModal: TemplateRef<any>;
|
||||||
public inboundPatterns: object[] = notifyPatterns;
|
public inboundPatterns: string[] = notifyPatterns;
|
||||||
public outboundPatterns: object[] = notifyPatterns;
|
public outboundPatterns: string[] = notifyPatterns;
|
||||||
itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
||||||
config: FindListOptions = Object.assign(new FindListOptions(), {
|
config: FindListOptions = Object.assign(new FindListOptions(), {
|
||||||
elementsPerPage: 20
|
elementsPerPage: 20
|
||||||
|
});
|
||||||
|
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||||
|
id: 'po',
|
||||||
|
pageSize: 20
|
||||||
|
});
|
||||||
|
@Input() public name: string;
|
||||||
|
@Input() public description: string;
|
||||||
|
@Input() public url: string;
|
||||||
|
@Input() public score: string;
|
||||||
|
@Input() public ldnUrl: string;
|
||||||
|
@Input() public inboundPattern: string;
|
||||||
|
@Input() public outboundPattern: string;
|
||||||
|
@Input() public constraint: string;
|
||||||
|
@Input() public automatic: boolean;
|
||||||
|
@Input() public headerKey: string;
|
||||||
|
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
||||||
|
@Output() cancelForm: EventEmitter<any> = new EventEmitter();
|
||||||
|
selectedOutboundPatterns: string[];
|
||||||
|
selectedInboundPatterns: string[];
|
||||||
|
selectedInboundItemfilters: string[];
|
||||||
|
selectedOutboundItemfilters: string[];
|
||||||
|
hasInboundPattern: boolean;
|
||||||
|
hasOutboundPattern: boolean;
|
||||||
|
isScoreValid: boolean;
|
||||||
|
private modalRef: any;
|
||||||
|
private selectPatternDefaultLabeli18Key = 'ldn-service.form.label.placeholder.default-select';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private ldnServicesService: LdnServicesService,
|
||||||
|
private ldnItemfiltersService: LdnItemfiltersService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private cdRef: ChangeDetectorRef,
|
||||||
|
protected modalService: NgbModal,
|
||||||
|
) {
|
||||||
|
|
||||||
|
this.formModel = this.formBuilder.group({
|
||||||
|
enabled: true,
|
||||||
|
id: [''],
|
||||||
|
name: ['', Validators.required],
|
||||||
|
description: [''],
|
||||||
|
url: ['', Validators.required],
|
||||||
|
score: ['', [Validators.required, Validators.pattern('^0*(\.[0-9]+)?$|^1(\.0+)?$')]],
|
||||||
|
ldnUrl: ['', Validators.required],
|
||||||
|
inboundPattern: [''],
|
||||||
|
outboundPattern: [''],
|
||||||
|
constraintPattern: [''],
|
||||||
|
notifyServiceInboundPatterns: this.formBuilder.array([this.createInboundPatternFormGroup()]),
|
||||||
|
notifyServiceOutboundPatterns: this.formBuilder.array([this.createOutboundPatternFormGroup()]),
|
||||||
|
type: LDN_SERVICE.value,
|
||||||
});
|
});
|
||||||
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
}
|
||||||
id: 'po',
|
|
||||||
pageSize: 20
|
ngOnInit(): void {
|
||||||
|
this.setItemfilters();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the item filters by fetching and observing the paginated list of item filters.
|
||||||
|
*/
|
||||||
|
setItemfilters() {
|
||||||
|
this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe(
|
||||||
|
getFirstCompletedRemoteData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the form submission by opening the confirmation modal.
|
||||||
|
*/
|
||||||
|
onSubmit() {
|
||||||
|
this.openConfirmModal(this.confirmModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the confirmation modal.
|
||||||
|
*
|
||||||
|
* @param {any} content - The content of the modal.
|
||||||
|
*/
|
||||||
|
openConfirmModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the reset form modal.
|
||||||
|
*
|
||||||
|
* @param {any} content - The content of the modal.
|
||||||
|
*/
|
||||||
|
openResetFormModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the creation of an LDN service by retrieving and validating form fields,
|
||||||
|
* and submitting the form data to the LDN services endpoint.
|
||||||
|
*/
|
||||||
|
createService() {
|
||||||
|
this.formModel.get('name').markAsTouched();
|
||||||
|
this.formModel.get('score').markAsTouched();
|
||||||
|
this.formModel.get('url').markAsTouched();
|
||||||
|
this.formModel.get('ldnUrl').markAsTouched();
|
||||||
|
this.formModel.get('notifyServiceInboundPatterns').markAsTouched();
|
||||||
|
this.formModel.get('notifyServiceOutboundPatterns').markAsTouched();
|
||||||
|
|
||||||
|
const name = this.formModel.get('name').value;
|
||||||
|
const url = this.formModel.get('url').value;
|
||||||
|
const score = this.formModel.get('score').value;
|
||||||
|
const ldnUrl = this.formModel.get('ldnUrl').value;
|
||||||
|
|
||||||
|
const hasInboundPattern = this.checkPatterns(this.formModel.get('notifyServiceInboundPatterns') as FormArray);
|
||||||
|
const hasOutboundPattern = this.checkPatterns(this.formModel.get('notifyServiceOutboundPatterns') as FormArray);
|
||||||
|
|
||||||
|
if (!name || !url || !ldnUrl || !score || (!hasInboundPattern && !hasOutboundPattern)) {
|
||||||
|
this.closeModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.formModel.value.notifyServiceInboundPatterns = this.formModel.value.notifyServiceInboundPatterns.map((pattern: {
|
||||||
|
pattern: string;
|
||||||
|
patternLabel: string
|
||||||
|
}) => {
|
||||||
|
const {patternLabel, ...rest} = pattern;
|
||||||
|
return rest;
|
||||||
});
|
});
|
||||||
@Input() public name: string;
|
|
||||||
@Input() public description: string;
|
|
||||||
@Input() public url: string;
|
|
||||||
@Input() public ldnUrl: string;
|
|
||||||
@Input() public inboundPattern: string;
|
|
||||||
@Input() public outboundPattern: string;
|
|
||||||
@Input() public constraint: string;
|
|
||||||
@Input() public automatic: boolean;
|
|
||||||
@Input() public headerKey: string;
|
|
||||||
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
|
||||||
@Output() cancelForm: EventEmitter<any> = new EventEmitter();
|
|
||||||
private modalRef: any;
|
|
||||||
|
|
||||||
constructor(
|
this.formModel.value.notifyServiceOutboundPatterns = this.formModel.value.notifyServiceOutboundPatterns.map((pattern: {
|
||||||
private ldnServicesService: LdnServicesService,
|
pattern: string;
|
||||||
private ldnItemfiltersService: LdnItemfiltersService,
|
patternLabel: string
|
||||||
private formBuilder: FormBuilder,
|
}) => {
|
||||||
private router: Router,
|
const {patternLabel, ...rest} = pattern;
|
||||||
private notificationsService: NotificationsService,
|
return rest;
|
||||||
private translateService: TranslateService,
|
});
|
||||||
private cdRef: ChangeDetectorRef,
|
|
||||||
protected modalService: NgbModal,
|
|
||||||
) {
|
|
||||||
|
|
||||||
this.formModel = this.formBuilder.group({
|
const values = this.formModel.value;
|
||||||
enabled: true,
|
|
||||||
id: [''],
|
|
||||||
name: ['', Validators.required],
|
|
||||||
description: [''],
|
|
||||||
url: ['', Validators.required],
|
|
||||||
ldnUrl: ['', Validators.required],
|
|
||||||
inboundPattern: [''],
|
|
||||||
outboundPattern: [''],
|
|
||||||
constraintPattern: [''],
|
|
||||||
notifyServiceInboundPatterns: this.formBuilder.array([this.createInboundPatternFormGroup()]),
|
|
||||||
notifyServiceOutboundPatterns: this.formBuilder.array([this.createOutboundPatternFormGroup()]),
|
|
||||||
type: LDN_SERVICE.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
const ldnServiceData = this.ldnServicesService.create(values);
|
||||||
this.setItemfilters();
|
|
||||||
|
|
||||||
}
|
ldnServiceData.pipe(
|
||||||
|
getFirstCompletedRemoteData()
|
||||||
|
).subscribe((rd: RemoteData<LdnService>) => {
|
||||||
|
if (rd.hasSucceeded) {
|
||||||
|
this.notificationsService.success(this.translateService.get('ldn-service-notification.created.success.title'),
|
||||||
|
this.translateService.get('ldn-service-notification.created.success.body'));
|
||||||
|
|
||||||
setItemfilters() {
|
|
||||||
this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe(
|
|
||||||
getFirstCompletedRemoteData());
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
this.openConfirmModal(this.confirmModal);
|
|
||||||
}
|
|
||||||
|
|
||||||
openConfirmModal(content) {
|
|
||||||
this.modalRef = this.modalService.open(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
openResetFormModal(content) {
|
|
||||||
this.modalRef = this.modalService.open(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
createService() {
|
|
||||||
this.formModel.get('name').markAsTouched();
|
|
||||||
this.formModel.get('url').markAsTouched();
|
|
||||||
this.formModel.get('ldnUrl').markAsTouched();
|
|
||||||
|
|
||||||
const name = this.formModel.get('name').value;
|
|
||||||
const url = this.formModel.get('url').value;
|
|
||||||
const ldnUrl = this.formModel.get('ldnUrl').value;
|
|
||||||
|
|
||||||
if (!name || !url || !ldnUrl) {
|
|
||||||
this.closeModal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const values = this.formModel.value;
|
|
||||||
|
|
||||||
const inboundPatternValue = this.formModel.get('inboundPattern').value;
|
|
||||||
const outboundPatternValue = this.formModel.get('outboundPattern').value;
|
|
||||||
|
|
||||||
if (inboundPatternValue === '') {
|
|
||||||
values.notifyServiceInboundPatterns = [];
|
|
||||||
}
|
|
||||||
if (outboundPatternValue === '') {
|
|
||||||
values.notifyServiceOutboundPatterns = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const ldnServiceData = this.ldnServicesService.create(values);
|
|
||||||
|
|
||||||
ldnServiceData.pipe(
|
|
||||||
getFirstCompletedRemoteData()
|
|
||||||
).subscribe((rd: RemoteData<LdnService>) => {
|
|
||||||
if (rd.hasSucceeded) {
|
|
||||||
this.notificationsService.success(this.translateService.get('ldn-service-notification.created.success.title'),
|
|
||||||
this.translateService.get('ldn-service-notification.created.success.body'));
|
|
||||||
|
|
||||||
this.sendBack();
|
|
||||||
this.closeModal();
|
|
||||||
} else {
|
|
||||||
this.notificationsService.error(this.translateService.get('notification.created.failure'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
resetFormAndLeave() {
|
|
||||||
this.sendBack();
|
this.sendBack();
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
}
|
} else {
|
||||||
|
this.notificationsService.error(this.translateService.get('ldn-service-notification.created.failure.title'),
|
||||||
|
this.translateService.get('ldn-service-notification.created.failure.body'));
|
||||||
|
this.closeModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
closeModal() {
|
/**
|
||||||
this.modalRef.close();
|
* Checks if at least one pattern in the specified form array has a value.
|
||||||
this.cdRef.detectChanges();
|
*
|
||||||
|
* @param {FormArray} formArray - The form array containing patterns to check.
|
||||||
|
* @returns {boolean} - True if at least one pattern has a value, otherwise false.
|
||||||
|
*/
|
||||||
|
checkPatterns(formArray: FormArray): boolean {
|
||||||
|
for (let i = 0; i < formArray.length; i++) {
|
||||||
|
const pattern = formArray.at(i).get('pattern').value;
|
||||||
|
if (pattern) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addInboundPattern() {
|
/**
|
||||||
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
* Closes the currently open modal and returns to the services directory..
|
||||||
notifyServiceInboundPatternsArray.push(this.createInboundPatternFormGroup());
|
*/
|
||||||
|
resetFormAndLeave() {
|
||||||
|
this.sendBack();
|
||||||
|
this.closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the currently open modal and triggers change detection.
|
||||||
|
*/
|
||||||
|
closeModal() {
|
||||||
|
this.modalRef.close();
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new inbound pattern form group to the notifyServiceInboundPatterns form array.
|
||||||
|
*/
|
||||||
|
addInboundPattern() {
|
||||||
|
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||||
|
notifyServiceInboundPatternsArray.push(this.createInboundPatternFormGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the inbound pattern form group at the specified index from the notifyServiceInboundPatterns form array.
|
||||||
|
*
|
||||||
|
* @param {number} index - The index of the inbound pattern form group to remove.
|
||||||
|
* @memberof LdnServiceFormComponent
|
||||||
|
*/
|
||||||
|
removeInboundPattern(index: number) {
|
||||||
|
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||||
|
notifyServiceInboundPatternsArray.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new outbound pattern form group to the notifyServiceOutboundPatterns form array.
|
||||||
|
*/
|
||||||
|
addOutboundPattern() {
|
||||||
|
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
||||||
|
notifyServiceOutboundPatternsArray.push(this.createOutboundPatternFormGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the outbound pattern form group at the specified index from the notifyServiceOutboundPatterns form array.
|
||||||
|
*
|
||||||
|
* @param {number} index - The index of the outbound pattern form group to remove.
|
||||||
|
*/
|
||||||
|
removeOutboundPattern(index: number) {
|
||||||
|
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
||||||
|
notifyServiceOutboundPatternsArray.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the value of the 'automatic' control at the specified index in the notifyServiceInboundPatterns form array.
|
||||||
|
*
|
||||||
|
* @param {number} i - The index of the 'automatic' control to toggle.
|
||||||
|
* @memberof LdnServiceFormComponent
|
||||||
|
*/
|
||||||
|
toggleAutomatic(i: number) {
|
||||||
|
const automaticControl = this.formModel.get(`notifyServiceInboundPatterns.${i}.automatic`);
|
||||||
|
if (automaticControl) {
|
||||||
|
automaticControl.setValue(!automaticControl.value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
removeInboundPattern(index: number) {
|
/**
|
||||||
const notifyServiceInboundPatternsArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
* Selects an outbound pattern for a specific index in the notifyServiceOutboundPatterns form array.
|
||||||
notifyServiceInboundPatternsArray.removeAt(index);
|
*
|
||||||
}
|
* @param {string} patternValue - The selected pattern value.
|
||||||
|
* @param {number} index - The index of the outbound pattern in the form array.
|
||||||
|
*/
|
||||||
|
selectOutboundPattern(patternValue: string, index: number): void {
|
||||||
|
const patternArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray);
|
||||||
|
patternArray.controls[index].patchValue({pattern: patternValue});
|
||||||
|
patternArray.controls[index].patchValue({patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternValue + '.label')});
|
||||||
|
|
||||||
addOutboundPattern() {
|
}
|
||||||
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
|
||||||
notifyServiceOutboundPatternsArray.push(this.createOutboundPatternFormGroup());
|
|
||||||
}
|
|
||||||
|
|
||||||
removeOutboundPattern(index: number) {
|
/**
|
||||||
const notifyServiceOutboundPatternsArray = this.formModel.get('notifyServiceOutboundPatterns') as FormArray;
|
* Selects an inbound pattern for a specific index in the form array.
|
||||||
notifyServiceOutboundPatternsArray.removeAt(index);
|
*
|
||||||
}
|
* @param {string} patternValue - The selected pattern value.
|
||||||
|
* @param {number} index - The index of the inbound pattern in the form array.
|
||||||
|
*/
|
||||||
|
selectInboundPattern(patternValue: string, index: number): void {
|
||||||
|
const patternArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray);
|
||||||
|
patternArray.controls[index].patchValue({pattern: patternValue});
|
||||||
|
patternArray.controls[index].patchValue({patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternValue + '.label')});
|
||||||
|
|
||||||
toggleAutomatic(i: number) {
|
}
|
||||||
const automaticControl = this.formModel.get(`notifyServiceInboundPatterns.${i}.automatic`);
|
|
||||||
if (automaticControl) {
|
|
||||||
automaticControl.setValue(!automaticControl.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sendBack() {
|
/**
|
||||||
this.router.navigateByUrl('admin/ldn/services');
|
* Selects an inbound item filter for a specific index in the form array.
|
||||||
}
|
*
|
||||||
|
* @param {string} filterValue - The selected item filter value.
|
||||||
|
* @param {number} index - The index of the inbound item filter in the form array.
|
||||||
|
*/
|
||||||
|
selectInboundItemFilter(filterValue: string, index: number): void {
|
||||||
|
const filterArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray);
|
||||||
|
filterArray.controls[index].patchValue({constraint: filterValue});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects an outbound item filter for a specific index in the form array.
|
||||||
|
*
|
||||||
|
* @param {string} filterValue - The selected item filter value.
|
||||||
|
* @param {number} index - The index of the outbound item filter in the form array.
|
||||||
|
*/
|
||||||
|
selectOutboundItemFilter(filterValue: string, index: number) {
|
||||||
|
const filterArray = (this.formModel.get('notifyServiceOutboundPatterns') as FormArray);
|
||||||
|
filterArray.controls[index].patchValue({constraint: filterValue});
|
||||||
|
}
|
||||||
|
|
||||||
private createOutboundPatternFormGroup(): FormGroup {
|
/**
|
||||||
return this.formBuilder.group({
|
* Sends the user back to the LDN services list.
|
||||||
pattern: [''],
|
*/
|
||||||
constraint: [''],
|
private sendBack() {
|
||||||
});
|
this.router.navigateByUrl('admin/ldn/services');
|
||||||
}
|
}
|
||||||
|
|
||||||
private createInboundPatternFormGroup(): FormGroup {
|
/**
|
||||||
return this.formBuilder.group({
|
* Creates a form group for an outbound pattern in the notifyServiceOutboundPatterns form array.
|
||||||
pattern: [''],
|
*
|
||||||
constraint: [''],
|
* @private
|
||||||
automatic: false
|
* @returns {FormGroup} - The created form group.
|
||||||
});
|
*/
|
||||||
}
|
private createOutboundPatternFormGroup(): FormGroup {
|
||||||
|
return this.formBuilder.group({
|
||||||
|
pattern: [''],
|
||||||
|
constraint: [''],
|
||||||
|
patternLabel: this.translateService.instant(this.selectPatternDefaultLabeli18Key),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a form group for an inbound pattern in the notifyServiceInboundPatterns form array.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {FormGroup} - The created form group.
|
||||||
|
*/
|
||||||
|
private createInboundPatternFormGroup(): FormGroup {
|
||||||
|
return this.formBuilder.group({
|
||||||
|
pattern: [''],
|
||||||
|
constraint: [''],
|
||||||
|
automatic: false,
|
||||||
|
patternLabel: this.translateService.instant(this.selectPatternDefaultLabeli18Key),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
import { LdnServiceNewComponent } from './ldn-service-new.component';
|
import {LdnServiceNewComponent} from './ldn-service-new.component';
|
||||||
|
|
||||||
describe('LdnServiceNewComponent', () => {
|
describe('LdnServiceNewComponent', () => {
|
||||||
let component: LdnServiceNewComponent;
|
let component: LdnServiceNewComponent;
|
||||||
let fixture: ComponentFixture<LdnServiceNewComponent>;
|
let fixture: ComponentFixture<LdnServiceNewComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [LdnServiceNewComponent]
|
declarations: [LdnServiceNewComponent]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(LdnServiceNewComponent);
|
fixture = TestBed.createComponent(LdnServiceNewComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,27 +1,9 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { LdnService } from "../ldn-services-model/ldn-services.model";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import { ProcessDataService } from "../../../core/data/processes/process-data.service";
|
|
||||||
import { LinkService } from "../../../core/cache/builders/link.service";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-ldn-service-new',
|
selector: 'ds-ldn-service-new',
|
||||||
templateUrl: './ldn-service-new.component.html',
|
templateUrl: './ldn-service-new.component.html',
|
||||||
styleUrls: ['./ldn-service-new.component.scss']
|
styleUrls: ['./ldn-service-new.component.scss']
|
||||||
})
|
})
|
||||||
export class LdnServiceNewComponent implements OnInit {
|
export class LdnServiceNewComponent {
|
||||||
/**
|
|
||||||
* Emits preselected process if there is one
|
|
||||||
*/
|
|
||||||
ldnService$?: Observable<LdnService>;
|
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private processService: ProcessDataService, private linkService: LinkService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If there's an id parameter, use this the process with this identifier as presets for the form
|
|
||||||
*/
|
|
||||||
ngOnInit() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,69 +1,126 @@
|
|||||||
import { LdnService } from '../ldn-services-model/ldn-services.model';
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
|
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
import { Observable, of } from 'rxjs';
|
import {Observable, of} from 'rxjs';
|
||||||
// Create a mock data object for a single LDN notify service
|
import {createSuccessfulRemoteDataObject$} from '../../../shared/remote-data.utils';
|
||||||
|
|
||||||
export const mockLdnService: LdnService = {
|
export const mockLdnService: LdnService = {
|
||||||
id: 1,
|
uuid: '1',
|
||||||
name: 'Service Name',
|
enabled: false,
|
||||||
description: 'Service Description',
|
score: 0,
|
||||||
url: 'Service URL',
|
id: 1,
|
||||||
ldnUrl: 'Service LDN URL',
|
name: 'Service Name',
|
||||||
notifyServiceInboundPatterns: [
|
description: 'Service Description',
|
||||||
{
|
url: 'Service URL',
|
||||||
pattern: 'patternA',
|
ldnUrl: 'Service LDN URL',
|
||||||
constraint: 'itemFilterA',
|
notifyServiceInboundPatterns: [
|
||||||
automatic: false,
|
{
|
||||||
},
|
pattern: 'patternA',
|
||||||
{
|
constraint: 'itemFilterA',
|
||||||
pattern: 'patternB',
|
automatic: 'false',
|
||||||
constraint: 'itemFilterB',
|
|
||||||
automatic: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
notifyServiceOutboundPatterns: [
|
|
||||||
{
|
|
||||||
pattern: 'patternC',
|
|
||||||
constraint: 'itemFilterC',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: LDN_SERVICE,
|
|
||||||
_links: {
|
|
||||||
self: {
|
|
||||||
href: 'http://localhost/api/ldn/ldnservices/1',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pattern: 'patternB',
|
||||||
|
constraint: 'itemFilterB',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
notifyServiceOutboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'patternC',
|
||||||
|
constraint: 'itemFilterC',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: LDN_SERVICE,
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'http://localhost/api/ldn/ldnservices/1'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get self(): string {
|
||||||
|
return '';
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mockLdnServiceRD$ = createSuccessfulRemoteDataObject$(mockLdnService);
|
||||||
|
|
||||||
const mockLdnServices = {
|
|
||||||
payload: {
|
export const mockLdnServices: LdnService[] = [{
|
||||||
elementsPerPage: 20,
|
uuid: '1',
|
||||||
totalPages: 1,
|
enabled: false,
|
||||||
totalElements: 1,
|
score: 0,
|
||||||
currentPage: 1,
|
id: 1,
|
||||||
first: undefined,
|
name: 'Service Name',
|
||||||
prev: undefined,
|
description: 'Service Description',
|
||||||
next: undefined,
|
url: 'Service URL',
|
||||||
last: undefined,
|
ldnUrl: 'Service LDN URL',
|
||||||
page: [mockLdnService],
|
notifyServiceInboundPatterns: [
|
||||||
type: LDN_SERVICE,
|
{
|
||||||
self: undefined,
|
pattern: 'patternA',
|
||||||
getPageLength: function () {
|
constraint: 'itemFilterA',
|
||||||
return this.page.length;
|
automatic: 'false',
|
||||||
},
|
|
||||||
_links: {
|
|
||||||
self: {
|
|
||||||
href: 'http://localhost/api/ldn/ldnservices/1',
|
|
||||||
},
|
|
||||||
page: [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
hasSucceeded: true,
|
{
|
||||||
msToLive: 0,
|
pattern: 'patternB',
|
||||||
};
|
constraint: 'itemFilterB',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
// Create a mock ldnServicesRD$ observable
|
],
|
||||||
|
notifyServiceOutboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'patternC',
|
||||||
|
constraint: 'itemFilterC',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: LDN_SERVICE,
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'http://localhost/api/ldn/ldnservices/1'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get self(): string {
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
uuid: '2',
|
||||||
|
enabled: false,
|
||||||
|
score: 0,
|
||||||
|
id: 2,
|
||||||
|
name: 'Service Name',
|
||||||
|
description: 'Service Description',
|
||||||
|
url: 'Service URL',
|
||||||
|
ldnUrl: 'Service LDN URL',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'patternA',
|
||||||
|
constraint: 'itemFilterA',
|
||||||
|
automatic: 'false',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'patternB',
|
||||||
|
constraint: 'itemFilterB',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
notifyServiceOutboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'patternC',
|
||||||
|
constraint: 'itemFilterC',
|
||||||
|
automatic: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: LDN_SERVICE,
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'http://localhost/api/ldn/ldnservices/1'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
get self(): string {
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
}
|
||||||
|
];
|
||||||
export const mockLdnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>> = of((mockLdnServices as unknown) as RemoteData<PaginatedList<LdnService>>);
|
export const mockLdnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>> = of((mockLdnServices as unknown) as RemoteData<PaginatedList<LdnService>>);
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import { dataService } from '../../../core/data/base/data-service.decorator';
|
import {dataService} from '../../../core/data/base/data-service.decorator';
|
||||||
import { LDN_SERVICE_CONSTRAINT_FILTERS } from '../ldn-services-model/ldn-service.resource-type';
|
import {LDN_SERVICE_CONSTRAINT_FILTERS} from '../ldn-services-model/ldn-service.resource-type';
|
||||||
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
|
import {IdentifiableDataService} from '../../../core/data/base/identifiable-data.service';
|
||||||
import { FindAllData, FindAllDataImpl } from '../../../core/data/base/find-all-data';
|
import {FindAllData, FindAllDataImpl} from '../../../core/data/base/find-all-data';
|
||||||
|
|
||||||
import { RequestService } from '../../../core/data/request.service';
|
import {RequestService} from '../../../core/data/request.service';
|
||||||
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
|
import {RemoteDataBuildService} from '../../../core/cache/builders/remote-data-build.service';
|
||||||
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
import {ObjectCacheService} from '../../../core/cache/object-cache.service';
|
||||||
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
import {HALEndpointService} from '../../../core/shared/hal-endpoint.service';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import {FindListOptions} from '../../../core/data/find-list-options.model';
|
||||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
import {FollowLinkConfig} from '../../../shared/utils/follow-link-config.model';
|
||||||
import { Observable } from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
import { Itemfilter } from '../ldn-services-model/ldn-service-itemfilters';
|
import {Itemfilter} from '../ldn-services-model/ldn-service-itemfilters';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,25 +23,39 @@ import { PaginatedList } from '../../../core/data/paginated-list.model';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
@dataService(LDN_SERVICE_CONSTRAINT_FILTERS)
|
@dataService(LDN_SERVICE_CONSTRAINT_FILTERS)
|
||||||
export class LdnItemfiltersService extends IdentifiableDataService<Itemfilter> implements FindAllData<Itemfilter> {
|
export class LdnItemfiltersService extends IdentifiableDataService<Itemfilter> implements FindAllData<Itemfilter> {
|
||||||
private findAllData: FindAllDataImpl<Itemfilter>;
|
private findAllData: FindAllDataImpl<Itemfilter>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
) {
|
) {
|
||||||
super('itemfilters', requestService, rdbService, objectCache, halService);
|
super('itemfilters', requestService, rdbService, objectCache, halService);
|
||||||
|
|
||||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
getEndpoint() {
|
/**
|
||||||
return this.halService.getEndpoint(this.linkPath);
|
* Gets the endpoint URL for the itemfilters.
|
||||||
}
|
*
|
||||||
|
* @returns {string} - The endpoint URL.
|
||||||
|
*/
|
||||||
|
getEndpoint() {
|
||||||
|
return this.halService.getEndpoint(this.linkPath);
|
||||||
|
}
|
||||||
|
|
||||||
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Itemfilter>[]): Observable<RemoteData<PaginatedList<Itemfilter>>> {
|
/**
|
||||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
* Finds all itemfilters based on the provided options and link configurations.
|
||||||
}
|
*
|
||||||
|
* @param {FindListOptions} options - The options for finding a list of itemfilters.
|
||||||
|
* @param {boolean} useCachedVersionIfAvailable - Whether to use the cached version if available.
|
||||||
|
* @param {boolean} reRequestOnStale - Whether to re-request the data if it's stale.
|
||||||
|
* @param {...FollowLinkConfig<Itemfilter>[]} linksToFollow - Configurations for following specific links.
|
||||||
|
* @returns {Observable<RemoteData<PaginatedList<Itemfilter>>>} - An observable of remote data containing a paginated list of itemfilters.
|
||||||
|
*/
|
||||||
|
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Itemfilter>[]): Observable<RemoteData<PaginatedList<Itemfilter>>> {
|
||||||
|
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,208 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import { dataService } from '../../../core/data/base/data-service.decorator';
|
import {dataService} from '../../../core/data/base/data-service.decorator';
|
||||||
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
|
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
|
||||||
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
|
import {IdentifiableDataService} from '../../../core/data/base/identifiable-data.service';
|
||||||
import { FindAllData, FindAllDataImpl } from '../../../core/data/base/find-all-data';
|
import {FindAllData, FindAllDataImpl} from '../../../core/data/base/find-all-data';
|
||||||
import { DeleteData, DeleteDataImpl } from '../../../core/data/base/delete-data';
|
import {DeleteData, DeleteDataImpl} from '../../../core/data/base/delete-data';
|
||||||
import { RequestService } from '../../../core/data/request.service';
|
import {RequestService} from '../../../core/data/request.service';
|
||||||
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
|
import {RemoteDataBuildService} from '../../../core/cache/builders/remote-data-build.service';
|
||||||
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
import {ObjectCacheService} from '../../../core/cache/object-cache.service';
|
||||||
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
import {HALEndpointService} from '../../../core/shared/hal-endpoint.service';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import {FindListOptions} from '../../../core/data/find-list-options.model';
|
||||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
import {FollowLinkConfig} from '../../../shared/utils/follow-link-config.model';
|
||||||
import { Observable } from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
import { NoContent } from '../../../core/shared/NoContent.model';
|
import {NoContent} from '../../../core/shared/NoContent.model';
|
||||||
import { map, take } from 'rxjs/operators';
|
import {map, take} from 'rxjs/operators';
|
||||||
import { URLCombiner } from '../../../core/url-combiner/url-combiner';
|
import {URLCombiner} from '../../../core/url-combiner/url-combiner';
|
||||||
import { MultipartPostRequest } from '../../../core/data/request.models';
|
import {MultipartPostRequest} from '../../../core/data/request.models';
|
||||||
import { RestRequest } from '../../../core/data/rest-request.model';
|
import {RestRequest} from '../../../core/data/rest-request.model';
|
||||||
|
|
||||||
|
|
||||||
import { LdnService } from '../ldn-services-model/ldn-services.model';
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
|
|
||||||
import { PatchData, PatchDataImpl } from '../../../core/data/base/patch-data';
|
import {PatchData, PatchDataImpl} from '../../../core/data/base/patch-data';
|
||||||
import { ChangeAnalyzer } from '../../../core/data/change-analyzer';
|
import {ChangeAnalyzer} from '../../../core/data/change-analyzer';
|
||||||
import { Operation } from 'fast-json-patch';
|
import {Operation} from 'fast-json-patch';
|
||||||
import { RestRequestMethod } from 'src/app/core/data/rest-request-method';
|
import {RestRequestMethod} from '../../../core/data/rest-request-method';
|
||||||
import { CreateData, CreateDataImpl } from '../../../core/data/base/create-data';
|
import {CreateData, CreateDataImpl} from '../../../core/data/base/create-data';
|
||||||
import { ldnServiceConstrain } from '../ldn-services-model/ldn-service.constrain.model';
|
import {LdnServiceConstrain} from '../ldn-services-model/ldn-service.constrain.model';
|
||||||
import { getFirstCompletedRemoteData } from 'src/app/core/shared/operators';
|
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
|
||||||
import { hasValue } from 'src/app/shared/empty.util';
|
import {hasValue} from '../../../shared/empty.util';
|
||||||
|
import {SearchDataImpl} from '../../../core/data/base/search-data';
|
||||||
|
import {RequestParam} from '../../../core/cache/models/request-param.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service responsible for fetching/sending data from/to the REST API on the ldnservices endpoint
|
* Injectable service responsible for fetching/sending data from/to the REST API on the ldnservices endpoint.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @class LdnServicesService
|
||||||
|
* @extends {IdentifiableDataService<LdnService>}
|
||||||
|
* @implements {FindAllData<LdnService>}
|
||||||
|
* @implements {DeleteData<LdnService>}
|
||||||
|
* @implements {PatchData<LdnService>}
|
||||||
|
* @implements {CreateData<LdnService>}
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@dataService(LDN_SERVICE)
|
@dataService(LDN_SERVICE)
|
||||||
export class LdnServicesService extends IdentifiableDataService<LdnService> implements FindAllData<LdnService>, DeleteData<LdnService>, PatchData<LdnService>, CreateData<LdnService> {
|
export class LdnServicesService extends IdentifiableDataService<LdnService> implements FindAllData<LdnService>, DeleteData<LdnService>, PatchData<LdnService>, CreateData<LdnService> {
|
||||||
createData: CreateDataImpl<LdnService>;
|
createData: CreateDataImpl<LdnService>;
|
||||||
private findAllData: FindAllDataImpl<LdnService>;
|
private findAllData: FindAllDataImpl<LdnService>;
|
||||||
private deleteData: DeleteDataImpl<LdnService>;
|
private deleteData: DeleteDataImpl<LdnService>;
|
||||||
private patchData: PatchDataImpl<LdnService>;
|
private patchData: PatchDataImpl<LdnService>;
|
||||||
private comparator: ChangeAnalyzer<LdnService>;
|
private comparator: ChangeAnalyzer<LdnService>;
|
||||||
|
private searchData: SearchDataImpl<LdnService>;
|
||||||
|
|
||||||
constructor(
|
private findByPatternEndpoint = 'byInboundPattern';
|
||||||
protected requestService: RequestService,
|
|
||||||
protected rdbService: RemoteDataBuildService,
|
|
||||||
protected objectCache: ObjectCacheService,
|
|
||||||
protected halService: HALEndpointService,
|
|
||||||
protected notificationsService: NotificationsService,
|
|
||||||
) {
|
|
||||||
super('ldnservices', requestService, rdbService, objectCache, halService);
|
|
||||||
|
|
||||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
constructor(
|
||||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
protected requestService: RequestService,
|
||||||
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.comparator, this.responseMsToLive, this.constructIdEndpoint);
|
protected rdbService: RemoteDataBuildService,
|
||||||
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
protected objectCache: ObjectCacheService,
|
||||||
}
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
) {
|
||||||
|
super('ldnservices', requestService, rdbService, objectCache, halService);
|
||||||
|
|
||||||
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||||
|
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||||
|
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||||
|
}
|
||||||
|
|
||||||
create(object: LdnService): Observable<RemoteData<LdnService>> {
|
/**
|
||||||
return this.createData.create(object);
|
* Creates an LDN service by sending a POST request to the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {LdnService} object - The LDN service object to be created.
|
||||||
|
* @returns {Observable<RemoteData<LdnService>>} - Observable containing the result of the creation operation.
|
||||||
|
*/
|
||||||
|
create(object: LdnService): Observable<RemoteData<LdnService>> {
|
||||||
|
return this.createData.create(object);
|
||||||
|
}
|
||||||
|
|
||||||
patch(object: LdnService, operations: Operation[]): Observable<RemoteData<LdnService>> {
|
/**
|
||||||
return this.patchData.patch(object, operations);
|
* Updates an LDN service by applying a set of operations through a PATCH request to the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {LdnService} object - The LDN service object to be updated.
|
||||||
|
* @param {Operation[]} operations - The patch operations to be applied.
|
||||||
|
* @returns {Observable<RemoteData<LdnService>>} - Observable containing the result of the update operation.
|
||||||
|
*/
|
||||||
|
patch(object: LdnService, operations: Operation[]): Observable<RemoteData<LdnService>> {
|
||||||
|
return this.patchData.patch(object, operations);
|
||||||
|
}
|
||||||
|
|
||||||
update(object: LdnService): Observable<RemoteData<LdnService>> {
|
/**
|
||||||
return this.patchData.update(object);
|
* Updates an LDN service by sending a PUT request to the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {LdnService} object - The LDN service object to be updated.
|
||||||
|
* @returns {Observable<RemoteData<LdnService>>} - Observable containing the result of the update operation.
|
||||||
|
*/
|
||||||
|
update(object: LdnService): Observable<RemoteData<LdnService>> {
|
||||||
|
return this.patchData.update(object);
|
||||||
|
}
|
||||||
|
|
||||||
commitUpdates(method?: RestRequestMethod): void {
|
/**
|
||||||
return this.patchData.commitUpdates(method);
|
* Commits pending updates by sending a PATCH request to the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {RestRequestMethod} [method] - The HTTP method to be used for the request.
|
||||||
|
*/
|
||||||
|
commitUpdates(method?: RestRequestMethod): void {
|
||||||
|
return this.patchData.commitUpdates(method);
|
||||||
|
}
|
||||||
|
|
||||||
createPatchFromCache(object: LdnService): Observable<Operation[]> {
|
/**
|
||||||
return this.patchData.createPatchFromCache(object);
|
* Creates a patch representing the changes made to the LDN service in the cache.
|
||||||
}
|
*
|
||||||
|
* @param {LdnService} object - The LDN service object for which to create the patch.
|
||||||
|
* @returns {Observable<Operation[]>} - Observable containing the patch operations.
|
||||||
|
*/
|
||||||
|
createPatchFromCache(object: LdnService): Observable<Operation[]> {
|
||||||
|
return this.patchData.createPatchFromCache(object);
|
||||||
|
}
|
||||||
|
|
||||||
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<LdnService>[]): Observable<RemoteData<PaginatedList<LdnService>>> {
|
/**
|
||||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
* Retrieves all LDN services from the REST API based on the provided options.
|
||||||
}
|
*
|
||||||
|
* @param {FindListOptions} [options] - The options to be applied to the request.
|
||||||
|
* @param {boolean} [useCachedVersionIfAvailable] - Flag indicating whether to use cached data if available.
|
||||||
|
* @param {boolean} [reRequestOnStale] - Flag indicating whether to re-request data if it's stale.
|
||||||
|
* @param {...FollowLinkConfig<LdnService>[]} linksToFollow - Optional links to follow during the request.
|
||||||
|
* @returns {Observable<RemoteData<PaginatedList<LdnService>>>} - Observable containing the result of the request.
|
||||||
|
*/
|
||||||
|
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<LdnService>[]): Observable<RemoteData<PaginatedList<LdnService>>> {
|
||||||
|
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
|
|
||||||
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
/**
|
||||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
* Retrieves LDN services based on the inbound pattern from the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {string} pattern - The inbound pattern to be used in the search.
|
||||||
|
* @param {FindListOptions} [options] - The options to be applied to the request.
|
||||||
|
* @param {boolean} [useCachedVersionIfAvailable] - Flag indicating whether to use cached data if available.
|
||||||
|
* @param {boolean} [reRequestOnStale] - Flag indicating whether to re-request data if it's stale.
|
||||||
|
* @param {...FollowLinkConfig<LdnService>[]} linksToFollow - Optional links to follow during the request.
|
||||||
|
* @returns {Observable<RemoteData<PaginatedList<LdnService>>>} - Observable containing the result of the request.
|
||||||
|
*/
|
||||||
|
findByInboundPattern(pattern: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<LdnService>[]): Observable<RemoteData<PaginatedList<LdnService>>> {
|
||||||
|
const params = [new RequestParam('pattern', pattern)];
|
||||||
|
const findListOptions = Object.assign(new FindListOptions(), options, {searchParams: params});
|
||||||
|
return this.searchData.searchBy(this.findByPatternEndpoint, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
|
|
||||||
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
/**
|
||||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
* Deletes an LDN service by sending a DELETE request to the REST API.
|
||||||
}
|
*
|
||||||
|
* @param {string} objectId - The ID of the LDN service to be deleted.
|
||||||
|
* @param {string[]} [copyVirtualMetadata] - Optional virtual metadata to be copied during the deletion.
|
||||||
|
* @returns {Observable<RemoteData<NoContent>>} - Observable containing the result of the deletion operation.
|
||||||
|
*/
|
||||||
|
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
|
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
public invoke(serviceName: string, serviceId: string, parameters: ldnServiceConstrain[], files: File[]): Observable<RemoteData<LdnService>> {
|
/**
|
||||||
const requestId = this.requestService.generateRequestId();
|
* Deletes an LDN service by its HATEOAS link.
|
||||||
this.getBrowseEndpoint().pipe(
|
*
|
||||||
take(1),
|
* @param {string} href - The HATEOAS link of the LDN service to be deleted.
|
||||||
map((endpoint: string) => new URLCombiner(endpoint, serviceName, 'processes', serviceId).toString()),
|
* @param {string[]} [copyVirtualMetadata] - Optional virtual metadata to be copied during the deletion.
|
||||||
map((endpoint: string) => {
|
* @returns {Observable<RemoteData<NoContent>>} - Observable containing the result of the deletion operation.
|
||||||
const body = this.getInvocationFormData(parameters, files);
|
*/
|
||||||
return new MultipartPostRequest(requestId, endpoint, body);
|
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
})
|
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||||
).subscribe((request: RestRequest) => this.requestService.send(request));
|
}
|
||||||
|
|
||||||
return this.rdbService.buildFromRequestUUID<LdnService>(requestId);
|
public invoke(serviceName: string, serviceId: string, parameters: LdnServiceConstrain[], files: File[]): Observable<RemoteData<LdnService>> {
|
||||||
}
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
this.getBrowseEndpoint().pipe(
|
||||||
|
take(1),
|
||||||
|
map((endpoint: string) => new URLCombiner(endpoint, serviceName, 'processes', serviceId).toString()),
|
||||||
|
map((endpoint: string) => {
|
||||||
|
const body = this.getInvocationFormData(parameters, files);
|
||||||
|
return new MultipartPostRequest(requestId, endpoint, body);
|
||||||
|
})
|
||||||
|
).subscribe((request: RestRequest) => this.requestService.send(request));
|
||||||
|
|
||||||
public ldnServiceWithNameExistsAndCanExecute(scriptName: string): Observable<boolean> {
|
return this.rdbService.buildFromRequestUUID<LdnService>(requestId);
|
||||||
return this.findById(scriptName).pipe(
|
}
|
||||||
getFirstCompletedRemoteData(),
|
|
||||||
map((rd: RemoteData<LdnService>) => {
|
|
||||||
return hasValue(rd.payload);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getInvocationFormData(constrain: ldnServiceConstrain[], files: File[]): FormData {
|
public ldnServiceWithNameExistsAndCanExecute(scriptName: string): Observable<boolean> {
|
||||||
const form: FormData = new FormData();
|
return this.findById(scriptName).pipe(
|
||||||
form.set('properties', JSON.stringify(constrain));
|
getFirstCompletedRemoteData(),
|
||||||
files.forEach((file: File) => {
|
map((rd: RemoteData<LdnService>) => {
|
||||||
form.append('file', file);
|
return hasValue(rd.payload);
|
||||||
});
|
}),
|
||||||
return form;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getInvocationFormData(constrain: LdnServiceConstrain[], files: File[]): FormData {
|
||||||
|
const form: FormData = new FormData();
|
||||||
|
form.set('properties', JSON.stringify(constrain));
|
||||||
|
files.forEach((file: File) => {
|
||||||
|
form.append('file', file);
|
||||||
|
});
|
||||||
|
return form;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,83 +1,84 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<h2 class="flex-grow-1">{{ 'ldn-registered-services.title' | translate }}</h2>
|
<h2 class="flex-grow-1">{{ 'ldn-registered-services.title' | translate }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<button class="btn btn-success" routerLink="/admin/ldn/services/new"><i
|
<button class="btn btn-success" routerLink="/admin/ldn/services/new"><i
|
||||||
class="fas fa-plus pr-2"></i>{{ 'process.overview.new' | translate }}</button>
|
class="fas fa-plus pr-2"></i>{{ 'process.overview.new' | translate }}</button>
|
||||||
</div>
|
</div>
|
||||||
<ds-pagination *ngIf="(ldnServicesRD$ | async)?.payload?.totalElements > 0"
|
<ds-pagination *ngIf="(ldnServicesRD$ | async)?.payload?.totalElements > 0"
|
||||||
[collectionSize]="(ldnServicesRD$ | async)?.payload?.totalElements"
|
[collectionSize]="(ldnServicesRD$ | async)?.payload?.totalElements"
|
||||||
[hideGear]="true"
|
[hideGear]="true"
|
||||||
[hidePagerWhenSinglePage]="true"
|
[hidePagerWhenSinglePage]="true"
|
||||||
[pageInfoState]="(ldnServicesRD$ | async)?.payload"
|
[pageInfoState]="(ldnServicesRD$ | async)?.payload"
|
||||||
[paginationOptions]="pageConfig">
|
[paginationOptions]="pageConfig">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">{{ 'service.overview.table.name' | translate }}</th>
|
<th scope="col">{{ 'service.overview.table.name' | translate }}</th>
|
||||||
<th scope="col">{{ 'service.overview.table.description' | translate }}</th>
|
<th scope="col">{{ 'service.overview.table.description' | translate }}</th>
|
||||||
<th scope="col">{{ 'service.overview.table.status' | translate }}</th>
|
<th scope="col">{{ 'service.overview.table.status' | translate }}</th>
|
||||||
<th scope="col">{{ 'service.overview.table.actions' | translate }}</th>
|
<th scope="col">{{ 'service.overview.table.actions' | translate }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let ldnService of (ldnServicesRD$ | async)?.payload?.page">
|
<tr *ngFor="let ldnService of (ldnServicesRD$ | async)?.payload?.page">
|
||||||
<td>{{ ldnService.name }}</td>
|
<td>{{ ldnService.name }}</td>
|
||||||
<td>{{ ldnService.description }}</td>
|
<td>{{ ldnService.description }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span (click)="toggleStatus(ldnService, ldnServicesService)"
|
<span (click)="toggleStatus(ldnService, ldnServicesService)"
|
||||||
[ngClass]="{ 'status-enabled': ldnService.enabled, 'status-disabled': !ldnService.enabled }" [title]="ldnService.enabled ? ('ldn-service.overview.table.clickToDisable' | translate) : ('ldn-service.overview.table.clickToEnable' | translate)"
|
[ngClass]="{ 'status-enabled': ldnService.enabled, 'status-disabled': !ldnService.enabled }"
|
||||||
|
[title]="ldnService.enabled ? ('ldn-service.overview.table.clickToDisable' | translate) : ('ldn-service.overview.table.clickToEnable' | translate)"
|
||||||
class="status-indicator">
|
class="status-indicator">
|
||||||
{{ ldnService.enabled ? ('ldn-service.overview.table.enabled' | translate) : ('ldn-service.overview.table.disabled' | translate) }}
|
{{ ldnService.enabled ? ('ldn-service.overview.table.enabled' | translate) : ('ldn-service.overview.table.disabled' | translate) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button (click)="selectServiceToDelete(ldnService.id)" class="btn btn-outline-danger">
|
<button (click)="selectServiceToDelete(ldnService.id)" class="btn btn-outline-danger">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
<button [routerLink]="['/admin/ldn/services/edit/', ldnService.id]"
|
<button [routerLink]="['/admin/ldn/services/edit/', ldnService.id]"
|
||||||
class="btn btn-outline-dark">
|
class="btn btn-outline-dark">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #deleteModal>
|
<ng-template #deleteModal>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div>
|
<div>
|
||||||
<h4>{{'service.overview.delete.header' | translate }}</h4>
|
<h4>{{'service.overview.delete.header' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="closeModal()" aria-label="Close"
|
<button (click)="closeModal()" aria-label="Close"
|
||||||
class="close" type="button">
|
class="close" type="button">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div>
|
|
||||||
{{ 'service.overview.delete.body' | translate }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-4">
|
|
||||||
<button (click)="closeModal()"
|
|
||||||
class="btn btn-primary mr-2">{{ 'service.detail.delete.cancel' | translate }}</button>
|
|
||||||
<button (click)="deleteSelected(this.selectedServiceId.toString(), ldnServicesService)"
|
|
||||||
class="btn btn-danger"
|
|
||||||
id="delete-confirm">{{ 'service.overview.delete' | translate }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
|
{{ 'service.overview.delete.body' | translate }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4">
|
||||||
|
<button (click)="closeModal()"
|
||||||
|
class="btn btn-primary mr-2">{{ 'service.detail.delete.cancel' | translate }}</button>
|
||||||
|
<button (click)="deleteSelected(this.selectedServiceId.toString(), ldnServicesService)"
|
||||||
|
class="btn btn-danger"
|
||||||
|
id="delete-confirm">{{ 'service.overview.delete' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
@@ -1,25 +1,144 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
|
||||||
|
import {ChangeDetectorRef, EventEmitter} from '@angular/core';
|
||||||
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
|
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service.stub';
|
||||||
|
import {TranslateModule, TranslateService} from '@ngx-translate/core';
|
||||||
|
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
|
||||||
|
import {PaginationService} from '../../../core/pagination/pagination.service';
|
||||||
|
import {PaginationServiceStub} from '../../../shared/testing/pagination-service.stub';
|
||||||
|
import {of} from 'rxjs';
|
||||||
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
|
import {LdnServicesOverviewComponent} from './ldn-services-directory.component';
|
||||||
|
import {createSuccessfulRemoteDataObject$} from '../../../shared/remote-data.utils';
|
||||||
|
import {createPaginatedList} from '../../../shared/testing/utils.test';
|
||||||
|
|
||||||
import { ServicesDirectoryComponent } from './services-directory.component';
|
describe('LdnServicesOverviewComponent', () => {
|
||||||
|
let component: LdnServicesOverviewComponent;
|
||||||
|
let fixture: ComponentFixture<LdnServicesOverviewComponent>;
|
||||||
|
let ldnServicesService;
|
||||||
|
let paginationService;
|
||||||
|
let modalService: NgbModal;
|
||||||
|
let notificationsService: NotificationsService;
|
||||||
|
let translateService: TranslateService;
|
||||||
|
|
||||||
describe('ServicesDirectoryComponent', () => {
|
const translateServiceStub = {
|
||||||
let component: ServicesDirectoryComponent;
|
get: () => of('translated-text'),
|
||||||
let fixture: ComponentFixture<ServicesDirectoryComponent>;
|
onLangChange: new EventEmitter(),
|
||||||
|
onTranslationChange: new EventEmitter(),
|
||||||
|
onDefaultLangChange: new EventEmitter()
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
paginationService = new PaginationServiceStub();
|
||||||
declarations: [ServicesDirectoryComponent]
|
ldnServicesService = jasmine.createSpyObj('LdnServicesService', ['findAll', 'delete', 'patch']);
|
||||||
})
|
await TestBed.configureTestingModule({
|
||||||
.compileComponents();
|
imports: [TranslateModule.forRoot()],
|
||||||
|
declarations: [LdnServicesOverviewComponent],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: LdnServicesService,
|
||||||
|
useValue: ldnServicesService
|
||||||
|
},
|
||||||
|
{provide: PaginationService, useValue: paginationService},
|
||||||
|
{
|
||||||
|
provide: NgbModal, useValue: {
|
||||||
|
open: () => { /*comment*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{provide: ChangeDetectorRef, useValue: {}},
|
||||||
|
{provide: NotificationsService, useValue: NotificationsServiceStub},
|
||||||
|
{provide: TranslateService, useValue: translateServiceStub},
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LdnServicesOverviewComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
ldnServicesService = TestBed.inject(LdnServicesService);
|
||||||
|
paginationService = TestBed.inject(PaginationService);
|
||||||
|
modalService = TestBed.inject(NgbModal);
|
||||||
|
notificationsService = TestBed.inject(NotificationsService);
|
||||||
|
translateService = TestBed.inject(TranslateService);
|
||||||
|
component.modalRef = jasmine.createSpyObj({close: null});
|
||||||
|
component.isProcessingSub = jasmine.createSpyObj({unsubscribe: null});
|
||||||
|
component.ldnServicesRD$ = of({} as RemoteData<PaginatedList<LdnService>>);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ngOnInit', () => {
|
||||||
|
it('should call setLdnServices', fakeAsync(() => {
|
||||||
|
spyOn(component, 'setLdnServices').and.callThrough();
|
||||||
|
component.ngOnInit();
|
||||||
|
tick();
|
||||||
|
expect(component.setLdnServices).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should set ldnServicesRD$ with mock data', fakeAsync(() => {
|
||||||
|
spyOn(component, 'setLdnServices').and.callThrough();
|
||||||
|
const testData: LdnService[] = Object.assign([new LdnService()], [
|
||||||
|
{id: 1, name: 'Service 1', description: 'Description 1', enabled: true},
|
||||||
|
{id: 2, name: 'Service 2', description: 'Description 2', enabled: false},
|
||||||
|
{id: 3, name: 'Service 3', description: 'Description 3', enabled: true}]);
|
||||||
|
|
||||||
|
const mockLdnServicesRD = createPaginatedList(testData);
|
||||||
|
component.ldnServicesRD$ = createSuccessfulRemoteDataObject$(mockLdnServicesRD);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const tableRows = fixture.debugElement.nativeElement.querySelectorAll('tbody tr');
|
||||||
|
expect(tableRows.length).toBe(testData.length);
|
||||||
|
const firstRowContent = tableRows[0].textContent;
|
||||||
|
expect(firstRowContent).toContain('Service 1');
|
||||||
|
expect(firstRowContent).toContain('Description 1');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ngOnDestroy', () => {
|
||||||
|
it('should call paginationService.clearPagination and unsubscribe', () => {
|
||||||
|
// spyOn(paginationService, 'clearPagination');
|
||||||
|
// spyOn(component.isProcessingSub, 'unsubscribe');
|
||||||
|
component.ngOnDestroy();
|
||||||
|
expect(paginationService.clearPagination).toHaveBeenCalledWith(component.pageConfig.id);
|
||||||
|
expect(component.isProcessingSub.unsubscribe).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
describe('openDeleteModal', () => {
|
||||||
fixture = TestBed.createComponent(ServicesDirectoryComponent);
|
it('should open delete modal', () => {
|
||||||
component = fixture.componentInstance;
|
spyOn(modalService, 'open');
|
||||||
fixture.detectChanges();
|
component.openDeleteModal(component.deleteModal);
|
||||||
|
expect(modalService.open).toHaveBeenCalledWith(component.deleteModal);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
describe('closeModal', () => {
|
||||||
expect(component).toBeTruthy();
|
it('should close modal and detect changes', () => {
|
||||||
|
// spyOn(component.modalRef, 'close');
|
||||||
|
spyOn(component.cdRef, 'detectChanges');
|
||||||
|
component.closeModal();
|
||||||
|
expect(component.modalRef.close).toHaveBeenCalled();
|
||||||
|
expect(component.cdRef.detectChanges).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteSelected', () => {
|
||||||
|
it('should delete selected service and update data', fakeAsync(() => {
|
||||||
|
const serviceId = '123';
|
||||||
|
const mockRemoteData = { /* just an empty object to retrieve as as RemoteData<PaginatedList<LdnService>> */};
|
||||||
|
spyOn(component, 'setLdnServices').and.callThrough();
|
||||||
|
const deleteSpy = ldnServicesService.delete.and.returnValue(of(mockRemoteData as RemoteData<PaginatedList<LdnService>>));
|
||||||
|
component.selectedServiceId = serviceId;
|
||||||
|
component.deleteSelected(serviceId, ldnServicesService);
|
||||||
|
tick();
|
||||||
|
expect(deleteSpy).toHaveBeenCalledWith(serviceId);
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -7,140 +7,170 @@ import {
|
|||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import {Observable, Subscription} from 'rxjs';
|
||||||
import { RemoteData } from '../../../core/data/remote-data';
|
import {RemoteData} from '../../../core/data/remote-data';
|
||||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
import {PaginatedList} from '../../../core/data/paginated-list.model';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import {FindListOptions} from '../../../core/data/find-list-options.model';
|
||||||
import { LdnService } from '../ldn-services-model/ldn-services.model';
|
import {LdnService} from '../ldn-services-model/ldn-services.model';
|
||||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
import {PaginationComponentOptions} from '../../../shared/pagination/pagination-component-options.model';
|
||||||
import { map, switchMap } from 'rxjs/operators';
|
import {map, switchMap} from 'rxjs/operators';
|
||||||
import { LdnServicesService } from 'src/app/admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
import {LdnServicesService} from 'src/app/admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||||
import { PaginationService } from 'src/app/core/pagination/pagination.service';
|
import {PaginationService} from 'src/app/core/pagination/pagination.service';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { hasValue } from '../../../shared/empty.util';
|
import {hasValue} from '../../../shared/empty.util';
|
||||||
import { Operation } from 'fast-json-patch';
|
import {Operation} from 'fast-json-patch';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
|
||||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
import {NotificationsService} from '../../../shared/notifications/notifications.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `LdnServicesOverviewComponent` is a component that provides an overview of LDN (Linked Data Notifications) services.
|
||||||
|
* It displays a paginated list of LDN services, allows users to edit and delete services,
|
||||||
|
* toggle the status of each service directly form the page and allows for creation of new services redirecting the user on the creation/edit form
|
||||||
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-ldn-services-directory',
|
selector: 'ds-ldn-services-directory',
|
||||||
templateUrl: './ldn-services-directory.component.html',
|
templateUrl: './ldn-services-directory.component.html',
|
||||||
styleUrls: ['./ldn-services-directory.component.scss'],
|
styleUrls: ['./ldn-services-directory.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.Default
|
changeDetection: ChangeDetectionStrategy.Default
|
||||||
})
|
})
|
||||||
export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
|
export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
selectedServiceId: string | number | null = null;
|
selectedServiceId: string | number | null = null;
|
||||||
servicesData: any[] = [];
|
servicesData: any[] = [];
|
||||||
@ViewChild('deleteModal', {static: true}) deleteModal: TemplateRef<any>;
|
@ViewChild('deleteModal', {static: true}) deleteModal: TemplateRef<any>;
|
||||||
ldnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>>;
|
ldnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>>;
|
||||||
config: FindListOptions = Object.assign(new FindListOptions(), {
|
config: FindListOptions = Object.assign(new FindListOptions(), {
|
||||||
elementsPerPage: 20
|
elementsPerPage: 20
|
||||||
});
|
});
|
||||||
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||||
id: 'po',
|
id: 'po',
|
||||||
pageSize: 20
|
pageSize: 20
|
||||||
});
|
});
|
||||||
isProcessingSub: Subscription;
|
isProcessingSub: Subscription;
|
||||||
private modalRef: any;
|
modalRef: any;
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected ldnServicesService: LdnServicesService,
|
protected ldnServicesService: LdnServicesService,
|
||||||
protected paginationService: PaginationService,
|
protected paginationService: PaginationService,
|
||||||
protected modalService: NgbModal,
|
protected modalService: NgbModal,
|
||||||
private cdRef: ChangeDetectorRef,
|
public cdRef: ChangeDetectorRef,
|
||||||
private notificationService: NotificationsService,
|
private notificationService: NotificationsService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
) {
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.setLdnServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the LDN services by fetching and observing the paginated list of services.
|
||||||
|
*/
|
||||||
|
setLdnServices() {
|
||||||
|
this.ldnServicesRD$ = this.paginationService.getFindListOptions(this.pageConfig.id, this.config).pipe(
|
||||||
|
switchMap((config) => this.ldnServicesService.findAll(config, false, false).pipe(
|
||||||
|
getFirstCompletedRemoteData()
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.paginationService.clearPagination(this.pageConfig.id);
|
||||||
|
if (hasValue(this.isProcessingSub)) {
|
||||||
|
this.isProcessingSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
/**
|
||||||
this.setLdnServices();
|
* Opens the delete confirmation modal.
|
||||||
}
|
*
|
||||||
|
* @param {any} content - The content of the modal.
|
||||||
|
*/
|
||||||
|
openDeleteModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
setLdnServices() {
|
/**
|
||||||
this.ldnServicesRD$ = this.paginationService.getFindListOptions(this.pageConfig.id, this.config).pipe(
|
* Closes the currently open modal and triggers change detection.
|
||||||
switchMap((config) => this.ldnServicesService.findAll(config, false, false).pipe(
|
*/
|
||||||
getFirstCompletedRemoteData()
|
closeModal() {
|
||||||
))
|
this.modalRef.close();
|
||||||
);
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
/**
|
||||||
this.paginationService.clearPagination(this.pageConfig.id);
|
* Sets the selected LDN service ID for deletion and opens the delete confirmation modal.
|
||||||
if (hasValue(this.isProcessingSub)) {
|
*
|
||||||
this.isProcessingSub.unsubscribe();
|
* @param {number} serviceId - The ID of the service to be deleted.
|
||||||
|
*/
|
||||||
|
selectServiceToDelete(serviceId: number) {
|
||||||
|
this.selectedServiceId = serviceId;
|
||||||
|
this.openDeleteModal(this.deleteModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the selected LDN service.
|
||||||
|
*
|
||||||
|
* @param {string} serviceId - The ID of the service to be deleted.
|
||||||
|
* @param {LdnServicesService} ldnServicesService - The service for managing LDN services.
|
||||||
|
*/
|
||||||
|
deleteSelected(serviceId: string, ldnServicesService: LdnServicesService): void {
|
||||||
|
if (this.selectedServiceId !== null) {
|
||||||
|
ldnServicesService.delete(serviceId).pipe(getFirstCompletedRemoteData()).subscribe((rd: RemoteData<LdnService>) => {
|
||||||
|
if (rd.hasSucceeded) {
|
||||||
|
this.servicesData = this.servicesData.filter(service => service.id !== serviceId);
|
||||||
|
this.ldnServicesRD$ = this.ldnServicesRD$.pipe(
|
||||||
|
map((remoteData: RemoteData<PaginatedList<LdnService>>) => {
|
||||||
|
if (remoteData.hasSucceeded) {
|
||||||
|
remoteData.payload.page = remoteData.payload.page.filter(service => service.id.toString() !== serviceId);
|
||||||
|
}
|
||||||
|
return remoteData;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.cdRef.detectChanges();
|
||||||
|
this.closeModal();
|
||||||
|
this.notificationService.success(this.translateService.get('ldn-service-delete.notification.success.title'),
|
||||||
|
this.translateService.get('ldn-service-delete.notification.success.content'));
|
||||||
|
} else {
|
||||||
|
this.notificationService.error(this.translateService.get('ldn-service-delete.notification.error.title'),
|
||||||
|
this.translateService.get('ldn-service-delete.notification.error.content'));
|
||||||
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
openDeleteModal(content) {
|
/**
|
||||||
this.modalRef = this.modalService.open(content);
|
* Toggles the status (enabled/disabled) of an LDN service.
|
||||||
}
|
*
|
||||||
|
* @param {any} ldnService - The LDN service object.
|
||||||
|
* @param {LdnServicesService} ldnServicesService - The service for managing LDN services.
|
||||||
|
*/
|
||||||
|
toggleStatus(ldnService: any, ldnServicesService: LdnServicesService): void {
|
||||||
|
const newStatus = !ldnService.enabled;
|
||||||
|
const originalStatus = ldnService.enabled;
|
||||||
|
|
||||||
closeModal() {
|
const patchOperation: Operation = {
|
||||||
this.modalRef.close();
|
op: 'replace',
|
||||||
this.cdRef.detectChanges();
|
path: '/enabled',
|
||||||
}
|
value: newStatus,
|
||||||
|
};
|
||||||
|
|
||||||
selectServiceToDelete(serviceId: number) {
|
ldnServicesService.patch(ldnService, [patchOperation]).pipe(getFirstCompletedRemoteData()).subscribe(
|
||||||
this.selectedServiceId = serviceId;
|
(rd: RemoteData<LdnService>) => {
|
||||||
this.openDeleteModal(this.deleteModal);
|
if (rd.hasSucceeded) {
|
||||||
}
|
ldnService.enabled = newStatus;
|
||||||
|
this.notificationService.success(this.translateService.get('ldn-enable-service.notification.success.title'),
|
||||||
deleteSelected(serviceId: string, ldnServicesService: LdnServicesService): void {
|
this.translateService.get('ldn-enable-service.notification.success.content'));
|
||||||
if (this.selectedServiceId !== null) {
|
} else {
|
||||||
ldnServicesService.delete(serviceId).pipe(getFirstCompletedRemoteData()).subscribe((rd: RemoteData<LdnService>) => {
|
ldnService.enabled = originalStatus;
|
||||||
if (rd.hasSucceeded) {
|
this.notificationService.error(this.translateService.get('ldn-enable-service.notification.error.title'),
|
||||||
this.servicesData = this.servicesData.filter(service => service.id !== serviceId);
|
this.translateService.get('ldn-enable-service.notification.error.content'));
|
||||||
this.ldnServicesRD$ = this.ldnServicesRD$.pipe(
|
|
||||||
map((remoteData: RemoteData<PaginatedList<LdnService>>) => {
|
|
||||||
if (remoteData.hasSucceeded) {
|
|
||||||
remoteData.payload.page = remoteData.payload.page.filter(service => service.id.toString() !== serviceId);
|
|
||||||
}
|
|
||||||
return remoteData;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
this.closeModal();
|
|
||||||
this.notificationService.success(this.translateService.get('ldn-service-delete.notification.success.title'),
|
|
||||||
this.translateService.get('ldn-service-delete.notification.success.content'));
|
|
||||||
} else {
|
|
||||||
this.notificationService.error(this.translateService.get('ldn-service-delete.notification.error.title'),
|
|
||||||
this.translateService.get('ldn-service-delete.notification.error.content'));
|
|
||||||
this.cdRef.detectChanges();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
toggleStatus(ldnService: any, ldnServicesService: LdnServicesService): void {
|
|
||||||
const newStatus = !ldnService.enabled;
|
|
||||||
const originalStatus = ldnService.enabled;
|
|
||||||
|
|
||||||
const patchOperation: Operation = {
|
|
||||||
op: 'replace',
|
|
||||||
path: '/enabled',
|
|
||||||
value: newStatus,
|
|
||||||
};
|
|
||||||
|
|
||||||
ldnServicesService.patch(ldnService, [patchOperation]).pipe(getFirstCompletedRemoteData()).subscribe(
|
|
||||||
(rd: RemoteData<LdnService>) => {
|
|
||||||
if (rd.hasSucceeded) {
|
|
||||||
ldnService.enabled = newStatus;
|
|
||||||
this.notificationService.success(this.translateService.get('ldn-enable-service.notification.success.title'),
|
|
||||||
this.translateService.get('ldn-enable-service.notification.success.content'));
|
|
||||||
} else {
|
|
||||||
ldnService.enabled = originalStatus;
|
|
||||||
this.notificationService.error(this.translateService.get('ldn-enable-service.notification.error.title'),
|
|
||||||
this.translateService.get('ldn-enable-service.notification.error.content'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,31 +1,31 @@
|
|||||||
import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
|
import {autoserialize, deserialize, inheritSerialization} from 'cerialize';
|
||||||
import { LDN_SERVICE_CONSTRAINT_FILTER } from './ldn-service.resource-type';
|
import {LDN_SERVICE_CONSTRAINT_FILTER} from './ldn-service.resource-type';
|
||||||
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
|
import {CacheableObject} from '../../../core/cache/cacheable-object.model';
|
||||||
import { typedObject } from '../../../core/cache/builders/build-decorators';
|
import {typedObject} from '../../../core/cache/builders/build-decorators';
|
||||||
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
|
import {excludeFromEquals} from '../../../core/utilities/equals.decorators';
|
||||||
import { ResourceType } from '../../../core/shared/resource-type';
|
import {ResourceType} from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
/** A single filter value and its properties. */
|
/** A single filter value and its properties. */
|
||||||
@typedObject
|
@typedObject
|
||||||
@inheritSerialization(CacheableObject)
|
@inheritSerialization(CacheableObject)
|
||||||
export class Itemfilter extends CacheableObject {
|
export class Itemfilter extends CacheableObject {
|
||||||
static type = LDN_SERVICE_CONSTRAINT_FILTER;
|
static type = LDN_SERVICE_CONSTRAINT_FILTER;
|
||||||
|
|
||||||
@excludeFromEquals
|
@excludeFromEquals
|
||||||
@autoserialize
|
@autoserialize
|
||||||
type: ResourceType;
|
type: ResourceType;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@deserialize
|
@deserialize
|
||||||
_links: {
|
_links: {
|
||||||
self: {
|
self: {
|
||||||
href: string;
|
href: string;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
get self(): string {
|
get self(): string {
|
||||||
return this._links.self.href;
|
return this._links.self.href;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
import { autoserialize } from 'cerialize';
|
import {autoserialize} from 'cerialize';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* notify service patterns
|
* A single notify service pattern and his properties
|
||||||
*/
|
*/
|
||||||
export class NotifyServicePattern {
|
export class NotifyServicePattern {
|
||||||
@autoserialize
|
@autoserialize
|
||||||
pattern: string;
|
pattern: string;
|
||||||
@autoserialize
|
@autoserialize
|
||||||
constraint: string;
|
constraint: string;
|
||||||
@autoserialize
|
@autoserialize
|
||||||
automatic: string;
|
automatic: string;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* List of services statuses
|
* List of services statuses
|
||||||
*/
|
*/
|
||||||
export enum LdnServiceStatus {
|
export enum LdnServiceStatus {
|
||||||
UNKOWN,
|
UNKOWN,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
ENABLED,
|
ENABLED,
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
export class ldnServiceConstrain {
|
export class LdnServiceConstrain {
|
||||||
void: any;
|
void: any;
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
* Needs to be in a separate file to prevent circular
|
* Needs to be in a separate file to prevent circular
|
||||||
* dependencies in webpack.
|
* dependencies in webpack.
|
||||||
*/
|
*/
|
||||||
import { ResourceType } from '../../../core/shared/resource-type';
|
import {ResourceType} from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
export const LDN_SERVICE = new ResourceType('ldnservice');
|
export const LDN_SERVICE = new ResourceType('ldnservice');
|
||||||
export const LDN_SERVICE_CONSTRAINT_FILTERS = new ResourceType('itemfilters');
|
export const LDN_SERVICE_CONSTRAINT_FILTERS = new ResourceType('itemfilters');
|
||||||
|
@@ -1,57 +1,60 @@
|
|||||||
import { ResourceType } from '../../../core/shared/resource-type';
|
import {ResourceType} from '../../../core/shared/resource-type';
|
||||||
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
|
import {CacheableObject} from '../../../core/cache/cacheable-object.model';
|
||||||
import { autoserialize, deserialize, deserializeAs, inheritSerialization } from 'cerialize';
|
import {autoserialize, deserialize, deserializeAs, inheritSerialization} from 'cerialize';
|
||||||
import { LDN_SERVICE } from './ldn-service.resource-type';
|
import {LDN_SERVICE} from './ldn-service.resource-type';
|
||||||
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
|
import {excludeFromEquals} from '../../../core/utilities/equals.decorators';
|
||||||
import { typedObject } from '../../../core/cache/builders/build-decorators';
|
import {typedObject} from '../../../core/cache/builders/build-decorators';
|
||||||
import { NotifyServicePattern } from './ldn-service-patterns.model';
|
import {NotifyServicePattern} from './ldn-service-patterns.model';
|
||||||
|
|
||||||
|
|
||||||
/** An LdnService and its properties. */
|
/** An LdnService and its properties. */
|
||||||
@typedObject
|
@typedObject
|
||||||
@inheritSerialization(CacheableObject)
|
@inheritSerialization(CacheableObject)
|
||||||
export class LdnService extends CacheableObject {
|
export class LdnService extends CacheableObject {
|
||||||
static type = LDN_SERVICE;
|
static type = LDN_SERVICE;
|
||||||
|
|
||||||
@excludeFromEquals
|
@excludeFromEquals
|
||||||
@autoserialize
|
@autoserialize
|
||||||
type: ResourceType;
|
type: ResourceType;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
@deserializeAs('id')
|
@deserializeAs('id')
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
enabled: boolean;
|
score: number;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
ldnUrl: string;
|
enabled: boolean;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
notifyServiceInboundPatterns?: NotifyServicePattern[];
|
ldnUrl: string;
|
||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
notifyServiceOutboundPatterns?: NotifyServicePattern[];
|
notifyServiceInboundPatterns?: NotifyServicePattern[];
|
||||||
|
|
||||||
@deserialize
|
@autoserialize
|
||||||
_links: {
|
notifyServiceOutboundPatterns?: NotifyServicePattern[];
|
||||||
self: {
|
|
||||||
href: string;
|
@deserialize
|
||||||
};
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: string;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
get self(): string {
|
get self(): string {
|
||||||
return this._links.self.href;
|
return this._links.self.href;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
* List of parameter types used for scripts
|
* List of parameter types used for scripts
|
||||||
*/
|
*/
|
||||||
export enum LdnServiceConstrainType {
|
export enum LdnServiceConstrainType {
|
||||||
STRING = 'String',
|
STRING = 'String',
|
||||||
DATE = 'date',
|
DATE = 'date',
|
||||||
BOOLEAN = 'boolean',
|
BOOLEAN = 'boolean',
|
||||||
FILE = 'InputStream',
|
FILE = 'InputStream',
|
||||||
OUTPUT = 'OutputStream'
|
OUTPUT = 'OutputStream'
|
||||||
}
|
}
|
||||||
|
@@ -1,69 +1,31 @@
|
|||||||
export const notifyPatterns = [
|
export const notifyPatterns = [
|
||||||
{
|
|
||||||
name: 'Acknowledge and Accept',
|
'ack-accept',
|
||||||
description: 'This pattern is used to acknowledge and accept a request (offer). It implies an intention to act on the request.',
|
|
||||||
category: 'Acknowledgements'
|
'ack-reject',
|
||||||
},
|
|
||||||
{
|
'ack-tentative-accept',
|
||||||
name: 'Acknowledge and Reject',
|
|
||||||
description: 'This pattern is used to acknowledge and reject a request (offer). It signifies no further action regarding the request.',
|
'ack-tentative-reject',
|
||||||
category: 'Acknowledgements'
|
|
||||||
},
|
'announce-endorsement',
|
||||||
{
|
|
||||||
name: 'Acknowledge and Tentatively Accept',
|
'announce-ingest',
|
||||||
description: 'This pattern is used to acknowledge and tentatively accept a request (offer). It implies an intention to act, which may change.',
|
|
||||||
category: 'Acknowledgements'
|
'announce-relationship',
|
||||||
},
|
|
||||||
{
|
'announce-review',
|
||||||
name: 'Acknowledge and Tentatively Reject',
|
|
||||||
description: 'This pattern is used to acknowledge and tentatively reject a request (offer). It signifies no further action, subject to change.',
|
'announce-service-result',
|
||||||
category: 'Acknowledgements'
|
|
||||||
},
|
'request-endorsement',
|
||||||
{
|
|
||||||
name: 'Announce Endorsement',
|
'request-ingest',
|
||||||
description: 'This pattern is used to announce the existence of an endorsement, referencing the endorsed resource.',
|
|
||||||
category: 'Announcements'
|
'request-review',
|
||||||
},
|
|
||||||
{
|
'undo-offer',
|
||||||
name: 'Announce Ingest',
|
|
||||||
description: 'This pattern is used to announce that a resource has been ingested.',
|
|
||||||
category: 'Announcements'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Announce Relationship',
|
|
||||||
description: 'This pattern is used to announce a relationship between two resources.',
|
|
||||||
category: 'Announcements'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Announce Review',
|
|
||||||
description: 'This pattern is used to announce the existence of a review, referencing the reviewed resource.',
|
|
||||||
category: 'Announcements'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Announce Service Result',
|
|
||||||
description: 'This pattern is used to announce the existence of a "service result", referencing the relevant resource.',
|
|
||||||
category: 'Announcements'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Request Endorsement',
|
|
||||||
description: 'This pattern is used to request endorsement of a resource owned by the origin system.',
|
|
||||||
category: 'Requests'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Request Ingest',
|
|
||||||
description: 'This pattern is used to request that the target system ingest a resource.',
|
|
||||||
category: 'Requests'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Request Review',
|
|
||||||
description: 'This pattern is used to request a review of a resource owned by the origin system.',
|
|
||||||
category: 'Requests'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Undo Offer',
|
|
||||||
description: 'This pattern is used to undo (retract) an offer previously made.',
|
|
||||||
category: 'Undo'
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LdnDirectoryService } from './ldn-directory.service';
|
|
||||||
|
|
||||||
describe('LdnDirectoryService', () => {
|
|
||||||
let service: LdnDirectoryService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({});
|
|
||||||
service = TestBed.inject(LdnDirectoryService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
// @ts-ignore
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,29 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
import { map, Observable } from 'rxjs';
|
|
||||||
import { LdnServicesService } from "../ldn-services-data/ldn-services-data.service";
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class LdnDirectoryService {
|
|
||||||
private itemFilterEndpoint = 'http://localhost:8080/server/api/config/itemfilters';
|
|
||||||
|
|
||||||
|
|
||||||
constructor(private http: HttpClient,
|
|
||||||
private ldnServicesService: LdnServicesService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public getItemFilters(): Observable<any> {
|
|
||||||
|
|
||||||
return this.ldnServicesService.findAll().pipe(
|
|
||||||
map((servicesData) => {
|
|
||||||
return servicesData;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,17 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LdnServicesBulkDeleteService } from './ldn-service-bulk-delete.service';
|
|
||||||
|
|
||||||
describe('LdnServiceBulkDeleteService', () => {
|
|
||||||
let service: LdnServicesBulkDeleteService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({});
|
|
||||||
service = TestBed.inject(LdnServicesBulkDeleteService);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
// @ts-ignore
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
@@ -49,6 +49,21 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon
|
|||||||
showBreadcrumbsFluid: false
|
showBreadcrumbsFluid: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
canActivate: [ AuthenticatedGuard ],
|
||||||
|
path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/target/:targetId`,
|
||||||
|
component: AdminQualityAssuranceTopicsPageComponent,
|
||||||
|
pathMatch: 'full',
|
||||||
|
resolve: {
|
||||||
|
breadcrumb: I18nBreadcrumbResolver,
|
||||||
|
openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
title: 'admin.quality-assurance.page.title',
|
||||||
|
breadcrumbKey: 'admin.quality-assurance',
|
||||||
|
showBreadcrumbsFluid: false
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
canActivate: [ AuthenticatedGuard ],
|
canActivate: [ AuthenticatedGuard ],
|
||||||
path: `${QUALITY_ASSURANCE_EDIT_PATH}`,
|
path: `${QUALITY_ASSURANCE_EDIT_PATH}`,
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<p [innerHTML]="('coar-notify-support-title.content' | translate)"></p>
|
<p [innerHTML]="('coar-notify-support-title.content' | translate)"></p>
|
||||||
|
|
||||||
<h2>{{ 'coar-notify-support.ldn-inbox.title' | translate }}</h2>
|
<h2>{{ 'coar-notify-support.ldn-inbox.title' | translate }}</h2>
|
||||||
<p [innerHTML]="('coar-notify-support.ldn-inbox.content' | translate).replace('{restApiUrl}', coarRestApiUrl)"></p>
|
<p [innerHTML]="('coar-notify-support.ldn-inbox.content' | translate).replace('{ldnInboxUrl}', (coarRestApiUrl | async)?.join(', '))"></p>
|
||||||
|
|
||||||
<h2>{{ 'coar-notify-support.message-moderation.title' | translate }}</h2>
|
<h2>{{ 'coar-notify-support.message-moderation.title' | translate }}</h2>
|
||||||
<p [innerHTML]="('coar-notify-support.message-moderation.content' | translate)"></p>
|
<p [innerHTML]="('coar-notify-support.message-moderation.content' | translate)"></p>
|
||||||
|
@@ -1,14 +1,23 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { NotifyInfoComponent } from './notify-info.component';
|
import { NotifyInfoComponent } from './notify-info.component';
|
||||||
|
import { NotifyInfoService } from './notify-info.service';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
describe('NotifyInfoComponent', () => {
|
describe('NotifyInfoComponent', () => {
|
||||||
let component: NotifyInfoComponent;
|
let component: NotifyInfoComponent;
|
||||||
let fixture: ComponentFixture<NotifyInfoComponent>;
|
let fixture: ComponentFixture<NotifyInfoComponent>;
|
||||||
|
let notifyInfoServiceSpy: any;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
notifyInfoServiceSpy = jasmine.createSpyObj('NotifyInfoService', ['getCoarLdnLocalInboxUrls']);
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ NotifyInfoComponent ]
|
imports: [TranslateModule.forRoot()],
|
||||||
|
declarations: [ NotifyInfoComponent ],
|
||||||
|
providers: [
|
||||||
|
{ provide: NotifyInfoService, useValue: notifyInfoServiceSpy }
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
@@ -1,26 +1,24 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { NotifyInfoService } from './notify-info.service';
|
import { NotifyInfoService } from './notify-info.service';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-notify-info',
|
selector: 'ds-notify-info',
|
||||||
templateUrl: './notify-info.component.html',
|
templateUrl: './notify-info.component.html',
|
||||||
styleUrls: ['./notify-info.component.scss']
|
styleUrls: ['./notify-info.component.scss'],
|
||||||
})
|
})
|
||||||
|
/**
|
||||||
|
* Component for displaying COAR notification information.
|
||||||
|
*/
|
||||||
export class NotifyInfoComponent implements OnInit {
|
export class NotifyInfoComponent implements OnInit {
|
||||||
coarLdnEnabled: boolean;
|
/**
|
||||||
coarRestApiUrl: string;
|
* Observable containing the COAR REST INBOX API URLs.
|
||||||
|
*/
|
||||||
|
coarRestApiUrl: Observable<string[]> = of([]);
|
||||||
|
|
||||||
constructor(
|
constructor(private notifyInfoService: NotifyInfoService) {}
|
||||||
public notifyInfoService: NotifyInfoService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.coarRestApiUrl = this.notifyInfoService.getCoarLdnRestApiUrl();
|
this.coarRestApiUrl = this.notifyInfoService.getCoarLdnLocalInboxUrls();
|
||||||
|
}
|
||||||
this.notifyInfoService.isCoarConfigEnabled().subscribe(value => {
|
|
||||||
this.coarLdnEnabled = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,49 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { NotifyInfoGuard } from './notify-info.guard';
|
import { NotifyInfoGuard } from './notify-info.guard';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { NotifyInfoService } from './notify-info.service';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
describe('NotifyInfoGuard', () => {
|
describe('NotifyInfoGuard', () => {
|
||||||
let guard: NotifyInfoGuard;
|
let guard: NotifyInfoGuard;
|
||||||
|
let notifyInfoServiceSpy: any;
|
||||||
|
let router: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({});
|
notifyInfoServiceSpy = jasmine.createSpyObj('NotifyInfoService', ['isCoarConfigEnabled']);
|
||||||
|
router = jasmine.createSpyObj('Router', ['parseUrl']);
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
NotifyInfoGuard,
|
||||||
|
{ provide: NotifyInfoService, useValue: notifyInfoServiceSpy},
|
||||||
|
{ provide: Router, useValue: router}
|
||||||
|
]
|
||||||
|
});
|
||||||
guard = TestBed.inject(NotifyInfoGuard);
|
guard = TestBed.inject(NotifyInfoGuard);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(guard).toBeTruthy();
|
expect(guard).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return true if COAR config is enabled', (done) => {
|
||||||
|
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(true));
|
||||||
|
|
||||||
|
guard.canActivate(null, null).subscribe((result) => {
|
||||||
|
expect(result).toBe(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call parseUrl method of Router if COAR config is not enabled', (done) => {
|
||||||
|
notifyInfoServiceSpy.isCoarConfigEnabled.and.returnValue(of(false));
|
||||||
|
router.parseUrl.and.returnValue(of('/404'));
|
||||||
|
|
||||||
|
guard.canActivate(null, null).subscribe(() => {
|
||||||
|
expect(router.parseUrl).toHaveBeenCalledWith('/404');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -16,7 +16,7 @@ export class NotifyInfoGuard implements CanActivate {
|
|||||||
canActivate(
|
canActivate(
|
||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot
|
state: RouterStateSnapshot
|
||||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
): Observable<boolean | UrlTree> {
|
||||||
return this.notifyInfoService.isCoarConfigEnabled().pipe(
|
return this.notifyInfoService.isCoarConfigEnabled().pipe(
|
||||||
map(coarLdnEnabled => {
|
map(coarLdnEnabled => {
|
||||||
if (coarLdnEnabled) {
|
if (coarLdnEnabled) {
|
||||||
|
@@ -1,16 +1,50 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { NotifyInfoService } from './notify-info.service';
|
import { NotifyInfoService } from './notify-info.service';
|
||||||
|
import { ConfigurationDataService } from '../../data/configuration-data.service';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
describe('NotifyInfoService', () => {
|
describe('NotifyInfoService', () => {
|
||||||
let service: NotifyInfoService;
|
let service: NotifyInfoService;
|
||||||
|
let configurationDataService: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({});
|
configurationDataService = {
|
||||||
|
findByPropertyName: jasmine.createSpy('findByPropertyName').and.returnValue(of({})),
|
||||||
|
};
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
NotifyInfoService,
|
||||||
|
{ provide: ConfigurationDataService, useValue: configurationDataService },
|
||||||
|
]
|
||||||
|
});
|
||||||
service = TestBed.inject(NotifyInfoService);
|
service = TestBed.inject(NotifyInfoService);
|
||||||
|
configurationDataService = TestBed.inject(ConfigurationDataService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(service).toBeTruthy();
|
expect(service).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should retrieve and map coar configuration', () => {
|
||||||
|
const mockResponse = { payload: { values: ['true'] } };
|
||||||
|
(configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(of(mockResponse));
|
||||||
|
|
||||||
|
service.isCoarConfigEnabled().subscribe((result) => {
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve and map LDN local inbox URLs', () => {
|
||||||
|
const mockResponse = { values: ['inbox1', 'inbox2'] };
|
||||||
|
(configurationDataService.findByPropertyName as jasmine.Spy).and.returnValue(of(mockResponse));
|
||||||
|
|
||||||
|
service.getCoarLdnLocalInboxUrls().subscribe((result) => {
|
||||||
|
expect(result).toEqual(['inbox1', 'inbox2']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the inbox relation link', () => {
|
||||||
|
expect(service.getInboxRelationLink()).toBe('http://www.w3.org/ns/ldp#inbox');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,14 +1,19 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { getFirstSucceededRemoteData } from '../../shared/operators';
|
import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../../shared/operators';
|
||||||
import { ConfigurationDataService } from '../../data/configuration-data.service';
|
import { ConfigurationDataService } from '../../data/configuration-data.service';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
import { DefaultAppConfig } from '../../../../config/default-app-config';
|
import { ConfigurationProperty } from '../../shared/configuration-property.model';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class NotifyInfoService {
|
export class NotifyInfoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relation link for the inbox
|
||||||
|
*/
|
||||||
|
private _inboxRelationLink = 'http://www.w3.org/ns/ldp#inbox';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private configService: ConfigurationDataService,
|
private configService: ConfigurationDataService,
|
||||||
) {}
|
) {}
|
||||||
@@ -24,15 +29,25 @@ export class NotifyInfoService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCoarLdnRestApiUrl(): string {
|
/**
|
||||||
const appConfig = new DefaultAppConfig();
|
* Get the url of the local inbox from the REST configuration
|
||||||
const restConfig = appConfig.rest;
|
* @returns the url of the local inbox
|
||||||
|
*/
|
||||||
|
getCoarLdnLocalInboxUrls(): Observable<string[]> {
|
||||||
|
return this.configService.findByPropertyName('ldn.notify.inbox').pipe(
|
||||||
|
getFirstSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((response: ConfigurationProperty) => {
|
||||||
|
return response.values;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const ssl = restConfig.ssl;
|
/**
|
||||||
const host = restConfig.host;
|
* Method to get the relation link for the inbox
|
||||||
const port = restConfig.port;
|
* @returns the relation link for the inbox
|
||||||
const namespace = restConfig.nameSpace;
|
*/
|
||||||
|
getInboxRelationLink(): string {
|
||||||
return `${ssl ? 'https' : 'http'}://${host}:${port}${namespace}`;
|
return this._inboxRelationLink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -190,7 +190,11 @@ import { SuggestionSource } from './suggestion-notifications/reciter-suggestions
|
|||||||
import { LdnServicesService } from '../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
import { LdnServicesService } from '../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||||
import { LdnService } from '../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
import { LdnService } from '../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
||||||
import { LdnItemfiltersService } from '../admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service';
|
import { LdnItemfiltersService } from '../admin/admin-ldn-services/ldn-services-data/ldn-itemfilters-data.service';
|
||||||
import { Itemfilter } from "../admin/admin-ldn-services/ldn-services-model/ldn-service-itemfilters";
|
import { Itemfilter } from '../admin/admin-ldn-services/ldn-services-model/ldn-service-itemfilters';
|
||||||
|
import {
|
||||||
|
CoarNotifyConfigDataService
|
||||||
|
} from '../submission/sections/section-coar-notify/coar-notify-config-data.service';
|
||||||
|
import { SubmissionCoarNotifyConfig } from '../submission/sections/section-coar-notify/submission-coar-notify.config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -315,7 +319,8 @@ const PROVIDERS = [
|
|||||||
OrcidHistoryDataService,
|
OrcidHistoryDataService,
|
||||||
SupervisionOrderDataService,
|
SupervisionOrderDataService,
|
||||||
LdnServicesService,
|
LdnServicesService,
|
||||||
LdnItemfiltersService
|
LdnItemfiltersService,
|
||||||
|
CoarNotifyConfigDataService
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -398,7 +403,8 @@ export const models =
|
|||||||
SuggestionTarget,
|
SuggestionTarget,
|
||||||
SuggestionSource,
|
SuggestionSource,
|
||||||
LdnService,
|
LdnService,
|
||||||
Itemfilter
|
Itemfilter,
|
||||||
|
SubmissionCoarNotifyConfig
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -25,7 +25,6 @@ import { RequestParam } from '../cache/models/request-param.model';
|
|||||||
import { ObjectCacheEntry } from '../cache/object-cache.reducer';
|
import { ObjectCacheEntry } from '../cache/object-cache.reducer';
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
import { DSpaceSerializer } from '../dspace-rest/dspace.serializer';
|
||||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload } from '../shared/operators';
|
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload } from '../shared/operators';
|
||||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||||
|
@@ -26,3 +26,5 @@ export type WorkspaceitemSectionDataType
|
|||||||
| WorkspaceitemSectionSherpaPoliciesObject
|
| WorkspaceitemSectionSherpaPoliciesObject
|
||||||
| WorkspaceitemSectionIdentifiersObject
|
| WorkspaceitemSectionIdentifiersObject
|
||||||
| string;
|
| string;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ import { Item } from '../shared/item.model';
|
|||||||
import { WorkspaceItem } from './models/workspaceitem.model';
|
import { WorkspaceItem } from './models/workspaceitem.model';
|
||||||
import { RequestEntry } from '../data/request-entry.model';
|
import { RequestEntry } from '../data/request-entry.model';
|
||||||
import { CoreState } from '../core-state.model';
|
import { CoreState } from '../core-state.model';
|
||||||
import { testSearchDataImplementation } from '../data/base/search-data.spec';
|
|
||||||
import { testDeleteDataImplementation } from '../data/base/delete-data.spec';
|
import { testDeleteDataImplementation } from '../data/base/delete-data.spec';
|
||||||
|
|
||||||
describe('WorkspaceitemDataService test', () => {
|
describe('WorkspaceitemDataService test', () => {
|
||||||
@@ -84,17 +83,19 @@ describe('WorkspaceitemDataService test', () => {
|
|||||||
function initTestService() {
|
function initTestService() {
|
||||||
hrefOnlyDataService = getMockHrefOnlyDataService();
|
hrefOnlyDataService = getMockHrefOnlyDataService();
|
||||||
return new WorkspaceitemDataService(
|
return new WorkspaceitemDataService(
|
||||||
|
comparator,
|
||||||
|
halService,
|
||||||
|
http,
|
||||||
|
notificationsService,
|
||||||
requestService,
|
requestService,
|
||||||
rdbService,
|
rdbService,
|
||||||
objectCache,
|
objectCache,
|
||||||
halService,
|
store,
|
||||||
notificationsService,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('composition', () => {
|
describe('composition', () => {
|
||||||
const initService = () => new WorkspaceitemDataService(null, null, null, null, null);
|
const initService = () => new WorkspaceitemDataService(null, null, null, null, null, null, null, null);
|
||||||
testSearchDataImplementation(initService);
|
|
||||||
testDeleteDataImplementation(initService);
|
testDeleteDataImplementation(initService);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ describe('WorkspaceitemDataService test', () => {
|
|||||||
service = initTestService();
|
service = initTestService();
|
||||||
|
|
||||||
spyOn((service as any), 'findByHref').and.callThrough();
|
spyOn((service as any), 'findByHref').and.callThrough();
|
||||||
spyOn((service as any), 'getSearchByHref').and.returnValue(searchRequestURL$);
|
spyOn((service as any), 'getIDHref').and.callThrough();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -138,7 +139,7 @@ describe('WorkspaceitemDataService test', () => {
|
|||||||
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
|
|
||||||
expect((service as any).findByHref).toHaveBeenCalledWith(searchRequestURL$, true, true);
|
expect((service as any).findByHref).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a RemoteData<WorkspaceItem> for the search', () => {
|
it('should return a RemoteData<WorkspaceItem> for the search', () => {
|
||||||
|
@@ -50,6 +50,20 @@ export class WorkspaceitemDataService extends IdentifiableDataService<WorkspaceI
|
|||||||
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing object on the server
|
||||||
|
* @param href The self link of the object to be removed
|
||||||
|
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||||
|
* metadata should be saved as real metadata
|
||||||
|
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||||
|
* errorMessage, timeCompleted, etc
|
||||||
|
* Only emits once all request related to the DSO has been invalidated.
|
||||||
|
*/
|
||||||
|
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
|
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the WorkspaceItem object found through the UUID of an item
|
* Return the WorkspaceItem object found through the UUID of an item
|
||||||
*
|
*
|
||||||
|
@@ -84,6 +84,16 @@ export class QualityAssuranceEventDataService extends IdentifiableDataService<Qu
|
|||||||
return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow);
|
return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for retrieving Quality Assurance events by topic and target.
|
||||||
|
* @param options (Optional) The search options to use when retrieving the events.
|
||||||
|
* @param linksToFollow (Optional) The links to follow when retrieving the events.
|
||||||
|
* @returns An observable of the remote data containing the paginated list of Quality Assurance events.
|
||||||
|
*/
|
||||||
|
public searchEventsByTopic(options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<QualityAssuranceEventObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceEventObject>>> {
|
||||||
|
return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear findByTopic requests from cache
|
* Clear findByTopic requests from cache
|
||||||
*/
|
*/
|
||||||
|
@@ -16,6 +16,7 @@ import { PaginatedList } from '../../../data/paginated-list.model';
|
|||||||
import { FindListOptions } from '../../../data/find-list-options.model';
|
import { FindListOptions } from '../../../data/find-list-options.model';
|
||||||
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
||||||
import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
||||||
|
import { SearchData, SearchDataImpl } from 'src/app/core/data/base/search-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The service handling all Quality Assurance source REST requests.
|
* The service handling all Quality Assurance source REST requests.
|
||||||
@@ -25,6 +26,9 @@ import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
|||||||
export class QualityAssuranceSourceDataService extends IdentifiableDataService<QualityAssuranceSourceObject> {
|
export class QualityAssuranceSourceDataService extends IdentifiableDataService<QualityAssuranceSourceObject> {
|
||||||
|
|
||||||
private findAllData: FindAllData<QualityAssuranceSourceObject>;
|
private findAllData: FindAllData<QualityAssuranceSourceObject>;
|
||||||
|
private searchAllData: SearchData<QualityAssuranceSourceObject>;
|
||||||
|
|
||||||
|
private searchByTargetMethod = 'byTarget';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize service variables
|
* Initialize service variables
|
||||||
@@ -43,6 +47,7 @@ export class QualityAssuranceSourceDataService extends IdentifiableDataService<Q
|
|||||||
) {
|
) {
|
||||||
super('qualityassurancesources', requestService, rdbService, objectCache, halService);
|
super('qualityassurancesources', requestService, rdbService, objectCache, halService);
|
||||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.searchAllData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,4 +89,16 @@ export class QualityAssuranceSourceDataService extends IdentifiableDataService<Q
|
|||||||
public getSource(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> {
|
public getSource(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<QualityAssuranceSourceObject>> {
|
||||||
return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a paginated list of QualityAssuranceSourceObject objects that are associated with a given target object.
|
||||||
|
* @param options The options for the search query.
|
||||||
|
* @param useCachedVersionIfAvailable Whether to use a cached version of the data if available.
|
||||||
|
* @param reRequestOnStale Whether to re-request the data if the cached version is stale.
|
||||||
|
* @param linksToFollow The links to follow to retrieve the data.
|
||||||
|
* @returns An observable that emits a RemoteData object containing the paginated list of QualityAssuranceSourceObject objects.
|
||||||
|
*/
|
||||||
|
public getSourcesByTarget(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceSourceObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceSourceObject>>> {
|
||||||
|
return this.searchAllData.searchBy(this.searchByTargetMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,22 +80,53 @@ describe('QualityAssuranceTopicDataService', () => {
|
|||||||
notificationsService
|
notificationsService
|
||||||
);
|
);
|
||||||
|
|
||||||
spyOn((service as any).findAllData, 'findAll').and.callThrough();
|
spyOn((service as any).searchData, 'searchBy').and.callThrough();
|
||||||
spyOn((service as any), 'findById').and.callThrough();
|
spyOn((service as any), 'findById').and.callThrough();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getTopics', () => {
|
describe('searchTopicsByTarget', () => {
|
||||||
it('should call findListByHref', (done) => {
|
it('should call searchData.searchBy with the correct parameters', () => {
|
||||||
service.getTopics().subscribe(
|
const options = { elementsPerPage: 10 };
|
||||||
(res) => {
|
const useCachedVersionIfAvailable = true;
|
||||||
expect((service as any).findAllData.findAll).toHaveBeenCalledWith({}, true, true);
|
const reRequestOnStale = true;
|
||||||
}
|
|
||||||
|
service.searchTopicsByTarget(options, useCachedVersionIfAvailable, reRequestOnStale);
|
||||||
|
|
||||||
|
expect((service as any).searchData.searchBy).toHaveBeenCalledWith(
|
||||||
|
'byTarget',
|
||||||
|
options,
|
||||||
|
useCachedVersionIfAvailable,
|
||||||
|
reRequestOnStale
|
||||||
);
|
);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a RemoteData<PaginatedList<QualityAssuranceTopicObject>> for the object with the given URL', () => {
|
it('should return a RemoteData<PaginatedList<QualityAssuranceTopicObject>> for the object with the given URL', () => {
|
||||||
const result = service.getTopics();
|
const result = service.searchTopicsByTarget();
|
||||||
|
const expected = cold('(a)', {
|
||||||
|
a: paginatedListRD
|
||||||
|
});
|
||||||
|
expect(result).toBeObservable(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('searchTopicsBySource', () => {
|
||||||
|
it('should call searchData.searchBy with the correct parameters', () => {
|
||||||
|
const options = { elementsPerPage: 10 };
|
||||||
|
const useCachedVersionIfAvailable = true;
|
||||||
|
const reRequestOnStale = true;
|
||||||
|
|
||||||
|
service.searchTopicsBySource(options, useCachedVersionIfAvailable, reRequestOnStale);
|
||||||
|
|
||||||
|
expect((service as any).searchData.searchBy).toHaveBeenCalledWith(
|
||||||
|
'bySource',
|
||||||
|
options,
|
||||||
|
useCachedVersionIfAvailable,
|
||||||
|
reRequestOnStale,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a RemoteData<PaginatedList<QualityAssuranceTopicObject>> for the object with the given URL', () => {
|
||||||
|
const result = service.searchTopicsBySource();
|
||||||
const expected = cold('(a)', {
|
const expected = cold('(a)', {
|
||||||
a: paginatedListRD
|
a: paginatedListRD
|
||||||
});
|
});
|
||||||
@@ -121,5 +152,4 @@ describe('QualityAssuranceTopicDataService', () => {
|
|||||||
expect(result).toBeObservable(expected);
|
expect(result).toBeObservable(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -15,6 +15,7 @@ import { FindListOptions } from '../../../data/find-list-options.model';
|
|||||||
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
||||||
import { dataService } from '../../../data/base/data-service.decorator';
|
import { dataService } from '../../../data/base/data-service.decorator';
|
||||||
import { QUALITY_ASSURANCE_TOPIC_OBJECT } from '../models/quality-assurance-topic-object.resource-type';
|
import { QUALITY_ASSURANCE_TOPIC_OBJECT } from '../models/quality-assurance-topic-object.resource-type';
|
||||||
|
import { SearchData, SearchDataImpl } from '../../../../core/data/base/search-data';
|
||||||
import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,6 +26,10 @@ import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data';
|
|||||||
export class QualityAssuranceTopicDataService extends IdentifiableDataService<QualityAssuranceTopicObject> {
|
export class QualityAssuranceTopicDataService extends IdentifiableDataService<QualityAssuranceTopicObject> {
|
||||||
|
|
||||||
private findAllData: FindAllData<QualityAssuranceTopicObject>;
|
private findAllData: FindAllData<QualityAssuranceTopicObject>;
|
||||||
|
private searchData: SearchData<QualityAssuranceTopicObject>;
|
||||||
|
|
||||||
|
private searchByTargetMethod = 'byTarget';
|
||||||
|
private searchBySourceMethod = 'bySource';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize service variables
|
* Initialize service variables
|
||||||
@@ -43,23 +48,31 @@ export class QualityAssuranceTopicDataService extends IdentifiableDataService<Qu
|
|||||||
) {
|
) {
|
||||||
super('qualityassurancetopics', requestService, rdbService, objectCache, halService);
|
super('qualityassurancetopics', requestService, rdbService, objectCache, halService);
|
||||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the list of Quality Assurance topics.
|
* Search for Quality Assurance topics.
|
||||||
*
|
* @param options The search options.
|
||||||
* @param options Find list options object.
|
* @param useCachedVersionIfAvailable Whether to use cached version if available.
|
||||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
* @param reRequestOnStale Whether to re-request on stale.
|
||||||
* no valid cached version. Defaults to true
|
* @param linksToFollow The links to follow.
|
||||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
* @returns An observable of remote data containing a paginated list of Quality Assurance topics.
|
||||||
* requested after the response becomes stale
|
|
||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved.
|
|
||||||
*
|
|
||||||
* @return Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>>
|
|
||||||
* The list of Quality Assurance topics.
|
|
||||||
*/
|
*/
|
||||||
public getTopics(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> {
|
public searchTopicsByTarget(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> {
|
||||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
return this.searchData.searchBy(this.searchByTargetMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for quality assurance topics by source.
|
||||||
|
* @param options The search options.
|
||||||
|
* @param useCachedVersionIfAvailable Whether to use a cached version if available.
|
||||||
|
* @param reRequestOnStale Whether to re-request the data if it's stale.
|
||||||
|
* @param linksToFollow The links to follow.
|
||||||
|
* @returns An observable of the remote data containing the paginated list of quality assurance topics.
|
||||||
|
*/
|
||||||
|
public searchTopicsBySource(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<QualityAssuranceTopicObject>[]): Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>> {
|
||||||
|
return this.searchData.searchBy(this.searchBySourceMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
// ... test imports
|
// ... test imports
|
||||||
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, inject, TestBed,waitForAsync } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ import { By } from '@angular/platform-browser';
|
|||||||
|
|
||||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
import { StoreModule } from '@ngrx/store';
|
import { StoreModule } from '@ngrx/store';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
// Load the implementations that should be tested
|
// Load the implementations that should be tested
|
||||||
import { FooterComponent } from './footer.component';
|
import { FooterComponent } from './footer.component';
|
||||||
@@ -17,15 +18,21 @@ import { TranslateLoaderMock } from '../shared/mocks/translate-loader.mock';
|
|||||||
import { storeModuleConfig } from '../app.reducer';
|
import { storeModuleConfig } from '../app.reducer';
|
||||||
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
|
||||||
import { AuthorizationDataServiceStub } from '../shared/testing/authorization-service.stub';
|
import { AuthorizationDataServiceStub } from '../shared/testing/authorization-service.stub';
|
||||||
|
import { NotifyInfoService } from '../core/coar-notify/notify-info/notify-info.service';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
|
||||||
|
|
||||||
let comp: FooterComponent;
|
let comp: FooterComponent;
|
||||||
|
let compAny: any;
|
||||||
let fixture: ComponentFixture<FooterComponent>;
|
let fixture: ComponentFixture<FooterComponent>;
|
||||||
let de: DebugElement;
|
let de: DebugElement;
|
||||||
let el: HTMLElement;
|
let el: HTMLElement;
|
||||||
|
|
||||||
describe('Footer component', () => {
|
let notifyInfoService = {
|
||||||
|
isCoarConfigEnabled: () => of(true)
|
||||||
|
};
|
||||||
|
|
||||||
// waitForAsync beforeEach
|
describe('Footer component', () => {
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
return TestBed.configureTestingModule({
|
return TestBed.configureTestingModule({
|
||||||
imports: [CommonModule, StoreModule.forRoot({}, storeModuleConfig), TranslateModule.forRoot({
|
imports: [CommonModule, StoreModule.forRoot({}, storeModuleConfig), TranslateModule.forRoot({
|
||||||
@@ -38,6 +45,7 @@ describe('Footer component', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
{ provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub },
|
{ provide: AuthorizationDataService, useClass: AuthorizationDataServiceStub },
|
||||||
|
{ provide: NotifyInfoService, useValue: notifyInfoService }
|
||||||
],
|
],
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
});
|
});
|
||||||
@@ -46,9 +54,8 @@ describe('Footer component', () => {
|
|||||||
// synchronous beforeEach
|
// synchronous beforeEach
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(FooterComponent);
|
fixture = TestBed.createComponent(FooterComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
comp = fixture.componentInstance; // component test instance
|
compAny = comp as any;
|
||||||
|
|
||||||
// query for the title <p> by CSS element selector
|
// query for the title <p> by CSS element selector
|
||||||
de = fixture.debugElement.query(By.css('p'));
|
de = fixture.debugElement.query(By.css('p'));
|
||||||
el = de.nativeElement;
|
el = de.nativeElement;
|
||||||
@@ -59,4 +66,56 @@ describe('Footer component', () => {
|
|||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should set showPrivacyPolicy to the value of environment.info.enablePrivacyStatement', () => {
|
||||||
|
expect(comp.showPrivacyPolicy).toBe(environment.info.enablePrivacyStatement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set showEndUserAgreement to the value of environment.info.enableEndUserAgreement', () => {
|
||||||
|
expect(comp.showEndUserAgreement).toBe(environment.info.enableEndUserAgreement);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('showCookieSettings', () => {
|
||||||
|
it('should call cookies.showSettings() if cookies is defined', () => {
|
||||||
|
const cookies = jasmine.createSpyObj('cookies', ['showSettings']);
|
||||||
|
compAny.cookies = cookies;
|
||||||
|
comp.showCookieSettings();
|
||||||
|
expect(cookies.showSettings).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call cookies.showSettings() if cookies is undefined', () => {
|
||||||
|
compAny.cookies = undefined;
|
||||||
|
expect(() => comp.showCookieSettings()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false', () => {
|
||||||
|
expect(comp.showCookieSettings()).toBeFalse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when coarLdnEnabled is true', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(notifyInfoService, 'isCoarConfigEnabled').and.returnValue(of(true));
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set coarLdnEnabled based on notifyInfoService', () => {
|
||||||
|
expect(comp.coarLdnEnabled).toBeTruthy();
|
||||||
|
// Check if COAR Notify section is rendered
|
||||||
|
const notifySection = fixture.debugElement.query(By.css('.notify-enabled'));
|
||||||
|
expect(notifySection).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect to info/coar-notify-support', () => {
|
||||||
|
// Check if the link to the COAR Notify support page is present
|
||||||
|
const routerLink = fixture.debugElement.query(By.css('a[routerLink="info/coar-notify-support"].coar-notify-support-route'));
|
||||||
|
expect(routerLink).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have an img tag with the class "n-coar" when coarLdnEnabled is true', fakeAsync(() => {
|
||||||
|
// Check if the img tag with the class "n-coar" is present
|
||||||
|
const imgTag = fixture.debugElement.query(By.css('.notify-enabled img.n-coar'));
|
||||||
|
expect(imgTag).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,22 +1,50 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
|
||||||
import { map } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Site } from '../core/shared/site.model';
|
import { Site } from '../core/shared/site.model';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
|
import { isPlatformServer } from '@angular/common';
|
||||||
|
import { ServerResponseService } from '../core/services/server-response.service';
|
||||||
|
import { NotifyInfoService } from '../core/coar-notify/notify-info/notify-info.service';
|
||||||
|
import { LinkDefinition, LinkHeadService } from '../core/services/link-head.service';
|
||||||
|
import { isNotEmpty } from '../shared/empty.util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-home-page',
|
selector: 'ds-home-page',
|
||||||
styleUrls: ['./home-page.component.scss'],
|
styleUrls: ['./home-page.component.scss'],
|
||||||
templateUrl: './home-page.component.html'
|
templateUrl: './home-page.component.html'
|
||||||
})
|
})
|
||||||
export class HomePageComponent implements OnInit {
|
export class HomePageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
site$: Observable<Site>;
|
site$: Observable<Site>;
|
||||||
recentSubmissionspageSize: number;
|
recentSubmissionspageSize: number;
|
||||||
|
/**
|
||||||
|
* An array of LinkDefinition objects representing inbox links for the home page.
|
||||||
|
*/
|
||||||
|
inboxLinks: LinkDefinition[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
private responseService: ServerResponseService,
|
||||||
|
private notifyInfoService: NotifyInfoService,
|
||||||
|
protected linkHeadService: LinkHeadService,
|
||||||
|
@Inject(PLATFORM_ID) private platformId: string
|
||||||
) {
|
) {
|
||||||
this.recentSubmissionspageSize = environment.homePage.recentSubmissions.pageSize;
|
this.recentSubmissionspageSize = environment.homePage.recentSubmissions.pageSize;
|
||||||
|
// Get COAR REST API URLs from REST configuration
|
||||||
|
// only if COAR configuration is enabled
|
||||||
|
this.notifyInfoService.isCoarConfigEnabled().pipe(
|
||||||
|
switchMap((coarLdnEnabled: boolean) => {
|
||||||
|
if (coarLdnEnabled) {
|
||||||
|
return this.notifyInfoService.getCoarLdnLocalInboxUrls();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).subscribe((coarRestApiUrls: string[]) => {
|
||||||
|
if (coarRestApiUrls.length > 0) {
|
||||||
|
this.initPageLinks(coarRestApiUrls);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -24,4 +52,38 @@ export class HomePageComponent implements OnInit {
|
|||||||
map((data) => data.site as Site),
|
map((data) => data.site as Site),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes page links for COAR REST API URLs.
|
||||||
|
* @param coarRestApiUrls An array of COAR REST API URLs.
|
||||||
|
*/
|
||||||
|
private initPageLinks(coarRestApiUrls: string[]): void {
|
||||||
|
const rel = this.notifyInfoService.getInboxRelationLink();
|
||||||
|
let links = '';
|
||||||
|
coarRestApiUrls.forEach((coarRestApiUrl: string) => {
|
||||||
|
// Add link to head
|
||||||
|
let tag: LinkDefinition = {
|
||||||
|
href: coarRestApiUrl,
|
||||||
|
rel: rel
|
||||||
|
};
|
||||||
|
this.inboxLinks.push(tag);
|
||||||
|
this.linkHeadService.addTag(tag);
|
||||||
|
|
||||||
|
links = links + (isNotEmpty(links) ? ', ' : '') + `<${coarRestApiUrl}> ; rel="${rel}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isPlatformServer(this.platformId)) {
|
||||||
|
// Add link to response header
|
||||||
|
this.responseService.setHeader('Link', links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It removes the inbox links from the head of the html.
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.inboxLinks.forEach((link: LinkDefinition) => {
|
||||||
|
this.linkHeadService.removeTag(`href='${link.href}'`);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import { RemoteData } from '../../core/data/remote-data';
|
|||||||
import { ServerResponseService } from '../../core/services/server-response.service';
|
import { ServerResponseService } from '../../core/services/server-response.service';
|
||||||
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
||||||
import { LinkHeadService } from '../../core/services/link-head.service';
|
import { LinkHeadService } from '../../core/services/link-head.service';
|
||||||
|
import { NotifyInfoService } from '../../core/coar-notify/notify-info/notify-info.service';
|
||||||
|
|
||||||
const mockItem: Item = Object.assign(new Item(), {
|
const mockItem: Item = Object.assign(new Item(), {
|
||||||
bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
||||||
@@ -61,6 +62,7 @@ describe('FullItemPageComponent', () => {
|
|||||||
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
|
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
|
||||||
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
|
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
|
||||||
let linkHeadService: jasmine.SpyObj<LinkHeadService>;
|
let linkHeadService: jasmine.SpyObj<LinkHeadService>;
|
||||||
|
let notifyInfoService: jasmine.SpyObj<NotifyInfoService>;
|
||||||
|
|
||||||
const mocklink = {
|
const mocklink = {
|
||||||
href: 'http://test.org',
|
href: 'http://test.org',
|
||||||
@@ -105,6 +107,12 @@ describe('FullItemPageComponent', () => {
|
|||||||
removeTag: jasmine.createSpy('removeTag'),
|
removeTag: jasmine.createSpy('removeTag'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
notifyInfoService = jasmine.createSpyObj('NotifyInfoService', {
|
||||||
|
isCoarConfigEnabled: observableOf(true),
|
||||||
|
getCoarLdnLocalInboxUrls: observableOf(['http://test.org']),
|
||||||
|
getInboxRelationLink: observableOf('http://test.org'),
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot({
|
imports: [TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
@@ -122,6 +130,7 @@ describe('FullItemPageComponent', () => {
|
|||||||
{ provide: ServerResponseService, useValue: serverResponseService },
|
{ provide: ServerResponseService, useValue: serverResponseService },
|
||||||
{ provide: SignpostingDataService, useValue: signpostingDataService },
|
{ provide: SignpostingDataService, useValue: signpostingDataService },
|
||||||
{ provide: LinkHeadService, useValue: linkHeadService },
|
{ provide: LinkHeadService, useValue: linkHeadService },
|
||||||
|
{ provide: NotifyInfoService, useValue: notifyInfoService },
|
||||||
{ provide: PLATFORM_ID, useValue: 'server' }
|
{ provide: PLATFORM_ID, useValue: 'server' }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
@@ -178,7 +187,7 @@ describe('FullItemPageComponent', () => {
|
|||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposting links', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('when the item is withdrawn and the user is not an admin', () => {
|
describe('when the item is withdrawn and the user is not an admin', () => {
|
||||||
@@ -207,7 +216,7 @@ describe('FullItemPageComponent', () => {
|
|||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposting links', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -224,7 +233,7 @@ describe('FullItemPageComponent', () => {
|
|||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposting links', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -19,6 +19,7 @@ import { AuthorizationDataService } from '../../core/data/feature-authorization/
|
|||||||
import { ServerResponseService } from '../../core/services/server-response.service';
|
import { ServerResponseService } from '../../core/services/server-response.service';
|
||||||
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
||||||
import { LinkHeadService } from '../../core/services/link-head.service';
|
import { LinkHeadService } from '../../core/services/link-head.service';
|
||||||
|
import { NotifyInfoService } from '../../core/coar-notify/notify-info/notify-info.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a full item page.
|
* This component renders a full item page.
|
||||||
@@ -55,9 +56,10 @@ export class FullItemPageComponent extends ItemPageComponent implements OnInit,
|
|||||||
protected responseService: ServerResponseService,
|
protected responseService: ServerResponseService,
|
||||||
protected signpostingDataService: SignpostingDataService,
|
protected signpostingDataService: SignpostingDataService,
|
||||||
protected linkHeadService: LinkHeadService,
|
protected linkHeadService: LinkHeadService,
|
||||||
|
protected notifyInfoService: NotifyInfoService,
|
||||||
@Inject(PLATFORM_ID) protected platformId: string,
|
@Inject(PLATFORM_ID) protected platformId: string,
|
||||||
) {
|
) {
|
||||||
super(route, router, items, authService, authorizationService, responseService, signpostingDataService, linkHeadService, platformId);
|
super(route, router, items, authService, authorizationService, responseService, signpostingDataService, linkHeadService, notifyInfoService, platformId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** AoT inheritance fix, will hopefully be resolved in the near future **/
|
/*** AoT inheritance fix, will hopefully be resolved in the near future **/
|
||||||
|
@@ -60,6 +60,7 @@ import { ThemedItemAlertsComponent } from './alerts/themed-item-alerts.component
|
|||||||
import {
|
import {
|
||||||
ThemedFullFileSectionComponent
|
ThemedFullFileSectionComponent
|
||||||
} from './full/field-components/file-section/themed-full-file-section.component';
|
} from './full/field-components/file-section/themed-full-file-section.component';
|
||||||
|
import { QaEventNotificationComponent } from './simple/qa-event-notification/qa-event-notification.component';
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
// put only entry components that use custom decorator
|
// put only entry components that use custom decorator
|
||||||
@@ -103,6 +104,7 @@ const DECLARATIONS = [
|
|||||||
ItemAlertsComponent,
|
ItemAlertsComponent,
|
||||||
ThemedItemAlertsComponent,
|
ThemedItemAlertsComponent,
|
||||||
BitstreamRequestACopyPageComponent,
|
BitstreamRequestACopyPageComponent,
|
||||||
|
QaEventNotificationComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
<div class="item-page" *ngIf="itemRD?.hasSucceeded" @fadeInOut>
|
<div class="item-page" *ngIf="itemRD?.hasSucceeded" @fadeInOut>
|
||||||
<div *ngIf="itemRD?.payload as item">
|
<div *ngIf="itemRD?.payload as item">
|
||||||
<ds-themed-item-alerts [item]="item"></ds-themed-item-alerts>
|
<ds-themed-item-alerts [item]="item"></ds-themed-item-alerts>
|
||||||
|
<ds-qa-event-notification [item]="item"></ds-qa-event-notification>
|
||||||
<ds-item-versions-notice [item]="item"></ds-item-versions-notice>
|
<ds-item-versions-notice [item]="item"></ds-item-versions-notice>
|
||||||
<ds-view-tracker [object]="item"></ds-view-tracker>
|
<ds-view-tracker [object]="item"></ds-view-tracker>
|
||||||
<ds-listable-object-component-loader *ngIf="!item.isWithdrawn || (isAdmin$|async)" [object]="item" [viewMode]="viewMode"></ds-listable-object-component-loader>
|
<ds-listable-object-component-loader *ngIf="!item.isWithdrawn || (isAdmin$|async)" [object]="item" [viewMode]="viewMode"></ds-listable-object-component-loader>
|
||||||
|
@@ -26,6 +26,7 @@ import { ServerResponseService } from '../../core/services/server-response.servi
|
|||||||
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
import { SignpostingDataService } from '../../core/data/signposting-data.service';
|
||||||
import { LinkDefinition, LinkHeadService } from '../../core/services/link-head.service';
|
import { LinkDefinition, LinkHeadService } from '../../core/services/link-head.service';
|
||||||
import { SignpostingLink } from '../../core/data/signposting-links.model';
|
import { SignpostingLink } from '../../core/data/signposting-links.model';
|
||||||
|
import { NotifyInfoService } from '../../core/coar-notify/notify-info/notify-info.service';
|
||||||
|
|
||||||
const mockItem: Item = Object.assign(new Item(), {
|
const mockItem: Item = Object.assign(new Item(), {
|
||||||
bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
bundles: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
||||||
@@ -62,6 +63,7 @@ describe('ItemPageComponent', () => {
|
|||||||
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
|
let serverResponseService: jasmine.SpyObj<ServerResponseService>;
|
||||||
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
|
let signpostingDataService: jasmine.SpyObj<SignpostingDataService>;
|
||||||
let linkHeadService: jasmine.SpyObj<LinkHeadService>;
|
let linkHeadService: jasmine.SpyObj<LinkHeadService>;
|
||||||
|
let notifyInfoService: jasmine.SpyObj<NotifyInfoService>;
|
||||||
|
|
||||||
const mockMetadataService = {
|
const mockMetadataService = {
|
||||||
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
|
/* eslint-disable no-empty,@typescript-eslint/no-empty-function */
|
||||||
@@ -73,6 +75,8 @@ describe('ItemPageComponent', () => {
|
|||||||
data: observableOf({ dso: createSuccessfulRemoteDataObject(mockItem) })
|
data: observableOf({ dso: createSuccessfulRemoteDataObject(mockItem) })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getCoarLdnLocalInboxUrls = ['http://InboxUrls.org', 'http://InboxUrls2.org'];
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
authService = jasmine.createSpyObj('authService', {
|
authService = jasmine.createSpyObj('authService', {
|
||||||
isAuthenticated: observableOf(true),
|
isAuthenticated: observableOf(true),
|
||||||
@@ -94,6 +98,12 @@ describe('ItemPageComponent', () => {
|
|||||||
removeTag: jasmine.createSpy('removeTag'),
|
removeTag: jasmine.createSpy('removeTag'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
notifyInfoService = jasmine.createSpyObj('NotifyInfoService', {
|
||||||
|
getInboxRelationLink: 'http://www.w3.org/ns/ldp#inbox',
|
||||||
|
isCoarConfigEnabled: observableOf(true),
|
||||||
|
getCoarLdnLocalInboxUrls: observableOf(getCoarLdnLocalInboxUrls),
|
||||||
|
});
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot({
|
imports: [TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
@@ -112,6 +122,7 @@ describe('ItemPageComponent', () => {
|
|||||||
{ provide: ServerResponseService, useValue: serverResponseService },
|
{ provide: ServerResponseService, useValue: serverResponseService },
|
||||||
{ provide: SignpostingDataService, useValue: signpostingDataService },
|
{ provide: SignpostingDataService, useValue: signpostingDataService },
|
||||||
{ provide: LinkHeadService, useValue: linkHeadService },
|
{ provide: LinkHeadService, useValue: linkHeadService },
|
||||||
|
{ provide: NotifyInfoService, useValue: notifyInfoService},
|
||||||
{ provide: PLATFORM_ID, useValue: 'server' },
|
{ provide: PLATFORM_ID, useValue: 'server' },
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -166,7 +177,7 @@ describe('ItemPageComponent', () => {
|
|||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposting links', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -175,7 +186,7 @@ describe('ItemPageComponent', () => {
|
|||||||
expect(comp.signpostingLinks).toEqual([mocklink, mocklink2]);
|
expect(comp.signpostingLinks).toEqual([mocklink, mocklink2]);
|
||||||
|
|
||||||
// Check if linkHeadService.addTag() was called with the correct arguments
|
// Check if linkHeadService.addTag() was called with the correct arguments
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(mockSignpostingLinks.length);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(mockSignpostingLinks.length + getCoarLdnLocalInboxUrls.length);
|
||||||
let expected: LinkDefinition = mockSignpostingLinks[0] as LinkDefinition;
|
let expected: LinkDefinition = mockSignpostingLinks[0] as LinkDefinition;
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledWith(expected);
|
expect(linkHeadService.addTag).toHaveBeenCalledWith(expected);
|
||||||
expected = {
|
expected = {
|
||||||
@@ -186,8 +197,7 @@ describe('ItemPageComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set Link header on the server', () => {
|
it('should set Link header on the server', () => {
|
||||||
|
expect(serverResponseService.setHeader).toHaveBeenCalledWith('Link', '<http://test.org> ; rel="rel1" ; type="type1" , <http://test2.org> ; rel="rel2" , <http://InboxUrls.org> ; rel="http://www.w3.org/ns/ldp#inbox", <http://InboxUrls2.org> ; rel="http://www.w3.org/ns/ldp#inbox"');
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalledWith('Link', '<http://test.org> ; rel="rel1" ; type="type1" , <http://test2.org> ; rel="rel2" ');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -215,9 +225,9 @@ describe('ItemPageComponent', () => {
|
|||||||
expect(objectLoader.nativeElement).toBeDefined();
|
expect(objectLoader.nativeElement).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposti`ng links`', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(4);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -234,7 +244,7 @@ describe('ItemPageComponent', () => {
|
|||||||
|
|
||||||
it('should add the signposting links', () => {
|
it('should add the signposting links', () => {
|
||||||
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
expect(serverResponseService.setHeader).toHaveBeenCalled();
|
||||||
expect(linkHeadService.addTag).toHaveBeenCalledTimes(2);
|
expect(linkHeadService.addTag).toHaveBeenCalledTimes(4);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -2,8 +2,8 @@ import { ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit, PLATFORM
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { isPlatformServer } from '@angular/common';
|
import { isPlatformServer } from '@angular/common';
|
||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, combineLatest } from 'rxjs';
|
||||||
import { map, take } from 'rxjs/operators';
|
import { map, switchMap, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ItemDataService } from '../../core/data/item-data.service';
|
import { ItemDataService } from '../../core/data/item-data.service';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
@@ -21,6 +21,7 @@ import { SignpostingDataService } from '../../core/data/signposting-data.service
|
|||||||
import { SignpostingLink } from '../../core/data/signposting-links.model';
|
import { SignpostingLink } from '../../core/data/signposting-links.model';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
import { LinkDefinition, LinkHeadService } from '../../core/services/link-head.service';
|
import { LinkDefinition, LinkHeadService } from '../../core/services/link-head.service';
|
||||||
|
import { NotifyInfoService } from 'src/app/core/coar-notify/notify-info/notify-info.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
@@ -32,7 +33,7 @@ import { LinkDefinition, LinkHeadService } from '../../core/services/link-head.s
|
|||||||
styleUrls: ['./item-page.component.scss'],
|
styleUrls: ['./item-page.component.scss'],
|
||||||
templateUrl: './item-page.component.html',
|
templateUrl: './item-page.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
animations: [fadeInOut]
|
animations: [fadeInOut],
|
||||||
})
|
})
|
||||||
export class ItemPageComponent implements OnInit, OnDestroy {
|
export class ItemPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@@ -68,6 +69,13 @@ export class ItemPageComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
signpostingLinks: SignpostingLink[] = [];
|
signpostingLinks: SignpostingLink[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of LinkDefinition objects representing inbox links for the item page.
|
||||||
|
*/
|
||||||
|
inboxTags: LinkDefinition[] = [];
|
||||||
|
|
||||||
|
coarRestApiUrls: string[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
@@ -77,6 +85,7 @@ export class ItemPageComponent implements OnInit, OnDestroy {
|
|||||||
protected responseService: ServerResponseService,
|
protected responseService: ServerResponseService,
|
||||||
protected signpostingDataService: SignpostingDataService,
|
protected signpostingDataService: SignpostingDataService,
|
||||||
protected linkHeadService: LinkHeadService,
|
protected linkHeadService: LinkHeadService,
|
||||||
|
protected notifyInfoService: NotifyInfoService,
|
||||||
@Inject(PLATFORM_ID) protected platformId: string
|
@Inject(PLATFORM_ID) protected platformId: string
|
||||||
) {
|
) {
|
||||||
this.initPageLinks();
|
this.initPageLinks();
|
||||||
@@ -106,7 +115,8 @@ export class ItemPageComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
private initPageLinks(): void {
|
private initPageLinks(): void {
|
||||||
this.route.params.subscribe(params => {
|
this.route.params.subscribe(params => {
|
||||||
this.signpostingDataService.getLinks(params.id).pipe(take(1)).subscribe((signpostingLinks: SignpostingLink[]) => {
|
combineLatest([this.signpostingDataService.getLinks(params.id).pipe(take(1)), this.getCoarLdnLocalInboxUrls()])
|
||||||
|
.subscribe(([signpostingLinks, coarRestApiUrls]) => {
|
||||||
let links = '';
|
let links = '';
|
||||||
this.signpostingLinks = signpostingLinks;
|
this.signpostingLinks = signpostingLinks;
|
||||||
|
|
||||||
@@ -124,6 +134,11 @@ export class ItemPageComponent implements OnInit, OnDestroy {
|
|||||||
this.linkHeadService.addTag(tag);
|
this.linkHeadService.addTag(tag);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (coarRestApiUrls.length > 0) {
|
||||||
|
let inboxLinks = this.initPageInboxLinks(coarRestApiUrls);
|
||||||
|
links = links + (isNotEmpty(links) ? ', ' : '') + inboxLinks;
|
||||||
|
}
|
||||||
|
|
||||||
if (isPlatformServer(this.platformId)) {
|
if (isPlatformServer(this.platformId)) {
|
||||||
this.responseService.setHeader('Link', links);
|
this.responseService.setHeader('Link', links);
|
||||||
}
|
}
|
||||||
@@ -131,9 +146,49 @@ export class ItemPageComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the COAR LDN local inbox URL if COAR configuration is enabled.
|
||||||
|
* If the COAR LDN local inbox URL is retrieved successfully, initializes the page inbox links.
|
||||||
|
*/
|
||||||
|
private getCoarLdnLocalInboxUrls(): Observable<string[]> {
|
||||||
|
return this.notifyInfoService.isCoarConfigEnabled().pipe(
|
||||||
|
switchMap((coarLdnEnabled: boolean) => {
|
||||||
|
if (coarLdnEnabled) {
|
||||||
|
return this.notifyInfoService.getCoarLdnLocalInboxUrls();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the page inbox links.
|
||||||
|
* @param coarRestApiUrls - An array of COAR REST API URLs.
|
||||||
|
*/
|
||||||
|
private initPageInboxLinks(coarRestApiUrls: string[]): string {
|
||||||
|
const rel = this.notifyInfoService.getInboxRelationLink();
|
||||||
|
let links = '';
|
||||||
|
|
||||||
|
coarRestApiUrls.forEach((coarRestApiUrl: string) => {
|
||||||
|
// Add link to head
|
||||||
|
let tag: LinkDefinition = {
|
||||||
|
href: coarRestApiUrl,
|
||||||
|
rel: rel
|
||||||
|
};
|
||||||
|
this.inboxTags.push(tag);
|
||||||
|
this.linkHeadService.addTag(tag);
|
||||||
|
|
||||||
|
links = links + (isNotEmpty(links) ? ', ' : '') + `<${coarRestApiUrl}> ; rel="${rel}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.signpostingLinks.forEach((link: SignpostingLink) => {
|
this.signpostingLinks.forEach((link: SignpostingLink) => {
|
||||||
this.linkHeadService.removeTag(`href='${link.href}'`);
|
this.linkHeadService.removeTag(`href='${link.href}'`);
|
||||||
});
|
});
|
||||||
|
this.inboxTags.forEach((link: LinkDefinition) => {
|
||||||
|
this.linkHeadService.removeTag(`href='${link.href}'`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -84,6 +84,18 @@
|
|||||||
[label]="'item.page.uri'">
|
[label]="'item.page.uri'">
|
||||||
</ds-item-page-uri-field>
|
</ds-item-page-uri-field>
|
||||||
<ds-item-page-collections [item]="object"></ds-item-page-collections>
|
<ds-item-page-collections [item]="object"></ds-item-page-collections>
|
||||||
|
<ds-generic-item-page-field [item]="object"
|
||||||
|
[fields]="['notify.relation.endorsedBy']"
|
||||||
|
[label]="'item.page.endorsed-by'">
|
||||||
|
</ds-generic-item-page-field>
|
||||||
|
<ds-generic-item-page-field [item]="object"
|
||||||
|
[fields]="['datacite.relation.isReviewedBy']"
|
||||||
|
[label]="'item.page.is-reviewed-by'">
|
||||||
|
</ds-generic-item-page-field>
|
||||||
|
<ds-generic-item-page-field [item]="object"
|
||||||
|
[fields]="['datacite.relation.isSupplementedBy']"
|
||||||
|
[label]="'item.page.is-supplemented-by'">
|
||||||
|
</ds-generic-item-page-field>
|
||||||
<div>
|
<div>
|
||||||
<a class="btn btn-outline-primary" role="button" [routerLink]="[itemPageRoute + '/full']">
|
<a class="btn btn-outline-primary" role="button" [routerLink]="[itemPageRoute + '/full']">
|
||||||
<i class="fas fa-info-circle"></i> {{"item.page.link.full" | translate}}
|
<i class="fas fa-info-circle"></i> {{"item.page.link.full" | translate}}
|
||||||
|
@@ -0,0 +1,14 @@
|
|||||||
|
<ng-container *ngIf="(getQualityAssuranceSources$() | async)?.length > 0">
|
||||||
|
<ng-container *ngFor="let source of (getQualityAssuranceSources$() | async)">
|
||||||
|
<div class="alert alert-info d-flex flex-row" *ngIf="source.totalEvents > 0">
|
||||||
|
<img class="source-logo" src="assets/images/qa-{{(source.id | dsSplit: ':')[0]}}-logo.png" alt="{{source.id}} logo">
|
||||||
|
<div class="w-100 d-flex justify-content-between">
|
||||||
|
<div class="pl-4 align-self-center">{{'item.qa-event-notification.check.notification-info' | translate : {num:
|
||||||
|
source.totalEvents } }} </div>
|
||||||
|
<button [routerLink]="['/admin/notifications/quality-assurance', (source.id | dsSplit: ':')[0], 'target', item.id]"
|
||||||
|
class="btn btn-primary align-self-center">{{'item.qa-event-notification-info.check.button' | translate
|
||||||
|
}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
.source-logo {
|
||||||
|
max-height: var(--ds-header-logo-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections-gap {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
@@ -0,0 +1,58 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { QaEventNotificationComponent } from './qa-event-notification.component';
|
||||||
|
import { QualityAssuranceSourceDataService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service';
|
||||||
|
import { createPaginatedList } from '../../../shared/testing/utils.test';
|
||||||
|
import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { SplitPipe } from '../../../shared/utils/split.pipe';
|
||||||
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
|
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||||
|
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { HALEndpointServiceStub } from '../../../shared/testing/hal-endpoint-service.stub';
|
||||||
|
|
||||||
|
describe('QaEventNotificationComponent', () => {
|
||||||
|
let component: QaEventNotificationComponent;
|
||||||
|
let fixture: ComponentFixture<QaEventNotificationComponent>;
|
||||||
|
|
||||||
|
let qualityAssuranceSourceDataServiceStub: any;
|
||||||
|
|
||||||
|
const obj = createSuccessfulRemoteDataObject$(createPaginatedList([new QualityAssuranceSourceObject()]));
|
||||||
|
const item = Object.assign({ uuid: '1234' });
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
qualityAssuranceSourceDataServiceStub = {
|
||||||
|
getSourcesByTarget: () => obj
|
||||||
|
};
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, TranslateModule.forRoot()],
|
||||||
|
declarations: [QaEventNotificationComponent, SplitPipe],
|
||||||
|
providers: [
|
||||||
|
{ provide: QualityAssuranceSourceDataService, useValue: qualityAssuranceSourceDataServiceStub },
|
||||||
|
{ provide: RequestService, useValue: {} },
|
||||||
|
{ provide: NotificationsService, useValue: {} },
|
||||||
|
{ provide: HALEndpointService, useValue: new HALEndpointServiceStub('test')},
|
||||||
|
ObjectCacheService,
|
||||||
|
RemoteDataBuildService,
|
||||||
|
provideMockStore({})
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(QaEventNotificationComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
component.item = item;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,53 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { Item } from '../../../core/shared/item.model';
|
||||||
|
import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { AlertType } from '../../../shared/alert/aletr-type';
|
||||||
|
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||||
|
import { RequestParam } from '../../../core/cache/models/request-param.model';
|
||||||
|
import { QualityAssuranceSourceDataService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service';
|
||||||
|
import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-qa-event-notification',
|
||||||
|
templateUrl: './qa-event-notification.component.html',
|
||||||
|
styleUrls: ['./qa-event-notification.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
providers: [QualityAssuranceSourceDataService]
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Component for displaying quality assurance event notifications for an item.
|
||||||
|
*/
|
||||||
|
export class QaEventNotificationComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item to display quality assurance event notifications for.
|
||||||
|
*/
|
||||||
|
@Input() item: Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of alert to display for the notification.
|
||||||
|
*/
|
||||||
|
AlertTypeInfo = AlertType.Info;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Observable of QualityAssuranceSourceObject[] for the current item.
|
||||||
|
* @returns An Observable of QualityAssuranceSourceObject[] for the current item.
|
||||||
|
* Note: sourceId is composed as: id: "sourceName:<target>"
|
||||||
|
*/
|
||||||
|
getQualityAssuranceSources$(): Observable<QualityAssuranceSourceObject[]> {
|
||||||
|
const findListTopicOptions: FindListOptions = {
|
||||||
|
searchParams: [new RequestParam('target', this.item.uuid)]
|
||||||
|
};
|
||||||
|
return this.qualityAssuranceSourceDataService.getSourcesByTarget(findListTopicOptions)
|
||||||
|
.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
getPaginatedListPayload(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
|
<ds-my-dspace-qa-events-notifications></ds-my-dspace-qa-events-notifications>
|
||||||
<ds-my-dspace-new-submission *dsShowOnlyForRole="[roleTypeEnum.Submitter]"></ds-my-dspace-new-submission>
|
<ds-my-dspace-new-submission *dsShowOnlyForRole="[roleTypeEnum.Submitter]"></ds-my-dspace-new-submission>
|
||||||
<ds-suggestions-notification></ds-suggestions-notification>
|
<ds-suggestions-notification></ds-suggestions-notification>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -16,6 +16,7 @@ import { ThemedMyDSpacePageComponent } from './themed-my-dspace-page.component';
|
|||||||
import { SearchModule } from '../shared/search/search.module';
|
import { SearchModule } from '../shared/search/search.module';
|
||||||
import { UploadModule } from '../shared/upload/upload.module';
|
import { UploadModule } from '../shared/upload/upload.module';
|
||||||
import { SuggestionNotificationsModule } from '../suggestion-notifications/suggestion-notifications.module';
|
import { SuggestionNotificationsModule } from '../suggestion-notifications/suggestion-notifications.module';
|
||||||
|
import { MyDspaceQaEventsNotificationsComponent } from './my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component';
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
MyDSpacePageComponent,
|
MyDSpacePageComponent,
|
||||||
@@ -23,7 +24,8 @@ const DECLARATIONS = [
|
|||||||
MyDSpaceNewSubmissionComponent,
|
MyDSpaceNewSubmissionComponent,
|
||||||
CollectionSelectorComponent,
|
CollectionSelectorComponent,
|
||||||
MyDSpaceNewSubmissionDropdownComponent,
|
MyDSpaceNewSubmissionDropdownComponent,
|
||||||
MyDSpaceNewExternalDropdownComponent
|
MyDSpaceNewExternalDropdownComponent,
|
||||||
|
MyDspaceQaEventsNotificationsComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
<ng-container *ngIf="(sources$ | async)?.length > 0">
|
||||||
|
<ng-container *ngFor="let source of sources$ | async">
|
||||||
|
<div
|
||||||
|
class="alert alert-info d-flex flex-row"
|
||||||
|
*ngIf="source.totalEvents > 0"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="source-logo"
|
||||||
|
src="assets/images/qa-{{ source.id }}-logo.png"
|
||||||
|
alt="{{ source.id }} logo"
|
||||||
|
/>
|
||||||
|
<div class="w-100 d-flex justify-content-between">
|
||||||
|
<div class="pl-4 align-self-center">
|
||||||
|
{{
|
||||||
|
"mydspace.qa-event-notification.check.notification-info"
|
||||||
|
| translate : { num: source.totalEvents }
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
[routerLink]="['/admin/notifications/quality-assurance', source.id]"
|
||||||
|
class="btn btn-primary align-self-center"
|
||||||
|
>
|
||||||
|
{{ "mydspace.qa-event-notification-info.check.button" | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
.source-logo {
|
||||||
|
max-height: var(--ds-header-logo-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sections-gap {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { MyDspaceQaEventsNotificationsComponent } from './my-dspace-qa-events-notifications.component';
|
||||||
|
import { QualityAssuranceSourceDataService } from '../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from 'src/app/shared/remote-data.utils';
|
||||||
|
import { createPaginatedList } from 'src/app/shared/testing/utils.test';
|
||||||
|
import { QualityAssuranceSourceObject } from 'src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model';
|
||||||
|
|
||||||
|
describe('MyDspaceQaEventsNotificationsComponent', () => {
|
||||||
|
let component: MyDspaceQaEventsNotificationsComponent;
|
||||||
|
let fixture: ComponentFixture<MyDspaceQaEventsNotificationsComponent>;
|
||||||
|
|
||||||
|
let qualityAssuranceSourceDataServiceStub: any;
|
||||||
|
const obj = createSuccessfulRemoteDataObject$(createPaginatedList([new QualityAssuranceSourceObject()]));
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
qualityAssuranceSourceDataServiceStub = {
|
||||||
|
getSources: () => obj
|
||||||
|
};
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ MyDspaceQaEventsNotificationsComponent ],
|
||||||
|
providers: [
|
||||||
|
{ provide: QualityAssuranceSourceDataService, useValue: qualityAssuranceSourceDataServiceStub }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(MyDspaceQaEventsNotificationsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,44 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
import { QualityAssuranceSourceDataService } from '../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service';
|
||||||
|
import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../core/shared/operators';
|
||||||
|
import { Observable, of, tap } from 'rxjs';
|
||||||
|
import { QualityAssuranceSourceObject } from 'src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-my-dspace-qa-events-notifications',
|
||||||
|
templateUrl: './my-dspace-qa-events-notifications.component.html',
|
||||||
|
styleUrls: ['./my-dspace-qa-events-notifications.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class MyDspaceQaEventsNotificationsComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Observable that emits an array of QualityAssuranceSourceObject.
|
||||||
|
*/
|
||||||
|
sources$: Observable<QualityAssuranceSourceObject[]> = of([]);
|
||||||
|
|
||||||
|
constructor(private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.getSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the sources for Quality Assurance.
|
||||||
|
* @returns An Observable of the sources for Quality Assurance.
|
||||||
|
* @throws An error if the retrieval of Quality Assurance sources fails.
|
||||||
|
*/
|
||||||
|
getSources() {
|
||||||
|
this.sources$ = this.qualityAssuranceSourceDataService.getSources()
|
||||||
|
.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
tap((rd) => {
|
||||||
|
if (rd.hasFailed) {
|
||||||
|
throw new Error('Can\'t retrieve Quality Assurance sources');
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
getPaginatedListPayload(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -1838,8 +1838,8 @@ export function getMockNotificationsStateService(): any {
|
|||||||
*/
|
*/
|
||||||
export function getMockQualityAssuranceTopicRestService(): QualityAssuranceTopicDataService {
|
export function getMockQualityAssuranceTopicRestService(): QualityAssuranceTopicDataService {
|
||||||
return jasmine.createSpyObj('QualityAssuranceTopicDataService', {
|
return jasmine.createSpyObj('QualityAssuranceTopicDataService', {
|
||||||
getTopics: jasmine.createSpy('getTopics'),
|
searchTopicsBySource: jasmine.createSpy('searchTopicsBySource'),
|
||||||
getTopic: jasmine.createSpy('getTopic'),
|
searchTopicsByTarget: jasmine.createSpy('searchTopicsByTarget'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { Item } from '../../core/shared/item.model';
|
import { Item } from '../../core/shared/item.model';
|
||||||
import { SearchResult } from '../search/models/search-result.model';
|
import { SearchResult } from '../search/models/search-result.model';
|
||||||
import { SuggestionsService } from '../../suggestion-notifications/reciter-suggestions/suggestions.service';
|
|
||||||
|
|
||||||
// REST Mock ---------------------------------------------------------------------
|
// REST Mock ---------------------------------------------------------------------
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
|
@@ -284,6 +284,7 @@ import {
|
|||||||
} from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
|
} from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
|
||||||
import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
||||||
import { NgxPaginationModule } from 'ngx-pagination';
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
import { SplitPipe } from './utils/split.pipe';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -323,7 +324,8 @@ const PIPES = [
|
|||||||
ObjNgFor,
|
ObjNgFor,
|
||||||
BrowserOnlyPipe,
|
BrowserOnlyPipe,
|
||||||
MarkdownPipe,
|
MarkdownPipe,
|
||||||
ShortNumberPipe
|
ShortNumberPipe,
|
||||||
|
SplitPipe,
|
||||||
];
|
];
|
||||||
|
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
|
12
src/app/shared/utils/split.pipe.ts
Normal file
12
src/app/shared/utils/split.pipe.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'dsSplit'
|
||||||
|
})
|
||||||
|
export class SplitPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(value: string, separator: string): string[] {
|
||||||
|
return value.split(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
<div class="submission-form-header-item mb-3 mb-sm-0 flex-sm-grow-1 flex-md-grow-0">
|
<div class="submission-form-header-item mb-3 mb-sm-0 flex-sm-grow-1 flex-md-grow-0">
|
||||||
<ng-container *ngIf="!isSectionHidden">
|
<ng-container *ngIf="!isSectionHidden">
|
||||||
<ds-submission-form-collection [currentCollectionId]="collectionId"
|
<ds-submission-form-collection
|
||||||
|
[currentCollectionId]="collectionId"
|
||||||
[currentDefinition]="definitionId"
|
[currentDefinition]="definitionId"
|
||||||
[submissionId]="submissionId"
|
[submissionId]="submissionId"
|
||||||
[collectionModifiable]="collectionModifiable"
|
[collectionModifiable]="collectionModifiable"
|
||||||
@@ -30,10 +31,12 @@
|
|||||||
<ng-container *ngFor="let object of (submissionSections | async)">
|
<ng-container *ngFor="let object of (submissionSections | async)">
|
||||||
<ds-submission-section-container [collectionId]="collectionId"
|
<ds-submission-section-container [collectionId]="collectionId"
|
||||||
[submissionId]="submissionId"
|
[submissionId]="submissionId"
|
||||||
[sectionData]="object"></ds-submission-section-container>
|
[sectionData]="object">
|
||||||
|
</ds-submission-section-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!(isLoading() | async)" class="submission-form-footer mt-3 mb-3 position-sticky">
|
<div *ngIf="!(isLoading() | async)" class="submission-form-footer mt-3 mb-3 position-sticky">
|
||||||
<ds-submission-form-footer [submissionId]="submissionId"></ds-submission-form-footer>
|
<ds-submission-form-footer [submissionId]="submissionId"></ds-submission-form-footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -48,4 +48,4 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
</ngb-accordion>
|
</ngb-accordion>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -0,0 +1,122 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { dataService } from '../../../core/data/base/data-service.decorator';
|
||||||
|
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
|
||||||
|
import { FindAllData, FindAllDataImpl } from '../../../core/data/base/find-all-data';
|
||||||
|
import { DeleteData, DeleteDataImpl } from '../../../core/data/base/delete-data';
|
||||||
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
|
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
|
||||||
|
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
||||||
|
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||||
|
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||||
|
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||||
|
import { NoContent } from '../../../core/shared/NoContent.model';
|
||||||
|
import { map, take } from 'rxjs/operators';
|
||||||
|
import { URLCombiner } from '../../../core/url-combiner/url-combiner';
|
||||||
|
import { MultipartPostRequest } from '../../../core/data/request.models';
|
||||||
|
import { RestRequest } from '../../../core/data/rest-request.model';
|
||||||
|
import { SUBMISSION_COAR_NOTIFY_CONFIG } from './section-coar-notify-service.resource-type';
|
||||||
|
import { SubmissionCoarNotifyConfig } from './submission-coar-notify.config';
|
||||||
|
import { CreateData, CreateDataImpl } from '../../../core/data/base/create-data';
|
||||||
|
import { PatchData, PatchDataImpl } from '../../../core/data/base/patch-data';
|
||||||
|
import { ChangeAnalyzer } from '../../../core/data/change-analyzer';
|
||||||
|
import { Operation } from 'fast-json-patch';
|
||||||
|
import { RestRequestMethod } from '../../../core/data/rest-request-method';
|
||||||
|
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||||
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service responsible for fetching/sending data from/to the REST API on the CoarNotifyConfig endpoint
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
@dataService(SUBMISSION_COAR_NOTIFY_CONFIG)
|
||||||
|
export class CoarNotifyConfigDataService extends IdentifiableDataService<SubmissionCoarNotifyConfig> implements FindAllData<SubmissionCoarNotifyConfig>, DeleteData<SubmissionCoarNotifyConfig>, PatchData<SubmissionCoarNotifyConfig>, CreateData<SubmissionCoarNotifyConfig> {
|
||||||
|
createData: CreateDataImpl<SubmissionCoarNotifyConfig>;
|
||||||
|
private findAllData: FindAllDataImpl<SubmissionCoarNotifyConfig>;
|
||||||
|
private deleteData: DeleteDataImpl<SubmissionCoarNotifyConfig>;
|
||||||
|
private patchData: PatchDataImpl<SubmissionCoarNotifyConfig>;
|
||||||
|
private comparator: ChangeAnalyzer<SubmissionCoarNotifyConfig>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
) {
|
||||||
|
super('submissioncoarnotifyconfigs', requestService, rdbService, objectCache, halService);
|
||||||
|
|
||||||
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||||
|
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||||
|
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
create(object: SubmissionCoarNotifyConfig): Observable<RemoteData<SubmissionCoarNotifyConfig>> {
|
||||||
|
return this.createData.create(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
patch(object: SubmissionCoarNotifyConfig, operations: Operation[]): Observable<RemoteData<SubmissionCoarNotifyConfig>> {
|
||||||
|
return this.patchData.patch(object, operations);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(object: SubmissionCoarNotifyConfig): Observable<RemoteData<SubmissionCoarNotifyConfig>> {
|
||||||
|
return this.patchData.update(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
commitUpdates(method?: RestRequestMethod): void {
|
||||||
|
return this.patchData.commitUpdates(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
createPatchFromCache(object: SubmissionCoarNotifyConfig): Observable<Operation[]> {
|
||||||
|
return this.patchData.createPatchFromCache(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<SubmissionCoarNotifyConfig>[]): Observable<RemoteData<PaginatedList<SubmissionCoarNotifyConfig>>> {
|
||||||
|
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
|
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||||
|
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public invoke(serviceName: string, serviceId: string, files: File[]): Observable<RemoteData<SubmissionCoarNotifyConfig>> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
this.getBrowseEndpoint().pipe(
|
||||||
|
take(1),
|
||||||
|
map((endpoint: string) => new URLCombiner(endpoint, serviceName, 'submissioncoarnotifyconfigmodel', serviceId).toString()),
|
||||||
|
map((endpoint: string) => {
|
||||||
|
const body = this.getInvocationFormData(files);
|
||||||
|
return new MultipartPostRequest(requestId, endpoint, body);
|
||||||
|
})
|
||||||
|
).subscribe((request: RestRequest) => this.requestService.send(request));
|
||||||
|
|
||||||
|
return this.rdbService.buildFromRequestUUID<SubmissionCoarNotifyConfig>(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubmissionCoarNotifyConfigModelWithNameExistsAndCanExecute(scriptName: string): Observable<boolean> {
|
||||||
|
return this.findById(scriptName).pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
map((rd: RemoteData<SubmissionCoarNotifyConfig>) => {
|
||||||
|
return hasValue(rd.payload);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getInvocationFormData(files: File[]): FormData {
|
||||||
|
const form: FormData = new FormData();
|
||||||
|
files.forEach((file: File) => {
|
||||||
|
form.append('file', file);
|
||||||
|
});
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* The resource type for Ldn-Services
|
||||||
|
*
|
||||||
|
* Needs to be in a separate file to prevent circular
|
||||||
|
* dependencies in webpack.
|
||||||
|
*/
|
||||||
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
|
||||||
|
|
||||||
|
export const SUBMISSION_COAR_NOTIFY_CONFIG = new ResourceType('submissioncoarnotifyconfig');
|
||||||
|
|
||||||
|
export const COAR_NOTIFY_WORKSPACEITEM = new ResourceType('workspaceitem');
|
||||||
|
|
@@ -0,0 +1,124 @@
|
|||||||
|
<div class="container-fluid">
|
||||||
|
<ng-container *ngIf="patterns?.length > 0">
|
||||||
|
<div *ngFor="let pattern of patterns; let i = index" class="col">
|
||||||
|
<label class="row col-form-label"
|
||||||
|
>
|
||||||
|
{{'submission.section.section-coar-notify.control.' + pattern + '.label' | translate }}
|
||||||
|
</label
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
*ngFor="
|
||||||
|
let service of ldnServiceByPattern[pattern];
|
||||||
|
let serviceIndex = index
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div class="row">
|
||||||
|
<div ngbDropdown #myDropdown="ngbDropdown" class="w-100">
|
||||||
|
<div class="position-relative right-addon" role="combobox">
|
||||||
|
<i ngbDropdownToggle class="position-absolute scrollable-dropdown-toggle"
|
||||||
|
aria-hidden="true"></i>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
[readonly]="true"
|
||||||
|
ngbDropdownAnchor
|
||||||
|
[ngClass]="{'border-danger': (getShownSectionErrors$(pattern, serviceIndex) | async)?.length > 0}"
|
||||||
|
class="form-control w-100 scrollable-dropdown-input"
|
||||||
|
[value]="ldnServiceByPattern[pattern][serviceIndex]?.name"
|
||||||
|
(click)="myDropdown.open()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ngbDropdownMenu
|
||||||
|
class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="scrollable-menu"
|
||||||
|
role="listbox"
|
||||||
|
infiniteScroll
|
||||||
|
[infiniteScrollDistance]="2"
|
||||||
|
[infiniteScrollThrottle]="50"
|
||||||
|
[scrollWindow]="false"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
*ngIf="(filterServices(pattern) | async)?.length == 0"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
>
|
||||||
|
{{'submission.section.section-coar-notify.dropdown.no-data' | translate}}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngIf="(filterServices(pattern) | async)?.length > 0"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
(click)="onChange(pattern, serviceIndex, null)"
|
||||||
|
>
|
||||||
|
{{'submission.section.section-coar-notify.dropdown.select-none' | translate}}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
*ngFor="let serviceOption of filterServices(pattern) | async"
|
||||||
|
[ngClass]="{'bg-light': ldnServiceByPattern[pattern][serviceIndex]?.id == serviceOption.id}"
|
||||||
|
class="dropdown-item collection-item text-truncate w-100"
|
||||||
|
(click)="onChange(pattern, serviceIndex, serviceOption)"
|
||||||
|
>
|
||||||
|
<b>
|
||||||
|
{{ serviceOption.name }}
|
||||||
|
</b>
|
||||||
|
<br />
|
||||||
|
{{ serviceOption.description }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small
|
||||||
|
class="row text-muted"
|
||||||
|
*ngIf="!ldnServiceByPattern[pattern][serviceIndex]"
|
||||||
|
>
|
||||||
|
{{'submission.section.section-coar-notify.small.notification' | translate : {pattern : pattern} }}
|
||||||
|
</small>
|
||||||
|
<ng-container *ngIf="(getShownSectionErrors$(pattern, serviceIndex) | async)?.length > 0">
|
||||||
|
<small class="row text-danger" *ngFor="let error of (getShownSectionErrors$(pattern, serviceIndex) | async)">
|
||||||
|
{{ error.message | translate}}
|
||||||
|
</small>
|
||||||
|
</ng-container>
|
||||||
|
<div
|
||||||
|
class="row mt-1"
|
||||||
|
*ngIf="ldnServiceByPattern[pattern][serviceIndex]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="alert alert-info w-100 d-flex align-items-center flex-row"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-circle-info fa-xl ml-2"></i>
|
||||||
|
<div class="ml-4">
|
||||||
|
<div>{{ 'submission.section.section-coar-notify.selection.description' | translate }}</div>
|
||||||
|
<div *ngIf="ldnServiceByPattern[pattern][serviceIndex]?.description; else noDesc">
|
||||||
|
{{ ldnServiceByPattern[pattern][serviceIndex].description }}
|
||||||
|
</div>
|
||||||
|
<ng-template #noDesc>
|
||||||
|
<span class="text-muted">
|
||||||
|
{{ 'submission.section.section-coar-notify.selection.no-description' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" *ngIf="(getShownSectionErrors$(pattern, serviceIndex) | async)?.length > 0">
|
||||||
|
<div
|
||||||
|
class="alert alert-danger w-100 d-flex align-items-center flex-row"
|
||||||
|
>
|
||||||
|
<div class="ml-4">
|
||||||
|
<span>
|
||||||
|
{{ 'submission.section.section-coar-notify.notification.error' | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="patterns?.length === 0">
|
||||||
|
<p>
|
||||||
|
{{'submission.section.section-coar-notify.info.no-pattern' | translate }}
|
||||||
|
</p>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
@@ -0,0 +1,4 @@
|
|||||||
|
// Getting styles for NgbDropdown
|
||||||
|
@import '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.scss';
|
||||||
|
@import '../../../shared/form/form.component.scss';
|
||||||
|
|
@@ -0,0 +1,406 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SubmissionSectionCoarNotifyComponent } from './section-coar-notify.component';
|
||||||
|
import { LdnServicesService } from '../../../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||||
|
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { SectionsService } from '../sections.service';
|
||||||
|
import { CoarNotifyConfigDataService } from './coar-notify-config-data.service';
|
||||||
|
import { ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { SubmissionCoarNotifyConfig } from './submission-coar-notify.config';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||||
|
import { createPaginatedList } from '../../../shared/testing/utils.test';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { LdnService } from '../../../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
||||||
|
import { NotifyServicePattern } from '../../../admin/admin-ldn-services/ldn-services-model/ldn-service-patterns.model';
|
||||||
|
|
||||||
|
describe('SubmissionSectionCoarNotifyComponent', () => {
|
||||||
|
let component: SubmissionSectionCoarNotifyComponent;
|
||||||
|
let componentAsAny: any;
|
||||||
|
let fixture: ComponentFixture<SubmissionSectionCoarNotifyComponent>;
|
||||||
|
|
||||||
|
let ldnServicesService: jasmine.SpyObj<LdnServicesService>;
|
||||||
|
let coarNotifyConfigDataService: jasmine.SpyObj<CoarNotifyConfigDataService>;
|
||||||
|
let operationsBuilder: jasmine.SpyObj<JsonPatchOperationsBuilder>;
|
||||||
|
let sectionService: jasmine.SpyObj<SectionsService>;
|
||||||
|
let cdRefStub: any;
|
||||||
|
|
||||||
|
const patterns: SubmissionCoarNotifyConfig[] = Object.assign(
|
||||||
|
[new SubmissionCoarNotifyConfig()],
|
||||||
|
{
|
||||||
|
patterns: ['review', 'endorsment'],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const patternsPL = createPaginatedList(patterns);
|
||||||
|
const coarNotifyConfig = createSuccessfulRemoteDataObject$(patternsPL);
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
ldnServicesService = jasmine.createSpyObj('LdnServicesService', [
|
||||||
|
'findByInboundPattern',
|
||||||
|
]);
|
||||||
|
coarNotifyConfigDataService = jasmine.createSpyObj(
|
||||||
|
'CoarNotifyConfigDataService',
|
||||||
|
['findAll']
|
||||||
|
);
|
||||||
|
operationsBuilder = jasmine.createSpyObj('JsonPatchOperationsBuilder', [
|
||||||
|
'remove',
|
||||||
|
'replace',
|
||||||
|
'add',
|
||||||
|
]);
|
||||||
|
sectionService = jasmine.createSpyObj('SectionsService', [
|
||||||
|
'dispatchRemoveSectionErrors',
|
||||||
|
'getSectionServerErrors',
|
||||||
|
'setSectionError',
|
||||||
|
]);
|
||||||
|
cdRefStub = Object.assign({
|
||||||
|
detectChanges: () => fixture.detectChanges(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [SubmissionSectionCoarNotifyComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: LdnServicesService, useValue: ldnServicesService },
|
||||||
|
{ provide: CoarNotifyConfigDataService, useValue: coarNotifyConfigDataService},
|
||||||
|
{ provide: JsonPatchOperationsBuilder, useValue: operationsBuilder },
|
||||||
|
{ provide: SectionsService, useValue: sectionService },
|
||||||
|
{ provide: ChangeDetectorRef, useValue: cdRefStub },
|
||||||
|
{ provide: 'collectionIdProvider', useValue: 'collectionId' },
|
||||||
|
{ provide: 'sectionDataProvider', useValue: { id: 'sectionId', data: {} }},
|
||||||
|
{ provide: 'submissionIdProvider', useValue: 'submissionId' },
|
||||||
|
NgbDropdown,
|
||||||
|
],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SubmissionSectionCoarNotifyComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
componentAsAny = component;
|
||||||
|
|
||||||
|
component.patterns = patterns[0].patterns;
|
||||||
|
coarNotifyConfigDataService.findAll.and.returnValue(coarNotifyConfig);
|
||||||
|
sectionService.getSectionServerErrors.and.returnValue(
|
||||||
|
of(
|
||||||
|
Object.assign([], {
|
||||||
|
path: 'sections/sectionId/data/notifyCoar',
|
||||||
|
message: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSectionInit', () => {
|
||||||
|
it('should call setCoarNotifyConfig and getSectionServerErrorsAndSetErrorsToDisplay', () => {
|
||||||
|
spyOn(component, 'setCoarNotifyConfig');
|
||||||
|
spyOn(componentAsAny, 'getSectionServerErrorsAndSetErrorsToDisplay');
|
||||||
|
|
||||||
|
component.onSectionInit();
|
||||||
|
|
||||||
|
expect(component.setCoarNotifyConfig).toHaveBeenCalled();
|
||||||
|
expect(componentAsAny.getSectionServerErrorsAndSetErrorsToDisplay).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onChange', () => {
|
||||||
|
const pattern = 'review';
|
||||||
|
const index = 0;
|
||||||
|
const selectedService: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'review',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.ldnServiceByPattern[pattern] = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing if the selected value is the same as the previous one', () => {
|
||||||
|
component.ldnServiceByPattern[pattern][index] = selectedService;
|
||||||
|
component.onChange(pattern, index, selectedService);
|
||||||
|
|
||||||
|
expect(componentAsAny.operationsBuilder.remove).not.toHaveBeenCalled();
|
||||||
|
expect(componentAsAny.operationsBuilder.replace).not.toHaveBeenCalled();
|
||||||
|
expect(componentAsAny.operationsBuilder.add).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the path when the selected value is null', () => {
|
||||||
|
component.ldnServiceByPattern[pattern][index] = selectedService;
|
||||||
|
component.onChange(pattern, index, null);
|
||||||
|
|
||||||
|
expect(componentAsAny.operationsBuilder.remove).toHaveBeenCalledWith(
|
||||||
|
componentAsAny.pathCombiner.getPath([pattern, index.toString()])
|
||||||
|
);
|
||||||
|
expect(component.ldnServiceByPattern[pattern][index]).toBeNull();
|
||||||
|
expect(component.previousServices[pattern][index]).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace the path when there is a previous value stored and it is different from the new one', () => {
|
||||||
|
const previousService: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 2,
|
||||||
|
name: 'service2',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
{
|
||||||
|
pattern: 'endorsement',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: 'test',
|
||||||
|
});
|
||||||
|
component.ldnServiceByPattern[pattern][index] = previousService;
|
||||||
|
component.previousServices[pattern] = [];
|
||||||
|
component.previousServices[pattern][index] = previousService.id;
|
||||||
|
component.onChange(pattern, index, selectedService);
|
||||||
|
|
||||||
|
expect(componentAsAny.operationsBuilder.replace).toHaveBeenCalledWith(
|
||||||
|
componentAsAny.pathCombiner.getPath([pattern, index.toString()]),
|
||||||
|
selectedService.id,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(component.ldnServiceByPattern[pattern][index]).toEqual(
|
||||||
|
selectedService
|
||||||
|
);
|
||||||
|
expect(component.previousServices[pattern][index]).toEqual(
|
||||||
|
selectedService.id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the path when there is no previous value stored', () => {
|
||||||
|
component.onChange(pattern, index, selectedService);
|
||||||
|
|
||||||
|
expect(componentAsAny.operationsBuilder.add).toHaveBeenCalledWith(
|
||||||
|
componentAsAny.pathCombiner.getPath([pattern, '-']),
|
||||||
|
[selectedService.id],
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(component.ldnServiceByPattern[pattern][index]).toEqual(
|
||||||
|
selectedService
|
||||||
|
);
|
||||||
|
expect(component.previousServices[pattern][index]).toEqual(
|
||||||
|
selectedService.id
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initSelectedServicesByPattern', () => {
|
||||||
|
const pattern1 = 'review';
|
||||||
|
const pattern2 = 'endorsement';
|
||||||
|
const service1: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern1,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const service2: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 2,
|
||||||
|
name: 'service2',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const service3: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 3,
|
||||||
|
name: 'service3',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern1,
|
||||||
|
}),
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const services = [service1, service2, service3];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(component, 'filterServices').and.callFake((pattern) => {
|
||||||
|
return of(
|
||||||
|
services.filter((service) =>
|
||||||
|
component.hasInboundPattern(service, pattern)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize the selected services by pattern', () => {
|
||||||
|
component.patterns = [pattern1, pattern2];
|
||||||
|
component.initSelectedServicesByPattern();
|
||||||
|
|
||||||
|
expect(component.ldnServiceByPattern[pattern1]).toEqual([null]);
|
||||||
|
expect(component.ldnServiceByPattern[pattern2]).toEqual([null]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the service to the selected services by pattern if the section data has a value for the pattern', () => {
|
||||||
|
component.patterns = [pattern1, pattern2];
|
||||||
|
component.sectionData.data[pattern1] = [service1.id, service3.id];
|
||||||
|
component.sectionData.data[pattern2] = [service2.id, service3.id];
|
||||||
|
component.initSelectedServicesByPattern();
|
||||||
|
|
||||||
|
expect(component.ldnServiceByPattern[pattern1]).toEqual([
|
||||||
|
service1,
|
||||||
|
service3,
|
||||||
|
]);
|
||||||
|
expect(component.ldnServiceByPattern[pattern2]).toEqual([
|
||||||
|
service2,
|
||||||
|
service3,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('addService', () => {
|
||||||
|
const pattern = 'review';
|
||||||
|
const service: any = {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [{ pattern: pattern }],
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.ldnServiceByPattern[pattern] = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should push the new service to the array corresponding to the pattern', () => {
|
||||||
|
component.addService(pattern, service);
|
||||||
|
|
||||||
|
expect(component.ldnServiceByPattern[pattern]).toEqual([service]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeService', () => {
|
||||||
|
const pattern = 'review';
|
||||||
|
const service1: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const service2: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const service3: LdnService = Object.assign(new LdnService(), {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [
|
||||||
|
Object.assign(new NotifyServicePattern(), {
|
||||||
|
pattern: pattern,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.ldnServiceByPattern[pattern] = [service1, service2, service3];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the service at the specified index from the array corresponding to the pattern', () => {
|
||||||
|
component.removeService(pattern, 1);
|
||||||
|
|
||||||
|
expect(component.ldnServiceByPattern[pattern]).toEqual([
|
||||||
|
service1,
|
||||||
|
service3,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('filterServices', () => {
|
||||||
|
const pattern = 'review';
|
||||||
|
const service1: any = {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [{ pattern: pattern }],
|
||||||
|
};
|
||||||
|
const service2: any = {
|
||||||
|
id: 2,
|
||||||
|
name: 'service2',
|
||||||
|
notifyServiceInboundPatterns: [{ pattern: pattern }],
|
||||||
|
};
|
||||||
|
const service3: any = {
|
||||||
|
id: 3,
|
||||||
|
name: 'service3',
|
||||||
|
notifyServiceInboundPatterns: [{ pattern: pattern }],
|
||||||
|
};
|
||||||
|
const services = [service1, service2, service3];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
ldnServicesService.findByInboundPattern.and.returnValue(
|
||||||
|
createSuccessfulRemoteDataObject$(createPaginatedList(services))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an observable of the services that match the given pattern', () => {
|
||||||
|
component.filterServices(pattern).subscribe((result) => {
|
||||||
|
expect(result).toEqual(services);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasInboundPattern', () => {
|
||||||
|
const pattern = 'review';
|
||||||
|
const service: any = {
|
||||||
|
id: 1,
|
||||||
|
name: 'service1',
|
||||||
|
notifyServiceInboundPatterns: [{ pattern: pattern }],
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should return true if the service has the specified inbound pattern type', () => {
|
||||||
|
expect(component.hasInboundPattern(service, pattern)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the service does not have the specified inbound pattern type', () => {
|
||||||
|
expect(component.hasInboundPattern(service, 'endorsement')).toBeFalse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSectionServerErrorsAndSetErrorsToDisplay', () => {
|
||||||
|
it('should set the validation errors for the current section to display', () => {
|
||||||
|
const validationErrors = [
|
||||||
|
{ path: 'sections/sectionId/data/notifyCoar', message: 'error' },
|
||||||
|
];
|
||||||
|
sectionService.getSectionServerErrors.and.returnValue(
|
||||||
|
of(validationErrors)
|
||||||
|
);
|
||||||
|
|
||||||
|
componentAsAny.getSectionServerErrorsAndSetErrorsToDisplay();
|
||||||
|
|
||||||
|
expect(sectionService.setSectionError).toHaveBeenCalledWith(
|
||||||
|
component.submissionId,
|
||||||
|
component.sectionData.id,
|
||||||
|
validationErrors[0]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSectionDestroy', () => {
|
||||||
|
it('should unsubscribe from all subscriptions', () => {
|
||||||
|
const sub1 = of(null).subscribe();
|
||||||
|
const sub2 = of(null).subscribe();
|
||||||
|
componentAsAny.subs = [sub1, sub2];
|
||||||
|
spyOn(sub1, 'unsubscribe');
|
||||||
|
spyOn(sub2, 'unsubscribe');
|
||||||
|
component.onSectionDestroy();
|
||||||
|
expect(sub1.unsubscribe).toHaveBeenCalled();
|
||||||
|
expect(sub2.unsubscribe).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,293 @@
|
|||||||
|
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
||||||
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
import { SectionModelComponent } from '../models/section.model';
|
||||||
|
import { renderSectionFor } from '../sections-decorator';
|
||||||
|
import { SectionsType } from '../sections-type';
|
||||||
|
import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
|
||||||
|
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { SectionsService } from '../sections.service';
|
||||||
|
import { SectionDataObject } from '../models/section-data.model';
|
||||||
|
|
||||||
|
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../../shared/empty.util';
|
||||||
|
|
||||||
|
import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||||
|
import { LdnServicesService } from '../../../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||||
|
import { LdnService } from '../../../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
||||||
|
import { CoarNotifyConfigDataService } from './coar-notify-config-data.service';
|
||||||
|
import { filter, map, take, tap } from 'rxjs/operators';
|
||||||
|
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { SubmissionSectionError } from '../../objects/submission-section-error.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents a section that contains the submission section-coar-notify form.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-submission-section-coar-notify',
|
||||||
|
templateUrl: './section-coar-notify.component.html',
|
||||||
|
styleUrls: ['./section-coar-notify.component.scss'],
|
||||||
|
providers: [NgbDropdown]
|
||||||
|
})
|
||||||
|
@renderSectionFor(SectionsType.CoarNotify)
|
||||||
|
export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains an array of string patterns.
|
||||||
|
*/
|
||||||
|
patterns: string[] = [];
|
||||||
|
/**
|
||||||
|
* An object that maps string keys to arrays of LdnService objects.
|
||||||
|
* Used to store LdnService objects by pattern.
|
||||||
|
*/
|
||||||
|
ldnServiceByPattern: { [key: string]: LdnService[] } = {};
|
||||||
|
/**
|
||||||
|
* A map representing all services for each pattern
|
||||||
|
* {
|
||||||
|
* 'pattern': {
|
||||||
|
* 'index': 'service.id'
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @type {{ [key: string]: {[key: number]: number} }}
|
||||||
|
* @memberof SubmissionSectionCoarNotifyComponent
|
||||||
|
*/
|
||||||
|
previousServices: { [key: string]: {[key: number]: number} } = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [[JsonPatchOperationPathCombiner]] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
/**
|
||||||
|
* A map representing all field on their way to be removed
|
||||||
|
* @type {Map}
|
||||||
|
*/
|
||||||
|
protected fieldsOnTheirWayToBeRemoved: Map<string, number[]> = new Map();
|
||||||
|
/**
|
||||||
|
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(protected ldnServicesService: LdnServicesService,
|
||||||
|
// protected formOperationsService: SectionFormOperationsService,
|
||||||
|
protected operationsBuilder: JsonPatchOperationsBuilder,
|
||||||
|
protected sectionService: SectionsService,
|
||||||
|
protected coarNotifyConfigDataService: CoarNotifyConfigDataService,
|
||||||
|
protected chd: ChangeDetectorRef,
|
||||||
|
@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||||
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
|
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||||
|
super(injectedCollectionId, injectedSectionData, injectedSubmissionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all instance variables
|
||||||
|
*/
|
||||||
|
onSectionInit() {
|
||||||
|
this.setCoarNotifyConfig();
|
||||||
|
this.getSectionServerErrorsAndSetErrorsToDisplay();
|
||||||
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when section is initialized
|
||||||
|
* Retriev available NotifyConfigs
|
||||||
|
*/
|
||||||
|
setCoarNotifyConfig() {
|
||||||
|
this.subs.push(
|
||||||
|
this.coarNotifyConfigDataService.findAll().pipe(
|
||||||
|
getFirstCompletedRemoteData()
|
||||||
|
).subscribe((data) => {
|
||||||
|
if (data.hasSucceeded) {
|
||||||
|
this.patterns = data.payload.page[0].patterns;
|
||||||
|
this.initSelectedServicesByPattern();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the change event of a select element.
|
||||||
|
* @param pattern - The pattern of the select element.
|
||||||
|
* @param index - The index of the select element.
|
||||||
|
*/
|
||||||
|
onChange(pattern: string, index: number, selectedService: LdnService | null) {
|
||||||
|
// do nothing if the selected value is the same as the previous one
|
||||||
|
if (this.ldnServiceByPattern[pattern][index]?.id === selectedService?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the previousServices object for the pattern if it does not exist
|
||||||
|
if (!this.previousServices[pattern]) {
|
||||||
|
this.previousServices[pattern] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasNoValue(selectedService)) {
|
||||||
|
// on value change, remove the path when the selected value is null
|
||||||
|
// and remove the previous value stored for the same index and pattern
|
||||||
|
this.operationsBuilder.remove(this.pathCombiner.getPath([pattern, index.toString()]));
|
||||||
|
this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionData.id);
|
||||||
|
this.ldnServiceByPattern[pattern][index] = null;
|
||||||
|
this.previousServices[pattern][index] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// store the previous value
|
||||||
|
this.previousServices[pattern][index] = this.ldnServiceByPattern[pattern][index]?.id;
|
||||||
|
// set the new value
|
||||||
|
this.ldnServiceByPattern[pattern][index] = selectedService;
|
||||||
|
|
||||||
|
const hasPrevValueStored = hasValue(this.previousServices[pattern][index]) && this.previousServices[pattern][index] !== selectedService.id;
|
||||||
|
if (hasPrevValueStored) {
|
||||||
|
// replace the path
|
||||||
|
// when there is a previous value stored and it is different from the new one
|
||||||
|
this.operationsBuilder.replace(this.pathCombiner.getPath([pattern, index.toString()]), selectedService.id, true);
|
||||||
|
} else {
|
||||||
|
// add the path when there is no previous value stored
|
||||||
|
this.operationsBuilder.add(this.pathCombiner.getPath([pattern, '-']), [selectedService.id], false, true);
|
||||||
|
}
|
||||||
|
// set the previous value to the new value
|
||||||
|
this.previousServices[pattern][index] = this.ldnServiceByPattern[pattern][index].id;
|
||||||
|
this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionData.id);
|
||||||
|
this.chd.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the selected services by pattern.
|
||||||
|
* Loops through each pattern and filters the services based on the pattern.
|
||||||
|
* If the section data has a value for the pattern, it adds the service to the selected services by pattern.
|
||||||
|
* If the section data does not have a value for the pattern, it adds a null service to the selected services by pattern,
|
||||||
|
* so that the select element is initialized with a null value and to display the default select input.
|
||||||
|
*/
|
||||||
|
initSelectedServicesByPattern(): void {
|
||||||
|
this.patterns.forEach((pattern) => {
|
||||||
|
if (hasValue(this.sectionData.data[pattern])) {
|
||||||
|
this.subs.push(
|
||||||
|
this.filterServices(pattern)
|
||||||
|
.subscribe((services: LdnService[]) => {
|
||||||
|
const selectedServices = services.filter((service) => {
|
||||||
|
const selection = (this.sectionData.data[pattern] as LdnService[]).find((s: LdnService) => s.id === service.id);
|
||||||
|
this.addService(pattern, selection);
|
||||||
|
return this.sectionData.data[pattern].includes(service.id);
|
||||||
|
});
|
||||||
|
this.ldnServiceByPattern[pattern] = selectedServices;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.ldnServiceByPattern[pattern] = [];
|
||||||
|
this.addService(pattern, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new service to the selected services for the given pattern.
|
||||||
|
* @param pattern - The pattern to add the new service to.
|
||||||
|
* @param newService - The new service to add.
|
||||||
|
*/
|
||||||
|
addService(pattern: string, newService: LdnService) {
|
||||||
|
// Your logic to add a new service to the selected services for the pattern
|
||||||
|
// Example: Push the newService to the array corresponding to the pattern
|
||||||
|
if (!this.ldnServiceByPattern[pattern]) {
|
||||||
|
this.ldnServiceByPattern[pattern] = [];
|
||||||
|
}
|
||||||
|
this.ldnServiceByPattern[pattern].push(newService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the service at the specified index from the array corresponding to the pattern.
|
||||||
|
* (part of next phase of implementation)
|
||||||
|
*/
|
||||||
|
removeService(pattern: string, serviceIndex: number) {
|
||||||
|
if (this.ldnServiceByPattern[pattern]) {
|
||||||
|
// Remove the service at the specified index from the array
|
||||||
|
this.ldnServiceByPattern[pattern].splice(serviceIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when dropdowns for the section are initialized
|
||||||
|
* Retrieve services with corresponding patterns to the dropdowns.
|
||||||
|
*/
|
||||||
|
filterServices(pattern: string): Observable<LdnService[]> {
|
||||||
|
return this.ldnServicesService.findByInboundPattern(pattern).pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
tap((rd) => {
|
||||||
|
if (rd.hasFailed) {
|
||||||
|
throw new Error(`Failed to retrieve services for pattern ${pattern}`);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter((rd) => rd.hasSucceeded),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
getPaginatedListPayload(),
|
||||||
|
map((res: LdnService[]) => res.filter((service) =>
|
||||||
|
this.hasInboundPattern(service, pattern)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given service has the specified inbound pattern type.
|
||||||
|
* @param service - The service to check.
|
||||||
|
* @param patternType - The inbound pattern type to look for.
|
||||||
|
* @returns True if the service has the specified inbound pattern type, false otherwise.
|
||||||
|
*/
|
||||||
|
hasInboundPattern(service: any, patternType: string): boolean {
|
||||||
|
return service.notifyServiceInboundPatterns.some((pattern: { pattern: string }) => {
|
||||||
|
return pattern.pattern === patternType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves server errors for the current section and sets them to display.
|
||||||
|
* @returns An Observable that emits the validation errors for the current section.
|
||||||
|
*/
|
||||||
|
private getSectionServerErrorsAndSetErrorsToDisplay() {
|
||||||
|
this.subs.push(
|
||||||
|
this.sectionService.getSectionServerErrors(this.submissionId, this.sectionData.id).pipe(
|
||||||
|
take(1),
|
||||||
|
filter((validationErrors) => isNotEmpty(validationErrors)),
|
||||||
|
).subscribe((validationErrors: SubmissionSectionError[]) => {
|
||||||
|
if (isNotEmpty(validationErrors)) {
|
||||||
|
validationErrors.forEach((error) => {
|
||||||
|
this.sectionService.setSectionError(this.submissionId, this.sectionData.id, error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an observable of the errors for the current section that match the given pattern and index.
|
||||||
|
* @param pattern - The pattern to match against the error paths.
|
||||||
|
* @param index - The index to match against the error paths.
|
||||||
|
* @returns An observable of the errors for the current section that match the given pattern and index.
|
||||||
|
*/
|
||||||
|
public getShownSectionErrors$(pattern: string, index: number): Observable<SubmissionSectionError[]> {
|
||||||
|
return this.sectionService.getShownSectionErrors(this.submissionId, this.sectionData.id, this.sectionData.sectionType)
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
filter((validationErrors) => isNotEmpty(validationErrors)),
|
||||||
|
map((validationErrors: SubmissionSectionError[]) => {
|
||||||
|
return validationErrors.filter((error) => {
|
||||||
|
const path = `${pattern}/${index}`;
|
||||||
|
return error.path.includes(path);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns An observable that emits a boolean indicating whether the section has any server errors or not.
|
||||||
|
*/
|
||||||
|
protected getSectionStatus(): Observable<boolean> {
|
||||||
|
return this.sectionService.getSectionServerErrors(this.submissionId, this.sectionData.id).pipe(
|
||||||
|
map((validationErrors) => isEmpty(validationErrors)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
|
onSectionDestroy() {
|
||||||
|
this.subs
|
||||||
|
.filter((subscription) => hasValue(subscription))
|
||||||
|
.forEach((subscription) => subscription.unsubscribe());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,35 @@
|
|||||||
|
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
|
||||||
|
import { autoserialize, deserialize, deserializeAs, inheritSerialization } from 'cerialize';
|
||||||
|
|
||||||
|
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
|
||||||
|
import { typedObject } from '../../../core/cache/builders/build-decorators';
|
||||||
|
import { COAR_NOTIFY_WORKSPACEITEM } from './section-coar-notify-service.resource-type';
|
||||||
|
|
||||||
|
|
||||||
|
/** An CoarNotify and its properties. */
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(CacheableObject)
|
||||||
|
export class SubmissionCoarNotifyWorkspaceitemModel extends CacheableObject {
|
||||||
|
static type = COAR_NOTIFY_WORKSPACEITEM;
|
||||||
|
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
endorsement?: number[];
|
||||||
|
|
||||||
|
@deserializeAs('id')
|
||||||
|
review?: number[];
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
ingest?: number[];
|
||||||
|
|
||||||
|
@deserialize
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
get self(): string {
|
||||||
|
return this._links.self.href;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
import { ResourceType } from '../../../core/shared/resource-type';
|
||||||
|
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
|
||||||
|
import { autoserialize, deserialize, deserializeAs, inheritSerialization } from 'cerialize';
|
||||||
|
|
||||||
|
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
|
||||||
|
import { typedObject } from '../../../core/cache/builders/build-decorators';
|
||||||
|
import { SUBMISSION_COAR_NOTIFY_CONFIG } from './section-coar-notify-service.resource-type';
|
||||||
|
|
||||||
|
|
||||||
|
/** A SubmissionCoarNotifyConfig and its properties. */
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(CacheableObject)
|
||||||
|
export class SubmissionCoarNotifyConfig extends CacheableObject {
|
||||||
|
static type = SUBMISSION_COAR_NOTIFY_CONFIG;
|
||||||
|
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@deserializeAs('id')
|
||||||
|
uuid: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
patterns: string[];
|
||||||
|
|
||||||
|
@deserialize
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
get self(): string {
|
||||||
|
return this._links.self.href;
|
||||||
|
}
|
||||||
|
}
|
@@ -9,4 +9,5 @@ export enum SectionsType {
|
|||||||
SherpaPolicies = 'sherpaPolicy',
|
SherpaPolicies = 'sherpaPolicy',
|
||||||
Identifiers = 'identifiers',
|
Identifiers = 'identifiers',
|
||||||
Collection = 'collection',
|
Collection = 'collection',
|
||||||
|
CoarNotify = 'coarnotify'
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import { SubmissionFormFooterComponent } from './form/footer/submission-form-foo
|
|||||||
import { SubmissionFormComponent } from './form/submission-form.component';
|
import { SubmissionFormComponent } from './form/submission-form.component';
|
||||||
import { SubmissionFormSectionAddComponent } from './form/section-add/submission-form-section-add.component';
|
import { SubmissionFormSectionAddComponent } from './form/section-add/submission-form-section-add.component';
|
||||||
import { SubmissionSectionContainerComponent } from './sections/container/section-container.component';
|
import { SubmissionSectionContainerComponent } from './sections/container/section-container.component';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule, NgOptimizedImage } from '@angular/common';
|
||||||
import { Action, StoreConfig, StoreModule } from '@ngrx/store';
|
import { Action, StoreConfig, StoreModule } from '@ngrx/store';
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
import { submissionReducers, SubmissionState } from './submission.reducers';
|
import { submissionReducers, SubmissionState } from './submission.reducers';
|
||||||
@@ -67,6 +67,11 @@ import {
|
|||||||
} from './sections/sherpa-policies/metadata-information/metadata-information.component';
|
} from './sections/sherpa-policies/metadata-information/metadata-information.component';
|
||||||
import { SectionFormOperationsService } from './sections/form/section-form-operations.service';
|
import { SectionFormOperationsService } from './sections/form/section-form-operations.service';
|
||||||
import {SubmissionSectionIdentifiersComponent} from './sections/identifiers/section-identifiers.component';
|
import {SubmissionSectionIdentifiersComponent} from './sections/identifiers/section-identifiers.component';
|
||||||
|
import { SubmissionSectionCoarNotifyComponent } from './sections/section-coar-notify/section-coar-notify.component';
|
||||||
|
import {
|
||||||
|
CoarNotifyConfigDataService
|
||||||
|
} from './sections/section-coar-notify/coar-notify-config-data.service';
|
||||||
|
import { LdnServicesService } from '../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
// put only entry components that use custom decorator
|
// put only entry components that use custom decorator
|
||||||
@@ -76,6 +81,7 @@ const ENTRY_COMPONENTS = [
|
|||||||
SubmissionSectionCcLicensesComponent,
|
SubmissionSectionCcLicensesComponent,
|
||||||
SubmissionSectionAccessesComponent,
|
SubmissionSectionAccessesComponent,
|
||||||
SubmissionSectionSherpaPoliciesComponent,
|
SubmissionSectionSherpaPoliciesComponent,
|
||||||
|
SubmissionSectionCoarNotifyComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const DECLARATIONS = [
|
const DECLARATIONS = [
|
||||||
@@ -109,20 +115,22 @@ const DECLARATIONS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
SharedModule,
|
SharedModule,
|
||||||
StoreModule.forFeature('submission', submissionReducers, storeModuleConfig as StoreConfig<SubmissionState, Action>),
|
StoreModule.forFeature('submission', submissionReducers, storeModuleConfig as StoreConfig<SubmissionState, Action>),
|
||||||
EffectsModule.forFeature(submissionEffects),
|
EffectsModule.forFeature(),
|
||||||
JournalEntitiesModule.withEntryComponents(),
|
EffectsModule.forFeature(submissionEffects),
|
||||||
ResearchEntitiesModule.withEntryComponents(),
|
JournalEntitiesModule.withEntryComponents(),
|
||||||
FormModule,
|
ResearchEntitiesModule.withEntryComponents(),
|
||||||
NgbModalModule,
|
FormModule,
|
||||||
NgbCollapseModule,
|
NgbModalModule,
|
||||||
NgbAccordionModule,
|
NgbCollapseModule,
|
||||||
UploadModule,
|
NgbAccordionModule,
|
||||||
],
|
UploadModule,
|
||||||
|
NgOptimizedImage,
|
||||||
|
],
|
||||||
declarations: DECLARATIONS,
|
declarations: DECLARATIONS,
|
||||||
exports: [
|
exports: [
|
||||||
...DECLARATIONS,
|
...DECLARATIONS,
|
||||||
@@ -135,6 +143,8 @@ const DECLARATIONS = [
|
|||||||
SubmissionAccessesConfigDataService,
|
SubmissionAccessesConfigDataService,
|
||||||
SectionAccessesService,
|
SectionAccessesService,
|
||||||
SectionFormOperationsService,
|
SectionFormOperationsService,
|
||||||
|
CoarNotifyConfigDataService,
|
||||||
|
LdnServicesService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -4,13 +4,19 @@
|
|||||||
<h2 class="border-bottom pb-2">
|
<h2 class="border-bottom pb-2">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
{{'notifications.events.title'| translate}}
|
{{'notifications.events.title'| translate}}
|
||||||
<a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']">
|
<a class="btn btn-outline-secondary" (click)="goBack()">
|
||||||
<i class="fas fa-angle-double-left"></i>
|
<i class="fas fa-angle-double-left"></i>
|
||||||
{{'quality-assurance.events.back' | translate}}
|
{{'quality-assurance.events.back' | translate}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<ds-alert [type]="'alert-info'" [content]="'quality-assurance.events.description'"></ds-alert>
|
<ds-alert *ngIf="!targetId" [type]="'alert-info'">
|
||||||
|
<span [innerHTML]="'quality-assurance.events.description' | translate : {topic: selectedTopicName, source: sourceId}"></span>
|
||||||
|
</ds-alert>
|
||||||
|
<ds-alert *ngIf="targetId" [type]="'alert-info'">
|
||||||
|
<span [innerHTML]="'quality-assurance.events.description-with-topic-and-target' | translate : {topic: selectedTopicName, source: sourceId}"></span>
|
||||||
|
<a [routerLink]="itemPageUrl" target="_blank">{{(getTargetItemTitle() | async)}}</a>
|
||||||
|
</ds-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -54,6 +60,16 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
[routerLink]="['/items', eventElement?.target?.id]">{{eventElement.title}}</a>
|
[routerLink]="['/items', eventElement?.target?.id]">{{eventElement.title}}</a>
|
||||||
<span *ngIf="!eventElement?.target">{{eventElement.title}}</span>
|
<span *ngIf="!eventElement?.target">{{eventElement.title}}</span>
|
||||||
|
<div *ngIf="eventElement?.event?.message?.serviceName">
|
||||||
|
<span class="small pr-1">{{'quality-assurance.event.table.event.message.serviceName' | translate}}</span>
|
||||||
|
<span class="badge badge-info">{{eventElement.event.message.serviceName}}</span>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="eventElement?.event?.message?.href" class="d-flex align-items-center">
|
||||||
|
<span class="small pr-1">{{'quality-assurance.event.table.event.message.link' | translate}}</span>
|
||||||
|
<span [title]="eventElement.event.message.href" class="text-truncate d-inline-block w-75">
|
||||||
|
<a [href]="eventElement.event.message.href" target="_blank">{{eventElement.event.message.href}}</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="showTopic.indexOf('/PID') !== -1">
|
<td *ngIf="showTopic.indexOf('/PID') !== -1">
|
||||||
<p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p>
|
<p><span class="small">{{'quality-assurance.event.table.pidtype' | translate}}</span> <span class="badge badge-info">{{eventElement.event.message.type}}</span></p>
|
||||||
@@ -157,7 +173,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row text-right">
|
<div class="row text-right">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<a class="btn btn-outline-secondary" [routerLink]="['/admin/notifications/quality-assurance']">
|
<a class="btn btn-outline-secondary" (click)="goBack()">
|
||||||
<i class="fas fa-angle-double-left"></i>
|
<i class="fas fa-angle-double-left"></i>
|
||||||
{{'quality-assurance.events.back' | translate}}
|
{{'quality-assurance.events.back' | translate}}
|
||||||
</a>
|
</a>
|
||||||
|
@@ -42,6 +42,7 @@ import { SortDirection, SortOptions } from '../../../core/cache/models/sort-opti
|
|||||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||||
|
import { ItemDataService } from 'src/app/core/data/item-data.service';
|
||||||
|
|
||||||
describe('QualityAssuranceEventsComponent test suite', () => {
|
describe('QualityAssuranceEventsComponent test suite', () => {
|
||||||
let fixture: ComponentFixture<QualityAssuranceEventsComponent>;
|
let fixture: ComponentFixture<QualityAssuranceEventsComponent>;
|
||||||
@@ -118,6 +119,7 @@ describe('QualityAssuranceEventsComponent test suite', () => {
|
|||||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
||||||
{ provide: TranslateService, useValue: getMockTranslateService() },
|
{ provide: TranslateService, useValue: getMockTranslateService() },
|
||||||
{ provide: PaginationService, useValue: paginationService },
|
{ provide: PaginationService, useValue: paginationService },
|
||||||
|
{ provide: ItemDataService, useValue: {} },
|
||||||
QualityAssuranceEventsComponent
|
QualityAssuranceEventsComponent
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@@ -26,10 +27,12 @@ import {
|
|||||||
ProjectEntryImportModalComponent,
|
ProjectEntryImportModalComponent,
|
||||||
QualityAssuranceEventData
|
QualityAssuranceEventData
|
||||||
} from '../project-entry-import-modal/project-entry-import-modal.component';
|
} from '../project-entry-import-modal/project-entry-import-modal.component';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
import { Item } from '../../../core/shared/item.model';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||||
|
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
|
||||||
|
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display the Quality Assurance event list.
|
* Component to display the Quality Assurance event list.
|
||||||
@@ -105,6 +108,26 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
protected subs: Subscription[] = [];
|
protected subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target item id, retrieved from the topic-id composition.
|
||||||
|
*/
|
||||||
|
public targetId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the item page/target.
|
||||||
|
*/
|
||||||
|
public itemPageUrl: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plain topic name (without the source id)
|
||||||
|
*/
|
||||||
|
public selectedTopicName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source id, retrieved from the topic-id composition.
|
||||||
|
*/
|
||||||
|
public sourceId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the component variables.
|
* Initialize the component variables.
|
||||||
* @param {ActivatedRoute} activatedRoute
|
* @param {ActivatedRoute} activatedRoute
|
||||||
@@ -120,7 +143,9 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
|||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private qualityAssuranceEventRestService: QualityAssuranceEventDataService,
|
private qualityAssuranceEventRestService: QualityAssuranceEventDataService,
|
||||||
private paginationService: PaginationService,
|
private paginationService: PaginationService,
|
||||||
private translateService: TranslateService
|
private translateService: TranslateService,
|
||||||
|
private itemService: ItemDataService,
|
||||||
|
private _location: Location
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,10 +162,13 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
|||||||
const regEx = /!/g;
|
const regEx = /!/g;
|
||||||
this.showTopic = id.replace(regEx, '/');
|
this.showTopic = id.replace(regEx, '/');
|
||||||
this.topic = id;
|
this.topic = id;
|
||||||
|
const splitList = this.showTopic?.split(':');
|
||||||
|
this.targetId = splitList.length > 2 ? splitList.pop() : null;
|
||||||
|
this.sourceId = splitList[0];
|
||||||
|
this.selectedTopicName = splitList[1];
|
||||||
return this.getQualityAssuranceEvents();
|
return this.getQualityAssuranceEvents();
|
||||||
})
|
})
|
||||||
).subscribe((events: QualityAssuranceEventData[]) => {
|
).subscribe((events: QualityAssuranceEventData[]) => {
|
||||||
console.log(events);
|
|
||||||
this.eventsUpdated$.next(events);
|
this.eventsUpdated$.next(events);
|
||||||
this.isEventPageLoading.next(false);
|
this.isEventPageLoading.next(false);
|
||||||
});
|
});
|
||||||
@@ -356,7 +384,6 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
|||||||
if (rd.hasSucceeded) {
|
if (rd.hasSucceeded) {
|
||||||
this.totalElements$.next(rd.payload.totalElements);
|
this.totalElements$.next(rd.payload.totalElements);
|
||||||
if (rd.payload.totalElements > 0) {
|
if (rd.payload.totalElements > 0) {
|
||||||
console.log(rd.payload.page);
|
|
||||||
return this.fetchEvents(rd.payload.page);
|
return this.fetchEvents(rd.payload.page);
|
||||||
} else {
|
} else {
|
||||||
return of([]);
|
return of([]);
|
||||||
@@ -425,4 +452,37 @@ export class QualityAssuranceEventsComponent implements OnInit, OnDestroy {
|
|||||||
last()
|
last()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page route for the given item.
|
||||||
|
* @param item The item to get the page route for.
|
||||||
|
* @returns The page route for the given item.
|
||||||
|
*/
|
||||||
|
public getItemPageRoute(item: Item): string {
|
||||||
|
return getItemPageRoute(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Observable that emits the title of the target item.
|
||||||
|
* The target item is retrieved by its ID using the itemService.
|
||||||
|
* The title is extracted from the first metadata value of the item.
|
||||||
|
* The item page URL is also set in the component.
|
||||||
|
* @returns An Observable that emits the title of the target item.
|
||||||
|
*/
|
||||||
|
public getTargetItemTitle(): Observable<string> {
|
||||||
|
return this.itemService.findById(this.targetId).pipe(
|
||||||
|
take(1),
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
tap((item: Item) => this.itemPageUrl = getItemPageRoute(item)),
|
||||||
|
map((item: Item) => item.firstMetadataValue('dc.title'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates back to the previous location in the browser's history stack.
|
||||||
|
*/
|
||||||
|
public goBack() {
|
||||||
|
this._location.back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,8 @@ export class RetrieveAllTopicsAction implements Action {
|
|||||||
payload: {
|
payload: {
|
||||||
elementsPerPage: number;
|
elementsPerPage: number;
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
|
source: string;
|
||||||
|
target?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,10 +37,12 @@ export class RetrieveAllTopicsAction implements Action {
|
|||||||
* @param currentPage
|
* @param currentPage
|
||||||
* The page number to retrieve
|
* The page number to retrieve
|
||||||
*/
|
*/
|
||||||
constructor(elementsPerPage: number, currentPage: number) {
|
constructor(elementsPerPage: number, currentPage: number, source: string, target?: string) {
|
||||||
this.payload = {
|
this.payload = {
|
||||||
elementsPerPage,
|
elementsPerPage,
|
||||||
currentPage
|
currentPage,
|
||||||
|
source,
|
||||||
|
target
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,11 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2>
|
<h2 class="border-bottom pb-2">{{'quality-assurance.title'| translate}}</h2>
|
||||||
<ds-alert [type]="'alert-info'">{{'quality-assurance.topics.description'| translate:{source: sourceId} }}</ds-alert>
|
<ds-alert *ngIf="!targetId" [type]="'alert-info'">{{'quality-assurance.topics.description'| translate:{source: sourceId} }}</ds-alert>
|
||||||
|
<ds-alert *ngIf="targetId" [type]="'alert-info'">
|
||||||
|
{{'quality-assurance.topics.description-with-target'| translate:{source: sourceId} }}
|
||||||
|
<a [routerLink]="itemPageUrl">{{(getTargetItemTitle() | async)}}</a>
|
||||||
|
</ds-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@@ -15,7 +19,7 @@
|
|||||||
[collectionSize]="(totalElements$ | async)"
|
[collectionSize]="(totalElements$ | async)"
|
||||||
[hideGear]="false"
|
[hideGear]="false"
|
||||||
[hideSortOptions]="true"
|
[hideSortOptions]="true"
|
||||||
(paginationChange)="getQualityAssuranceTopics()">
|
(paginationChange)="getQualityAssuranceTopics(sourceId, targetId)">
|
||||||
|
|
||||||
<ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'quality-assurance.loading' | translate"></ds-loading>
|
<ds-loading class="container" *ngIf="(isTopicsProcessing() | async)" message="'quality-assurance.loading' | translate"></ds-loading>
|
||||||
<ng-container *ngIf="!(isTopicsProcessing() | async)">
|
<ng-container *ngIf="!(isTopicsProcessing() | async)">
|
||||||
@@ -40,7 +44,7 @@
|
|||||||
<button
|
<button
|
||||||
class="btn btn-outline-primary btn-sm"
|
class="btn btn-outline-primary btn-sm"
|
||||||
title="{{'quality-assurance.button.detail' | translate }}"
|
title="{{'quality-assurance.button.detail' | translate }}"
|
||||||
[routerLink]="[topicElement.id]">
|
[routerLink]="['/admin/notifications/quality-assurance', sourceId, topicElement.id]">
|
||||||
<span class="badge badge-info">{{topicElement.totalEvents}}</span>
|
<span class="badge badge-info">{{topicElement.totalEvents}}</span>
|
||||||
<i class="fas fa-info fa-fw"></i>
|
<i class="fas fa-info fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@@ -16,7 +16,7 @@ import { SuggestionNotificationsStateService } from '../../suggestion-notificati
|
|||||||
import { cold } from 'jasmine-marbles';
|
import { cold } from 'jasmine-marbles';
|
||||||
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
|
||||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||||
import { QualityAssuranceTopicsService } from './quality-assurance-topics.service';
|
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||||
|
|
||||||
describe('QualityAssuranceTopicsComponent test suite', () => {
|
describe('QualityAssuranceTopicsComponent test suite', () => {
|
||||||
let fixture: ComponentFixture<QualityAssuranceTopicsComponent>;
|
let fixture: ComponentFixture<QualityAssuranceTopicsComponent>;
|
||||||
@@ -44,14 +44,14 @@ describe('QualityAssuranceTopicsComponent test suite', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService },
|
{ provide: SuggestionNotificationsStateService, useValue: mockNotificationsStateService },
|
||||||
{ provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), snapshot: {
|
{ provide: ActivatedRoute, useValue: { data: observableOf(activatedRouteParams), snapshot: {
|
||||||
paramMap: {
|
params: {
|
||||||
get: () => 'openaire',
|
sourceId: 'openaire',
|
||||||
|
targetId: null
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
{ provide: PaginationService, useValue: paginationService },
|
{ provide: PaginationService, useValue: paginationService },
|
||||||
|
{ provide: ItemDataService, useValue: {} },
|
||||||
QualityAssuranceTopicsComponent,
|
QualityAssuranceTopicsComponent,
|
||||||
// tslint:disable-next-line: no-empty
|
|
||||||
{ provide: QualityAssuranceTopicsService, useValue: { setSourceId: (sourceId: string) => { } }}
|
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { distinctUntilChanged, take } from 'rxjs/operators';
|
import { distinctUntilChanged, map, take, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { SortOptions } from '../../../core/cache/models/sort-options.model';
|
import { SortOptions } from '../../../core/cache/models/sort-options.model';
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +15,10 @@ import {
|
|||||||
} from '../../../admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service';
|
} from '../../../admin/admin-notifications/admin-quality-assurance-topics-page/admin-quality-assurance-topics-page-resolver.service';
|
||||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { QualityAssuranceTopicsService } from './quality-assurance-topics.service';
|
import { ItemDataService } from '../../../core/data/item-data.service';
|
||||||
|
import { getFirstCompletedRemoteData, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||||
|
import { Item } from '../../../core/shared/item.model';
|
||||||
|
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display the Quality Assurance topic list.
|
* Component to display the Quality Assurance topic list.
|
||||||
@@ -60,6 +63,17 @@ export class QualityAssuranceTopicsComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
public sourceId: string;
|
public sourceId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This property represents a targetId (item-id) which is used to retrive a topic
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public targetId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the item page.
|
||||||
|
*/
|
||||||
|
public itemPageUrl: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the component variables.
|
* Initialize the component variables.
|
||||||
* @param {PaginationService} paginationService
|
* @param {PaginationService} paginationService
|
||||||
@@ -71,16 +85,16 @@ export class QualityAssuranceTopicsComponent implements OnInit {
|
|||||||
private paginationService: PaginationService,
|
private paginationService: PaginationService,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private notificationsStateService: SuggestionNotificationsStateService,
|
private notificationsStateService: SuggestionNotificationsStateService,
|
||||||
private qualityAssuranceTopicsService: QualityAssuranceTopicsService
|
private itemService: ItemDataService
|
||||||
) {
|
) {
|
||||||
|
this.sourceId = this.activatedRoute.snapshot.params.sourceId;
|
||||||
|
this.targetId = this.activatedRoute.snapshot.params.targetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component initialization.
|
* Component initialization.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.sourceId = this.activatedRoute.snapshot.paramMap.get('sourceId');
|
|
||||||
this.qualityAssuranceTopicsService.setSourceId(this.sourceId);
|
|
||||||
this.topics$ = this.notificationsStateService.getQualityAssuranceTopics();
|
this.topics$ = this.notificationsStateService.getQualityAssuranceTopics();
|
||||||
this.totalElements$ = this.notificationsStateService.getQualityAssuranceTopicsTotals();
|
this.totalElements$ = this.notificationsStateService.getQualityAssuranceTopicsTotals();
|
||||||
}
|
}
|
||||||
@@ -93,7 +107,7 @@ export class QualityAssuranceTopicsComponent implements OnInit {
|
|||||||
this.notificationsStateService.isQualityAssuranceTopicsLoaded().pipe(
|
this.notificationsStateService.isQualityAssuranceTopicsLoaded().pipe(
|
||||||
take(1)
|
take(1)
|
||||||
).subscribe(() => {
|
).subscribe(() => {
|
||||||
this.getQualityAssuranceTopics();
|
this.getQualityAssuranceTopics(this.sourceId, this.targetId);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -121,13 +135,15 @@ export class QualityAssuranceTopicsComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* Dispatch the Quality Assurance topics retrival.
|
* Dispatch the Quality Assurance topics retrival.
|
||||||
*/
|
*/
|
||||||
public getQualityAssuranceTopics(): void {
|
public getQualityAssuranceTopics(source: string, target?: string): void {
|
||||||
this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe(
|
this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig).pipe(
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
).subscribe((options: PaginationComponentOptions) => {
|
).subscribe((options: PaginationComponentOptions) => {
|
||||||
this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics(
|
this.notificationsStateService.dispatchRetrieveQualityAssuranceTopics(
|
||||||
options.pageSize,
|
options.pageSize,
|
||||||
options.currentPage
|
options.currentPage,
|
||||||
|
source,
|
||||||
|
target
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -150,6 +166,32 @@ export class QualityAssuranceTopicsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Observable that emits the title of the target item.
|
||||||
|
* The target item is retrieved by its ID using the itemService.
|
||||||
|
* The title is extracted from the first metadata value of the item.
|
||||||
|
* The item page URL is also set in the component.
|
||||||
|
* @returns An Observable that emits the title of the target item.
|
||||||
|
*/
|
||||||
|
getTargetItemTitle(): Observable<string> {
|
||||||
|
return this.itemService.findById(this.targetId).pipe(
|
||||||
|
take(1),
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
tap((item: Item) => this.itemPageUrl = getItemPageRoute(item)),
|
||||||
|
map((item: Item) => item.firstMetadataValue('dc.title'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page route for the given item.
|
||||||
|
* @param item The item to get the page route for.
|
||||||
|
* @returns The page route for the given item.
|
||||||
|
*/
|
||||||
|
getItemPageRoute(item: Item): string {
|
||||||
|
return getItemPageRoute(item);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribe from all subscriptions.
|
* Unsubscribe from all subscriptions.
|
||||||
*/
|
*/
|
||||||
|
@@ -37,7 +37,9 @@ export class QualityAssuranceTopicsEffects {
|
|||||||
switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => {
|
switchMap(([action, currentState]: [RetrieveAllTopicsAction, any]) => {
|
||||||
return this.qualityAssuranceTopicService.getTopics(
|
return this.qualityAssuranceTopicService.getTopics(
|
||||||
action.payload.elementsPerPage,
|
action.payload.elementsPerPage,
|
||||||
action.payload.currentPage
|
action.payload.currentPage,
|
||||||
|
action.payload.source,
|
||||||
|
action.payload.target
|
||||||
).pipe(
|
).pipe(
|
||||||
map((topics: PaginatedList<QualityAssuranceTopicObject>) =>
|
map((topics: PaginatedList<QualityAssuranceTopicObject>) =>
|
||||||
new AddTopicsAction(topics.page, topics.totalPages, topics.currentPage, topics.totalElements)
|
new AddTopicsAction(topics.page, topics.totalPages, topics.currentPage, topics.totalElements)
|
||||||
|
@@ -29,7 +29,7 @@ describe('qualityAssuranceTopicsReducer test suite', () => {
|
|||||||
const expectedState = qualityAssuranceTopicInitialState;
|
const expectedState = qualityAssuranceTopicInitialState;
|
||||||
expectedState.processing = true;
|
expectedState.processing = true;
|
||||||
|
|
||||||
const action = new RetrieveAllTopicsAction(elementPerPage, currentPage);
|
const action = new RetrieveAllTopicsAction(elementPerPage, currentPage, 'source', 'target');
|
||||||
const newState = qualityAssuranceTopicsReducer(qualityAssuranceTopicInitialState, action);
|
const newState = qualityAssuranceTopicsReducer(qualityAssuranceTopicInitialState, action);
|
||||||
|
|
||||||
expect(newState).toEqual(expectedState);
|
expect(newState).toEqual(expectedState);
|
||||||
|
@@ -42,31 +42,46 @@ describe('QualityAssuranceTopicsService', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
restService = TestBed.inject(QualityAssuranceTopicDataService);
|
restService = TestBed.inject(QualityAssuranceTopicDataService);
|
||||||
restServiceAsAny = restService;
|
restServiceAsAny = restService;
|
||||||
restServiceAsAny.getTopics.and.returnValue(observableOf(paginatedListRD));
|
restServiceAsAny.searchTopicsBySource.and.returnValue(observableOf(paginatedListRD));
|
||||||
|
restServiceAsAny.searchTopicsByTarget.and.returnValue(observableOf(paginatedListRD));
|
||||||
service = new QualityAssuranceTopicsService(restService);
|
service = new QualityAssuranceTopicsService(restService);
|
||||||
serviceAsAny = service;
|
serviceAsAny = service;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getTopics', () => {
|
describe('getTopicsBySource', () => {
|
||||||
it('Should proxy the call to qualityAssuranceTopicRestService.getTopics', () => {
|
it('should proxy the call to qualityAssuranceTopicRestService.searchTopicsBySource', () => {
|
||||||
const sortOptions = new SortOptions('name', SortDirection.ASC);
|
const sortOptions = new SortOptions('name', SortDirection.ASC);
|
||||||
const findListOptions: FindListOptions = {
|
const findListOptions: FindListOptions = {
|
||||||
elementsPerPage: elementsPerPage,
|
elementsPerPage: elementsPerPage,
|
||||||
currentPage: currentPage,
|
currentPage: currentPage,
|
||||||
sort: sortOptions,
|
sort: sortOptions,
|
||||||
searchParams: [new RequestParam('source', 'ENRICH!MORE!ABSTRACT')]
|
searchParams: [new RequestParam('source', 'openaire')]
|
||||||
};
|
};
|
||||||
service.setSourceId('ENRICH!MORE!ABSTRACT');
|
const result = service.getTopics(elementsPerPage, currentPage, 'openaire');
|
||||||
const result = service.getTopics(elementsPerPage, currentPage);
|
expect((service as any).qualityAssuranceTopicRestService.searchTopicsBySource).toHaveBeenCalledWith(findListOptions);
|
||||||
expect((service as any).qualityAssuranceTopicRestService.getTopics).toHaveBeenCalledWith(findListOptions);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should return a paginated list of Quality Assurance topics', () => {
|
it('should return a paginated list of Quality Assurance topics', () => {
|
||||||
const expected = cold('(a|)', {
|
const expected = cold('(a|)', {
|
||||||
a: paginatedList
|
a: paginatedList
|
||||||
});
|
});
|
||||||
const result = service.getTopics(elementsPerPage, currentPage);
|
const result = service.getTopics(elementsPerPage, currentPage, 'openaire');
|
||||||
expect(result).toBeObservable(expected);
|
expect(result).toBeObservable(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should include targetId in searchParams if set', () => {
|
||||||
|
const sortOptions = new SortOptions('name', SortDirection.ASC);
|
||||||
|
const findListOptions: FindListOptions = {
|
||||||
|
elementsPerPage: elementsPerPage,
|
||||||
|
currentPage: currentPage,
|
||||||
|
sort: sortOptions,
|
||||||
|
searchParams: [
|
||||||
|
new RequestParam('source', 'openaire'),
|
||||||
|
new RequestParam('target', '0000-0000-0000-0000-0000')
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const result = service.getTopics(elementsPerPage, currentPage,'openaire', '0000-0000-0000-0000-0000');
|
||||||
|
expect((service as any).qualityAssuranceTopicRestService.searchTopicsByTarget).toHaveBeenCalledWith(findListOptions);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -13,6 +13,7 @@ import {
|
|||||||
import { RequestParam } from '../../../core/cache/models/request-param.model';
|
import { RequestParam } from '../../../core/cache/models/request-param.model';
|
||||||
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
import { FindListOptions } from '../../../core/data/find-list-options.model';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||||
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The service handling all Quality Assurance topic requests to the REST service.
|
* The service handling all Quality Assurance topic requests to the REST service.
|
||||||
@@ -28,10 +29,6 @@ export class QualityAssuranceTopicsService {
|
|||||||
private qualityAssuranceTopicRestService: QualityAssuranceTopicDataService
|
private qualityAssuranceTopicRestService: QualityAssuranceTopicDataService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
|
||||||
* sourceId used to get topics
|
|
||||||
*/
|
|
||||||
sourceId: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the list of Quality Assurance topics managing pagination and errors.
|
* Return the list of Quality Assurance topics managing pagination and errors.
|
||||||
@@ -43,17 +40,25 @@ export class QualityAssuranceTopicsService {
|
|||||||
* @return Observable<PaginatedList<QualityAssuranceTopicObject>>
|
* @return Observable<PaginatedList<QualityAssuranceTopicObject>>
|
||||||
* The list of Quality Assurance topics.
|
* The list of Quality Assurance topics.
|
||||||
*/
|
*/
|
||||||
public getTopics(elementsPerPage, currentPage): Observable<PaginatedList<QualityAssuranceTopicObject>> {
|
public getTopics(elementsPerPage, currentPage, source: string, target?: string): Observable<PaginatedList<QualityAssuranceTopicObject>> {
|
||||||
const sortOptions = new SortOptions('name', SortDirection.ASC);
|
const sortOptions = new SortOptions('name', SortDirection.ASC);
|
||||||
|
|
||||||
const findListOptions: FindListOptions = {
|
const findListOptions: FindListOptions = {
|
||||||
elementsPerPage: elementsPerPage,
|
elementsPerPage: elementsPerPage,
|
||||||
currentPage: currentPage,
|
currentPage: currentPage,
|
||||||
sort: sortOptions,
|
sort: sortOptions,
|
||||||
searchParams: [new RequestParam('source', this.sourceId)]
|
searchParams: [new RequestParam('source', source)]
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.qualityAssuranceTopicRestService.getTopics(findListOptions).pipe(
|
let request$: Observable<RemoteData<PaginatedList<QualityAssuranceTopicObject>>>;
|
||||||
|
|
||||||
|
if (hasValue(target)) {
|
||||||
|
findListOptions.searchParams.push(new RequestParam('target', target));
|
||||||
|
request$ = this.qualityAssuranceTopicRestService.searchTopicsByTarget(findListOptions);
|
||||||
|
} else {
|
||||||
|
request$ = this.qualityAssuranceTopicRestService.searchTopicsBySource(findListOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request$.pipe(
|
||||||
getFirstCompletedRemoteData(),
|
getFirstCompletedRemoteData(),
|
||||||
map((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => {
|
map((rd: RemoteData<PaginatedList<QualityAssuranceTopicObject>>) => {
|
||||||
if (rd.hasSucceeded) {
|
if (rd.hasSucceeded) {
|
||||||
@@ -64,12 +69,4 @@ export class QualityAssuranceTopicsService {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* set sourceId which is used to get topics
|
|
||||||
* @param sourceId string
|
|
||||||
*/
|
|
||||||
setSourceId(sourceId: string) {
|
|
||||||
this.sourceId = sourceId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,8 @@ describe('SuggestionsPopupComponent', () => {
|
|||||||
const suggestionStateService = jasmine.createSpyObj('SuggestionTargetsStateService', {
|
const suggestionStateService = jasmine.createSpyObj('SuggestionTargetsStateService', {
|
||||||
hasUserVisitedSuggestions: jasmine.createSpy('hasUserVisitedSuggestions'),
|
hasUserVisitedSuggestions: jasmine.createSpy('hasUserVisitedSuggestions'),
|
||||||
getCurrentUserSuggestionTargets: jasmine.createSpy('getCurrentUserSuggestionTargets'),
|
getCurrentUserSuggestionTargets: jasmine.createSpy('getCurrentUserSuggestionTargets'),
|
||||||
dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction')
|
dispatchMarkUserSuggestionsAsVisitedAction: jasmine.createSpy('dispatchMarkUserSuggestionsAsVisitedAction'),
|
||||||
|
dispatchRefreshUserSuggestionsAction: jasmine.createSpy('dispatchRefreshUserSuggestionsAction')
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockNotificationInterpolation = { count: 12, source: 'source', suggestionId: 'id', displayName: 'displayName' };
|
const mockNotificationInterpolation = { count: 12, source: 'source', suggestionId: 'id', displayName: 'displayName' };
|
||||||
|
@@ -31,7 +31,6 @@ export class SuggestionsPopupComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public initializePopup() {
|
public initializePopup() {
|
||||||
console.log('POPUP INIT dispatchRefreshUserSuggestionsAction');
|
|
||||||
this.reciterSuggestionStateService.dispatchRefreshUserSuggestionsAction();
|
this.reciterSuggestionStateService.dispatchRefreshUserSuggestionsAction();
|
||||||
const notifier = new Subject();
|
const notifier = new Subject();
|
||||||
this.subscription = combineLatest([
|
this.subscription = combineLatest([
|
||||||
|
@@ -271,8 +271,8 @@ describe('NotificationsStateService', () => {
|
|||||||
it('Should call store.dispatch', () => {
|
it('Should call store.dispatch', () => {
|
||||||
const elementsPerPage = 3;
|
const elementsPerPage = 3;
|
||||||
const currentPage = 1;
|
const currentPage = 1;
|
||||||
const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage);
|
const action = new RetrieveAllTopicsAction(elementsPerPage, currentPage, 'source', 'target');
|
||||||
service.dispatchRetrieveQualityAssuranceTopics(elementsPerPage, currentPage);
|
service.dispatchRetrieveQualityAssuranceTopics(elementsPerPage, currentPage, 'source', 'target');
|
||||||
expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action);
|
expect(serviceAsAny.store.dispatch).toHaveBeenCalledWith(action);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -118,8 +118,8 @@ export class SuggestionNotificationsStateService {
|
|||||||
* @param currentPage
|
* @param currentPage
|
||||||
* The number of the current page.
|
* The number of the current page.
|
||||||
*/
|
*/
|
||||||
public dispatchRetrieveQualityAssuranceTopics(elementsPerPage: number, currentPage: number): void {
|
public dispatchRetrieveQualityAssuranceTopics(elementsPerPage: number, currentPage: number, sourceId: string, targteId?: string): void {
|
||||||
this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage));
|
this.store.dispatch(new RetrieveAllTopicsAction(elementsPerPage, currentPage, sourceId, targteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quality Assurance source
|
// Quality Assurance source
|
||||||
|
@@ -5,7 +5,6 @@ import { SuggestionsPageResolver } from './suggestions-page.resolver';
|
|||||||
import { SuggestionsPageComponent } from './suggestions-page.component';
|
import { SuggestionsPageComponent } from './suggestions-page.component';
|
||||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
import { SiteAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@@ -892,11 +892,11 @@
|
|||||||
|
|
||||||
"coar-notify-support.title": "COAR Notify Protocol",
|
"coar-notify-support.title": "COAR Notify Protocol",
|
||||||
|
|
||||||
"coar-notify-support-title.content":"Here, we fully support the COAR Notify protocol, which is designed to enhance the communication between repositories. To learn more about the COAR Notify protocol, you can visit their official website <a href=\"https://notify.coar-repositories.org/\">here</a>.",
|
"coar-notify-support-title.content": "Here, we fully support the COAR Notify protocol, which is designed to enhance the communication between repositories. To learn more about the COAR Notify protocol, you can visit their official website <a href=\"https://notify.coar-repositories.org/\">here</a>.",
|
||||||
|
|
||||||
"coar-notify-support.ldn-inbox.title": "LDN InBox",
|
"coar-notify-support.ldn-inbox.title": "LDN InBox",
|
||||||
|
|
||||||
"coar-notify-support.ldn-inbox.content": "For your convenience, our LDN (Linked Data Notifications) InBox is easily accessible at <code>{restApiUrl}ldn/inbox</code>. The LDN InBox enables seamless communication and data exchange, ensuring efficient and effective collaboration.",
|
"coar-notify-support.ldn-inbox.content": "For your convenience, our LDN (Linked Data Notifications) InBox is easily accessible at <code>{ldnInboxUrl}ldn/inbox</code>. The LDN InBox enables seamless communication and data exchange, ensuring efficient and effective collaboration.",
|
||||||
|
|
||||||
"coar-notify-support.message-moderation.title": "Message Moderation",
|
"coar-notify-support.message-moderation.title": "Message Moderation",
|
||||||
|
|
||||||
@@ -905,7 +905,7 @@
|
|||||||
"service.overview.delete.header": "Delete Service",
|
"service.overview.delete.header": "Delete Service",
|
||||||
|
|
||||||
"ldn-registered-services.title": "Registered Services",
|
"ldn-registered-services.title": "Registered Services",
|
||||||
"ldn-registered-services.table.name":"Name",
|
"ldn-registered-services.table.name": "Name",
|
||||||
"ldn-registered-services.table.description": "Description",
|
"ldn-registered-services.table.description": "Description",
|
||||||
"ldn-registered-services.table.status": "Status",
|
"ldn-registered-services.table.status": "Status",
|
||||||
"ldn-registered-services.table.action": "Action",
|
"ldn-registered-services.table.action": "Action",
|
||||||
@@ -920,7 +920,7 @@
|
|||||||
"ldn-edit-registered-service.title": "Edit Service",
|
"ldn-edit-registered-service.title": "Edit Service",
|
||||||
"ldn-create-service.title": "Create service",
|
"ldn-create-service.title": "Create service",
|
||||||
"service.overview.create.modal": "Create Service",
|
"service.overview.create.modal": "Create Service",
|
||||||
"service.overview.create.body": "Please confirm the creation of this service",
|
"service.overview.create.body": "Please confirm the creation of this service.",
|
||||||
"ldn-service-status": "Status",
|
"ldn-service-status": "Status",
|
||||||
"service.confirm.create": "Create",
|
"service.confirm.create": "Create",
|
||||||
"service.refuse.create": "Discard",
|
"service.refuse.create": "Discard",
|
||||||
@@ -929,16 +929,77 @@
|
|||||||
"ldn-new-service.form.label.name": "Name",
|
"ldn-new-service.form.label.name": "Name",
|
||||||
"ldn-new-service.form.label.description": "Description",
|
"ldn-new-service.form.label.description": "Description",
|
||||||
"ldn-new-service.form.label.url": "Service URL",
|
"ldn-new-service.form.label.url": "Service URL",
|
||||||
|
"ldn-new-service.form.label.score": "Level of trust",
|
||||||
"ldn-new-service.form.label.ldnUrl": "LDN Inbox URL",
|
"ldn-new-service.form.label.ldnUrl": "LDN Inbox URL",
|
||||||
"ldn-new-service.form.placeholder.name": "Please provide service name",
|
"ldn-new-service.form.placeholder.name": "Please provide service name",
|
||||||
"ldn-new-service.form.placeholder.description": "Please provide a description regarding your service",
|
"ldn-new-service.form.placeholder.description": "Please provide a description regarding your service",
|
||||||
"ldn-new-service.form.placeholder.url": "Please input the URL for users to check out more information about the service",
|
"ldn-new-service.form.placeholder.url": "Please input the URL for users to check out more information about the service",
|
||||||
"ldn-new-service.form.placeholder.ldnUrl": "Please specify the URL of the LDN Inbox",
|
"ldn-new-service.form.placeholder.ldnUrl": "Please specify the URL of the LDN Inbox",
|
||||||
"ldn-new-service.form.label.inboundPattern": "Inbound Patterns",
|
"ldn-new-service.form.placeholder.score": "Please enter a value between 0 and 1. Use the “.” as decimal separator",
|
||||||
"ldn-new-service.form.label.placeholder.inboundPattern": "Select an Inbound Pattern",
|
"ldn-service.form.label.placeholder.default-select": "Select a pattern",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.ack-accept.label": "Acknowledge and Accept",
|
||||||
|
"ldn-service.form.pattern.ack-accept.description": "This pattern is used to acknowledge and accept a request (offer). It implies an intention to act on the request.",
|
||||||
|
"ldn-service.form.pattern.ack-accept.category": "Acknowledgements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.ack-reject.label": "Acknowledge and Reject",
|
||||||
|
"ldn-service.form.pattern.ack-reject.description": "This pattern is used to acknowledge and reject a request (offer). It signifies no further action regarding the request.",
|
||||||
|
"ldn-service.form.pattern.ack-reject.category": "Acknowledgements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.ack-tentative-accept.label": "Acknowledge and Tentatively Accept",
|
||||||
|
"ldn-service.form.pattern.ack-tentative-accept.description": "This pattern is used to acknowledge and tentatively accept a request (offer). It implies an intention to act, which may change.",
|
||||||
|
"ldn-service.form.pattern.ack-tentative-accept.category": "Acknowledgements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.ack-tentative-reject.label": "Acknowledge and Tentatively Reject",
|
||||||
|
"ldn-service.form.pattern.ack-tentative-reject.description": "This pattern is used to acknowledge and tentatively reject a request (offer). It signifies no further action, subject to change.",
|
||||||
|
"ldn-service.form.pattern.ack-tentative-reject.category": "Acknowledgements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.announce-endorsement.label": "Announce Endorsement",
|
||||||
|
"ldn-service.form.pattern.announce-endorsement.description": "This pattern is used to announce the existence of an endorsement, referencing the endorsed resource.",
|
||||||
|
"ldn-service.form.pattern.announce-endorsement.category": "Announcements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.announce-ingest.label": "Announce Ingest",
|
||||||
|
"ldn-service.form.pattern.announce-ingest.description": "This pattern is used to announce that a resource has been ingested.",
|
||||||
|
"ldn-service.form.pattern.announce-ingest.category": "Announcements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.announce-relationship.label": "Announce Relationship",
|
||||||
|
"ldn-service.form.pattern.announce-relationship.description": "This pattern is used to announce a relationship between two resources.",
|
||||||
|
"ldn-service.form.pattern.announce-relationship.category": "Announcements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.announce-review.label": "Announce Review",
|
||||||
|
"ldn-service.form.pattern.announce-review.description": "This pattern is used to announce the existence of a review, referencing the reviewed resource.",
|
||||||
|
"ldn-service.form.pattern.announce-review.category": "Announcements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.announce-service-result.label": "Announce Service Result",
|
||||||
|
"ldn-service.form.pattern.announce-service-result.description": "This pattern is used to announce the existence of a 'service result', referencing the relevant resource.",
|
||||||
|
"ldn-service.form.pattern.announce-service-result.category": "Announcements",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.request-endorsement.label": "Request Endorsement",
|
||||||
|
"ldn-service.form.pattern.request-endorsement.description": "This pattern is used to request endorsement of a resource owned by the origin system.",
|
||||||
|
"ldn-service.form.pattern.request-endorsement.category": "Requests",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.request-ingest.label": "Request Ingest",
|
||||||
|
"ldn-service.form.pattern.request-ingest.description": "This pattern is used to request that the target system ingest a resource.",
|
||||||
|
"ldn-service.form.pattern.request-ingest.category": "Requests",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.request-review.label": "Request Review",
|
||||||
|
"ldn-service.form.pattern.request-review.description": "This pattern is used to request a review of a resource owned by the origin system.",
|
||||||
|
"ldn-service.form.pattern.request-review.category": "Requests",
|
||||||
|
|
||||||
|
"ldn-service.form.pattern.undo-offer.label": "Undo Offer",
|
||||||
|
"ldn-service.form.pattern.undo-offer.description": "This pattern is used to undo (retract) an offer previously made.",
|
||||||
|
"ldn-service.form.pattern.undo-offer.category": "Undo",
|
||||||
|
|
||||||
"ldn-new-service.form.label.placeholder.selectedItemFilter": "No Item Filter Selected",
|
"ldn-new-service.form.label.placeholder.selectedItemFilter": "No Item Filter Selected",
|
||||||
"ldn-new-service.form.label.ItemFilter": "Item Filter",
|
"ldn-new-service.form.label.ItemFilter": "Item Filter",
|
||||||
"ldn-new-service.form.label.automatic": "Automatic",
|
"ldn-new-service.form.label.automatic": "Automatic",
|
||||||
|
"ldn-new-service.form.error.name": "Name is required",
|
||||||
|
"ldn-new-service.form.error.url": "URL is required",
|
||||||
|
"ldn-new-service.form.error.ldnurl": "LDN URL is required",
|
||||||
|
"ldn-new-service.form.error.patterns": "At least a pattern is required",
|
||||||
|
"ldn-new-service.form.error.score": "Please enter a valid score (between 0 and 1). Use the “.” as decimal separator",
|
||||||
|
|
||||||
|
"ldn-new-service.form.label.inboundPattern": "Inbound Pattern",
|
||||||
"ldn-new-service.form.label.outboundPattern": "Outbound Patterns",
|
"ldn-new-service.form.label.outboundPattern": "Outbound Patterns",
|
||||||
"ldn-new-service.form.label.placeholder.outboundPattern": "Select an Outbound Pattern",
|
"ldn-new-service.form.label.placeholder.outboundPattern": "Select an Outbound Pattern",
|
||||||
"ldn-new-service.form.label.addPattern": "+ Add more",
|
"ldn-new-service.form.label.addPattern": "+ Add more",
|
||||||
@@ -951,11 +1012,15 @@
|
|||||||
"service.detail.return": "Cancel",
|
"service.detail.return": "Cancel",
|
||||||
"service.overview.reset-form.body": "Are you sure you want to discard those changes and leave?",
|
"service.overview.reset-form.body": "Are you sure you want to discard those changes and leave?",
|
||||||
"service.overview.reset-form.modal": "Discard Service Changes",
|
"service.overview.reset-form.modal": "Discard Service Changes",
|
||||||
"service.overview.reset-form.reset-confirm":"Discard",
|
"service.overview.reset-form.reset-confirm": "Discard",
|
||||||
"admin.registries.services-formats.modify.success.head": "Successful Edit",
|
"admin.registries.services-formats.modify.success.head": "Successful Edit",
|
||||||
"admin.registries.services-formats.modify.success.content": "The service has been edited",
|
"admin.registries.services-formats.modify.success.content": "The service has been edited",
|
||||||
|
"admin.registries.services-formats.modify.failure.head": "Failed Edit",
|
||||||
|
"admin.registries.services-formats.modify.failure.content": "The service has not been edited",
|
||||||
"ldn-service-notification.created.success.title": "Successful Create",
|
"ldn-service-notification.created.success.title": "Successful Create",
|
||||||
"ldn-service-notification.created.success.body": "The service has been created",
|
"ldn-service-notification.created.success.body": "The service has been created",
|
||||||
|
"ldn-service-notification.created.failure.title": "Failed Create",
|
||||||
|
"ldn-service-notification.created.failure.body": "The service has not been created",
|
||||||
"ldn-enable-service.notification.success.title": "Successful status updated",
|
"ldn-enable-service.notification.success.title": "Successful status updated",
|
||||||
"ldn-enable-service.notification.success.content": "The service status has been updated",
|
"ldn-enable-service.notification.success.content": "The service status has been updated",
|
||||||
"ldn-service-delete.notification.success.title": "Successful Deletion",
|
"ldn-service-delete.notification.success.title": "Successful Deletion",
|
||||||
@@ -1978,10 +2043,12 @@
|
|||||||
|
|
||||||
"info.feedback.breadcrumbs": "Feedback",
|
"info.feedback.breadcrumbs": "Feedback",
|
||||||
|
|
||||||
"info.coar-notify-support.title":"Notify Support",
|
"info.coar-notify-support.title": "Notify Support",
|
||||||
|
|
||||||
"info.coar-notify.breadcrumbs": "Notify Support",
|
"info.coar-notify.breadcrumbs": "Notify Support",
|
||||||
|
|
||||||
|
"submission.sections.notify.info": "The selected service is compatible with the item according to its current status. {{ service.name }}: {{ service.description }}",
|
||||||
|
|
||||||
"info.feedback.head": "Feedback",
|
"info.feedback.head": "Feedback",
|
||||||
|
|
||||||
"info.feedback.title": "Feedback",
|
"info.feedback.title": "Feedback",
|
||||||
@@ -2472,6 +2539,14 @@
|
|||||||
|
|
||||||
"item.truncatable-part.show-less": "Collapse",
|
"item.truncatable-part.show-less": "Collapse",
|
||||||
|
|
||||||
|
"item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
|
||||||
|
"item.qa-event-notification-info.check.button": "Check",
|
||||||
|
|
||||||
|
"mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
|
||||||
|
"mydspace.qa-event-notification-info.check.button": "Check",
|
||||||
|
|
||||||
"workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
"workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
||||||
|
|
||||||
"workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order",
|
"workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order",
|
||||||
@@ -2494,6 +2569,12 @@
|
|||||||
|
|
||||||
"item.page.citation": "Citation",
|
"item.page.citation": "Citation",
|
||||||
|
|
||||||
|
"item.page.endorsed-by": "Endorsement",
|
||||||
|
|
||||||
|
"item.page.is-reviewed-by": "Review",
|
||||||
|
|
||||||
|
"item.page.is-supplemented-by": "Dataset",
|
||||||
|
|
||||||
"item.page.collections": "Collections",
|
"item.page.collections": "Collections",
|
||||||
|
|
||||||
"item.page.collections.loading": "Loading...",
|
"item.page.collections.loading": "Loading...",
|
||||||
@@ -3210,6 +3291,8 @@
|
|||||||
|
|
||||||
"quality-assurance.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.",
|
"quality-assurance.topics.description": "Below you can see all the topics received from the subscriptions to {{source}}.",
|
||||||
|
|
||||||
|
"quality-assurance.topics.description-with-target": "Below you can see all the topics received from the subscriptions to {{source}} in regards to the",
|
||||||
|
|
||||||
"quality-assurance.source.description": "Below you can see all the notification's sources.",
|
"quality-assurance.source.description": "Below you can see all the notification's sources.",
|
||||||
|
|
||||||
"quality-assurance.topics": "Current Topics",
|
"quality-assurance.topics": "Current Topics",
|
||||||
@@ -3236,7 +3319,9 @@
|
|||||||
|
|
||||||
"quality-assurance.source.error.service.retrieve": "An error occurred while loading the Quality Assurance source",
|
"quality-assurance.source.error.service.retrieve": "An error occurred while loading the Quality Assurance source",
|
||||||
|
|
||||||
"quality-assurance.events.description": "Below the list of all the suggestions for the selected topic.",
|
"quality-assurance.events.description": "Below the list of all the suggestions for the selected topic <b>{{topic}}</b>, related to <b>{{source}}</b>.",
|
||||||
|
|
||||||
|
"quality-assurance.events.description-with-topic-and-target": "Below the list of all the suggestions for the selected topic <b>{{topic}}</b>, related to <b>{{source}}</b> and ",
|
||||||
|
|
||||||
"quality-assurance.loading": "Loading ...",
|
"quality-assurance.loading": "Loading ...",
|
||||||
|
|
||||||
@@ -3290,6 +3375,10 @@
|
|||||||
|
|
||||||
"quality-assurance.event.table.more": "Show more",
|
"quality-assurance.event.table.more": "Show more",
|
||||||
|
|
||||||
|
"quality-assurance.event.table.event.message.serviceName": "Service Name:",
|
||||||
|
|
||||||
|
"quality-assurance.event.table.event.message.link": "Link:",
|
||||||
|
|
||||||
"quality-assurance.event.project.found": "Bound to the local record:",
|
"quality-assurance.event.project.found": "Bound to the local record:",
|
||||||
|
|
||||||
"quality-assurance.event.project.notFound": "No local record found",
|
"quality-assurance.event.project.notFound": "No local record found",
|
||||||
@@ -4760,6 +4849,8 @@
|
|||||||
|
|
||||||
"submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information",
|
"submission.sections.submit.progressbar.sherpaPolicies": "Publisher open access policy information",
|
||||||
|
|
||||||
|
"submission.sections.submit.progressbar.coarnotify": "COAR Notify",
|
||||||
|
|
||||||
"submission.sections.sherpa-policy.title-empty": "No publisher policy information available. If your work has an associated ISSN, please enter it above to see any related publisher open access policies.",
|
"submission.sections.sherpa-policy.title-empty": "No publisher policy information available. If your work has an associated ISSN, please enter it above to see any related publisher open access policies.",
|
||||||
|
|
||||||
"submission.sections.status.errors.title": "Errors",
|
"submission.sections.status.errors.title": "Errors",
|
||||||
@@ -5006,6 +5097,28 @@
|
|||||||
|
|
||||||
"submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
|
"submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.control.request-review.label": "You can request a review to one of the following services",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.control.request-endorsement.label": "You can request an Endorsement to one of the following overlay journals",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.control.request-ingest.label": "You can request to ingest a copy of your submission to one of the following services",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.dropdown.no-data": "No data available",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.dropdown.select-none": "Select none",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.small.notification": "Select a service for {{ pattern }} of this item",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.selection.description": "Selected service's description:",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.selection.no-description": "No further information is available",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.notification.error": "The selected service is not suitable for the current item. Please check the description for details about which record can be managed by this service.",
|
||||||
|
|
||||||
|
"submission.section.section-coar-notify.info.no-pattern": "No patterns found in the submission.",
|
||||||
|
|
||||||
|
"error.validation.coarnotify.invalidfilter": "Invalid filter, try to select another service or none.",
|
||||||
|
|
||||||
"submitter.empty": "N/A",
|
"submitter.empty": "N/A",
|
||||||
|
|
||||||
"subscriptions.title": "Subscriptions",
|
"subscriptions.title": "Subscriptions",
|
||||||
|
@@ -3723,6 +3723,22 @@
|
|||||||
// "item.truncatable-part.show-less": "Collapse",
|
// "item.truncatable-part.show-less": "Collapse",
|
||||||
"item.truncatable-part.show-less": "Riduci",
|
"item.truncatable-part.show-less": "Riduci",
|
||||||
|
|
||||||
|
// "item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
// TODO New key - Add a translation
|
||||||
|
"item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
|
||||||
|
// "item.qa-event-notification-info.check.button": "Check",
|
||||||
|
// TODO New key - Add a translation
|
||||||
|
"item.qa-event-notification-info.check.button": "Check",
|
||||||
|
|
||||||
|
// "mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
// TODO New key - Add a translation
|
||||||
|
"mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check",
|
||||||
|
|
||||||
|
// "mydspace.qa-event-notification-info.check.button": "Check",
|
||||||
|
// TODO New key - Add a translation
|
||||||
|
"mydspace.qa-event-notification-info.check.button": "Check",
|
||||||
|
|
||||||
// "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
// "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
||||||
// TODO New key - Add a translation
|
// TODO New key - Add a translation
|
||||||
"workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
"workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order",
|
||||||
@@ -7461,6 +7477,25 @@
|
|||||||
// "submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
|
// "submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
|
||||||
"submission.workspace.generic.view-help": "Seleziona questa opzione per vedere i metadata dell'item.",
|
"submission.workspace.generic.view-help": "Seleziona questa opzione per vedere i metadata dell'item.",
|
||||||
|
|
||||||
|
// "submission.section.section-coar-notify.dropdown.no-data": "No data available",
|
||||||
|
// TODO New key - a translation
|
||||||
|
"submission.section.section-coar-notify.dropdown.no-data": "No data available",
|
||||||
|
|
||||||
|
// "submission.section.section-coar-notify.dropdown.select-none": "Select none",
|
||||||
|
// TODO New key - a translation
|
||||||
|
"submission.section.section-coar-notify.dropdown.select-none": "Select none",
|
||||||
|
|
||||||
|
// "submission.section.section-coar-notify.small.notification": "Select a service for {{ pattern }} of this item",
|
||||||
|
// TODO New key - a translation
|
||||||
|
"submission.section.section-coar-notify.small.notification": "Select a service for {{ pattern }} of this item",
|
||||||
|
|
||||||
|
// "submission.section.section-coar-notify.selection.description": "Selected service's description:",
|
||||||
|
// TODO New key - a translation
|
||||||
|
"submission.section.section-coar-notify.selection.description": "Selected service's description:",
|
||||||
|
|
||||||
|
// "submission.section.section-coar-notify.notification.error": "The selected service is not suitable for the current item.Please check the description for details about which record can be managed by this service.",
|
||||||
|
// TODO New key - a translation
|
||||||
|
"submission.section.section-coar-notify.notification.error": "The selected service is not suitable for the current item.Please check the description for details about which record can be managed by this service.",
|
||||||
|
|
||||||
// "subscriptions.title": "Subscriptions",
|
// "subscriptions.title": "Subscriptions",
|
||||||
"subscriptions.title": "Sottoscrizioni",
|
"subscriptions.title": "Sottoscrizioni",
|
||||||
|
BIN
src/assets/images/qa-coar-notify-logo.png
Normal file
BIN
src/assets/images/qa-coar-notify-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user