mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[CST-11045] Save & update coar-notify-data (submission form)
This commit is contained in:
@@ -26,11 +26,13 @@ import { LdnService } from '../ldn-services-model/ldn-services.model';
|
||||
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 '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 { LdnServiceConstrain } from '../ldn-services-model/ldn-service.constrain.model';
|
||||
import { getFirstCompletedRemoteData } from 'src/app/core/shared/operators';
|
||||
import { hasValue } from 'src/app/shared/empty.util';
|
||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
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
|
||||
@@ -43,6 +45,9 @@ export class LdnServicesService extends IdentifiableDataService<LdnService> impl
|
||||
private deleteData: DeleteDataImpl<LdnService>;
|
||||
private patchData: PatchDataImpl<LdnService>;
|
||||
private comparator: ChangeAnalyzer<LdnService>;
|
||||
private searchData: SearchDataImpl<LdnService>;
|
||||
|
||||
private findByPatternEndpoint = 'byInboundPattern';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
@@ -54,6 +59,7 @@ export class LdnServicesService extends IdentifiableDataService<LdnService> impl
|
||||
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);
|
||||
@@ -84,9 +90,11 @@ export class LdnServicesService extends IdentifiableDataService<LdnService> impl
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/*findByPattern(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<LdnService>[]): Observable<RemoteData<PaginatedList<LdnService>>> {
|
||||
return this.findAllData.find
|
||||
}*/
|
||||
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 delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
|
@@ -1,117 +0,0 @@
|
||||
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 { COAR_NOTIFY_WORKSPACEITEM } from './section-coar-notify-service.resource-type';
|
||||
import { LdnService } from '../../../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
||||
import { SubmissionCoarNotifyConfig } from './submission-coar-notify.config';
|
||||
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the ldnservices endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(COAR_NOTIFY_WORKSPACEITEM)
|
||||
export class SectionCoarNotifyWorkspaceitemsDataService extends IdentifiableDataService<SubmissionCoarNotifyConfig> implements FindAllData<SubmissionCoarNotifyConfig>, DeleteData<LdnService>, PatchData<LdnService>, CreateData<LdnService> {
|
||||
createData: CreateDataImpl<LdnService>;
|
||||
private findAllData: FindAllDataImpl<LdnService>;
|
||||
private deleteData: DeleteDataImpl<LdnService>;
|
||||
private patchData: PatchDataImpl<LdnService>;
|
||||
private comparator: ChangeAnalyzer<LdnService>;
|
||||
|
||||
constructor(
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
commitUpdates(method?: RestRequestMethod): void {
|
||||
return this.patchData.commitUpdates(method);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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, 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));
|
||||
|
||||
return this.rdbService.buildFromRequestUUID<LdnService>(requestId);
|
||||
}
|
||||
|
||||
public ldnServiceWithNameExistsAndCanExecute(scriptName: string): Observable<boolean> {
|
||||
return this.findById(scriptName).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
map((rd: RemoteData<LdnService>) => {
|
||||
return hasValue(rd.payload);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
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,56 +1,125 @@
|
||||
<div>
|
||||
<ng-container>
|
||||
<div *ngFor="let pattern of patterns; let i = index" class="col mt-3">
|
||||
<label class="mt-2 row">Request {{ pattern }} at the following services</label>
|
||||
<div *ngFor="let service of selectedServicesByPattern[pattern]; let serviceIndex = index">
|
||||
<label class="mt-2 row"
|
||||
>
|
||||
{{'submission.section.section-coar-notify.control.label' | translate : {pattern : pattern} }}
|
||||
</label
|
||||
>
|
||||
<div
|
||||
*ngFor="
|
||||
let service of ldnServiceByPattern[pattern];
|
||||
let serviceIndex = index
|
||||
"
|
||||
>
|
||||
<div class="row">
|
||||
<select [(ngModel)]="selectedServicesByPattern[pattern][serviceIndex]" [compareWith]="compareById" class="form-control col">
|
||||
<option [ngValue]="null" selected>Select a service</option>
|
||||
<option *ngFor="let serviceOption of (filterServices(pattern) | async)" [ngValue]="serviceOption">
|
||||
<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
|
||||
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 }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="col-sm-1">
|
||||
<button (click)="removeService(pattern, serviceIndex)" class="btn btn-outline-dark trash-button">
|
||||
<i class="fas fa-trash"></i>
|
||||
</b>
|
||||
<br />
|
||||
{{ serviceOption.description }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<small class="row" *ngIf="!selectedServicesByPattern[pattern][serviceIndex]">
|
||||
Select a service for {{ pattern }} of this item
|
||||
</div>
|
||||
<!-- TODO: NEXT version
|
||||
<div
|
||||
class="col-sm-1"
|
||||
>
|
||||
<button
|
||||
(click)="removeService(pattern, serviceIndex)"
|
||||
class="btn btn-outline-dark trash-button"
|
||||
>
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div> -->
|
||||
</div>
|
||||
<small
|
||||
class="row text-muted"
|
||||
*ngIf="!ldnServiceByPattern[pattern][serviceIndex]"
|
||||
>
|
||||
{{'submission.section.section-coar-notify.small.notification' | translate : {pattern : pattern} }}
|
||||
</small>
|
||||
<div class="row mt-1">
|
||||
<div *ngIf="selectedServicesByPattern[pattern][serviceIndex]" class="alert alert-success col">
|
||||
<div class="row ml-2 mt-2 mb-1">
|
||||
<img alt="Coar-Notify-Pattern" class="coar-img-submission "
|
||||
src="../../../../assets/images/notify_logo.png">
|
||||
<i class="fa-solid fa-circle-check icon-check ml-2"></i>
|
||||
<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="mt-1 ml-4">
|
||||
The selected service is compatible with the item according to its current status.
|
||||
<b>{{ 'submission.section.section-coar-notify.selection.description' | translate }}</b>
|
||||
<br />
|
||||
{{ ldnServiceByPattern[pattern][serviceIndex].description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ml-2 mt-2 mb-1">
|
||||
<img alt="Coar-Notify-Pattern" class="coar-img-submission invisible"
|
||||
src="../../../../assets/images/notify_logo.png">
|
||||
<i class="fa-solid fa-circle-check icon-check ml-2 invisible"></i>
|
||||
</div>
|
||||
<div class="row mt-1" *ngIf="sectionData.errorsToShow.length > 0">
|
||||
<!--TODO: get error message and display here -->
|
||||
<div
|
||||
class="alert alert-danger w-100 d-flex align-items-center flex-row"
|
||||
>
|
||||
<div class="mt-1 ml-4">
|
||||
{{ selectedServicesByPattern[pattern][serviceIndex].name }}:
|
||||
{{ selectedServicesByPattern[pattern][serviceIndex].description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1 invisible">
|
||||
<button class="btn btn-outline-dark trash-button">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-1">
|
||||
<span (click)="addService(pattern, newService)" class="add-pattern-link mb-2">
|
||||
{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
||||
<span>
|
||||
{{ 'submission.section.section-coar-notify.notification.error' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO: NEXT version
|
||||
<div class="row mt-1">
|
||||
<span (click)="addService(pattern, newService)" class="ds-form-add-more btn btn-link mb-2">
|
||||
{{ 'ldn-new-service.form.label.addPattern' | translate }}
|
||||
</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
@@ -1,22 +1,3 @@
|
||||
.add-pattern-link {
|
||||
color: #0048ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
@import '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.scss';
|
||||
@import '../../../shared/form/form.component.scss';
|
||||
|
||||
.ds-alert-coar {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.coar-img-submission {
|
||||
max-height: var(--ds-header-logo-height);
|
||||
}
|
||||
|
||||
.icon-check {
|
||||
color: rgba(6, 68, 6, 0.42);
|
||||
font-size: var(--ds-header-logo-height);
|
||||
}
|
||||
|
||||
|
||||
.ds-alert-box {
|
||||
|
||||
}
|
||||
|
@@ -1,36 +1,22 @@
|
||||
import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core';
|
||||
import { DynamicFormControlEvent, DynamicFormControlModel, DynamicFormLayout } from '@ng-dynamic-forms/core';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
|
||||
import { Observable, Subscription, of } 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 { FormComponent } from '../../../shared/form/form.component';
|
||||
import { CollectionDataService } from '../../../core/data/collection-data.service';
|
||||
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
|
||||
import { SectionFormOperationsService } from '../form/section-form-operations.service';
|
||||
import { FormService } from '../../../shared/form/form.service';
|
||||
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||
import { SectionsService } from '../sections.service';
|
||||
import { SubmissionService } from '../../submission.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SectionDataObject } from '../models/section-data.model';
|
||||
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { hasNoValue, hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
|
||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||
import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../../core/shared/operators';
|
||||
import { LdnServicesService } from '../../../admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
|
||||
import { isLoading } from '../../../core/data/request-entry-state.model';
|
||||
import { LdnService } from '../../../admin/admin-ldn-services/ldn-services-model/ldn-services.model';
|
||||
import { SECTION_COAR_FORM_LAYOUT, SECTION_COAR_FORM_MODEL } from './section-coar-notify-model';
|
||||
import { CoarNotifyConfigDataService } from './coar-notify-config-data.service';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
||||
import { SubmissionCoarNotifyConfig } from './submission-coar-notify.config';
|
||||
import { FormFieldPreviousValueObject } from '../../../shared/form/builder/models/form-field-previous-value-object';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { AlertType } from '../../../shared/alert/aletr-type';
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import { filter, map, tap } from 'rxjs/operators';
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
export interface CoarNotifyDropdownSelector {
|
||||
ldnService: LdnService;
|
||||
@@ -42,56 +28,29 @@ export interface CoarNotifyDropdownSelector {
|
||||
@Component({
|
||||
selector: 'ds-submission-section-coar-notify',
|
||||
templateUrl: './section-coar-notify.component.html',
|
||||
styleUrls: ['./section-coar-notify.component.scss']
|
||||
styleUrls: ['./section-coar-notify.component.scss'],
|
||||
providers: [NgbDropdown]
|
||||
})
|
||||
@renderSectionFor(SectionsType.CoarNotify)
|
||||
|
||||
export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent {
|
||||
|
||||
requestReview: LdnService;
|
||||
requestEndorsement: LdnService;
|
||||
requestIngest: LdnService;
|
||||
|
||||
coarNotifyConfigRD$: Observable<RemoteData<PaginatedList<SubmissionCoarNotifyConfig>>>;
|
||||
|
||||
ldnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>>;
|
||||
newService: LdnService = new LdnService();
|
||||
|
||||
|
||||
patterns: string[] = [];
|
||||
selectedServicesByPattern: { [key: string]: LdnService[] } = {};
|
||||
patternServices: { [key: string]: LdnService } = {};
|
||||
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} } = {};
|
||||
|
||||
patternsLoaded = false;
|
||||
patternObservables: Observable<RemoteData<PaginatedList<LdnService>>[]>;
|
||||
private _ldnServicesPerPattern: Map<string, LdnService[]> = new Map();
|
||||
|
||||
|
||||
|
||||
public AlertTypeEnum = AlertType;
|
||||
/**
|
||||
* The form model
|
||||
* @type {DynamicFormControlModel[]}
|
||||
*/
|
||||
public formModel: DynamicFormControlModel[];
|
||||
/**
|
||||
* The form id
|
||||
* @type {string}
|
||||
*/
|
||||
public formId: string;
|
||||
/**
|
||||
* The [[DynamicFormLayout]] object
|
||||
* @type {DynamicFormLayout}
|
||||
*/
|
||||
public formLayout: DynamicFormLayout = SECTION_COAR_FORM_LAYOUT;
|
||||
/**
|
||||
* A FormGroup that combines all inputs
|
||||
*/
|
||||
formGroup: UntypedFormGroup;
|
||||
/**
|
||||
* A boolean representing if div should start collapsed
|
||||
*/
|
||||
public isCollapsed = false;
|
||||
protected readonly AlertType = AlertType;
|
||||
/**
|
||||
* The [[JsonPatchOperationPathCombiner]] object
|
||||
* @type {JsonPatchOperationPathCombiner}
|
||||
@@ -102,51 +61,18 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
* @type {Map}
|
||||
*/
|
||||
protected fieldsOnTheirWayToBeRemoved: Map<string, number[]> = new Map();
|
||||
/**
|
||||
* The [FormFieldPreviousValueObject] object
|
||||
* @type {FormFieldPreviousValueObject}
|
||||
*/
|
||||
protected previousValue: FormFieldPreviousValueObject = new FormFieldPreviousValueObject();
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
*/
|
||||
protected subs: Subscription[] = [];
|
||||
protected readonly isLoading = isLoading;
|
||||
/**
|
||||
* The FormComponent reference
|
||||
*/
|
||||
@ViewChild('formRef') private formRef: FormComponent;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
* @param {ChangeDetectorRef} changeDetectorRef
|
||||
* @param ldnServicesService
|
||||
* @param {CollectionDataService} collectionDataService
|
||||
* @param {FormBuilderService} formBuilderService
|
||||
* @param {SectionFormOperationsService} formOperationsService
|
||||
* @param {FormService} formService
|
||||
* @param {JsonPatchOperationsBuilder} operationsBuilder
|
||||
* @param {SectionsService} sectionService
|
||||
* @param {SubmissionService} submissionService
|
||||
* @param {TranslateService} translateService
|
||||
* @param {CoarNotifyConfigDataService} coarNotifyConfigDataService
|
||||
* @param {string} injectedCollectionId
|
||||
* @param {SectionDataObject} injectedSectionData
|
||||
* @param {string} injectedSubmissionId
|
||||
*/
|
||||
constructor(protected changeDetectorRef: ChangeDetectorRef,
|
||||
protected ldnServicesService: LdnServicesService,
|
||||
protected collectionDataService: CollectionDataService,
|
||||
protected formBuilderService: FormBuilderService,
|
||||
constructor(protected ldnServicesService: LdnServicesService,
|
||||
protected formOperationsService: SectionFormOperationsService,
|
||||
protected formService: FormService,
|
||||
protected operationsBuilder: JsonPatchOperationsBuilder,
|
||||
protected sectionService: SectionsService,
|
||||
protected submissionService: SubmissionService,
|
||||
protected translateService: TranslateService,
|
||||
protected coarNotifyConfigDataService: CoarNotifyConfigDataService,
|
||||
protected chd: ChangeDetectorRef,
|
||||
@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||
@Inject('submissionIdProvider') public injectedSubmissionId: string) {
|
||||
@@ -157,12 +83,8 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
* Initialize all instance variables
|
||||
*/
|
||||
onSectionInit() {
|
||||
this.formModel = this.formBuilderService.fromJSON(SECTION_COAR_FORM_MODEL);
|
||||
this.setCoarNotifyConfig();
|
||||
this.fetchLdnServices();
|
||||
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,94 +92,107 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
* Retriev available NotifyConfigs
|
||||
*/
|
||||
setCoarNotifyConfig() {
|
||||
this.coarNotifyConfigRD$ = this.coarNotifyConfigDataService.findAll().pipe(
|
||||
this.subs.push(
|
||||
this.coarNotifyConfigDataService.findAll().pipe(
|
||||
getFirstCompletedRemoteData()
|
||||
);
|
||||
|
||||
this.coarNotifyConfigRD$.subscribe((data) => {
|
||||
).subscribe((data) => {
|
||||
if (data.hasSucceeded) {
|
||||
this.patterns = data.payload.page[0].patterns;
|
||||
this.patternsLoaded = true;
|
||||
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) => {
|
||||
this._ldnServicesPerPattern.set(pattern, services);
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
compareById(service1, service2){
|
||||
return service1 && service2 && service1.id === service2.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the customEvent (ex. drag-drop move event).
|
||||
* The customEvent is stored inside event.$event
|
||||
* @param event
|
||||
*/
|
||||
onCustomEvent(event: DynamicFormControlEvent) {
|
||||
this.formOperationsService.dispatchOperationsFromEvent(
|
||||
this.pathCombiner,
|
||||
event,
|
||||
this.previousValue,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when a form dfChange event is fired.
|
||||
* Dispatch form operations based on changes.
|
||||
*/
|
||||
onChange(event: DynamicFormControlEvent) {
|
||||
const path = this.formOperationsService.getFieldPathSegmentedFromChangeEvent(event);
|
||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||
if (value) {
|
||||
this.operationsBuilder.add(this.pathCombiner.getPath(path), value.value.toString(), false, true);
|
||||
this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionData.id);
|
||||
} else {
|
||||
this.operationsBuilder.remove(this.pathCombiner.getPath(path));
|
||||
}
|
||||
}
|
||||
|
||||
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.selectedServicesByPattern[pattern]) {
|
||||
this.selectedServicesByPattern[pattern] = [];
|
||||
if (!this.ldnServiceByPattern[pattern]) {
|
||||
this.ldnServiceByPattern[pattern] = [];
|
||||
}
|
||||
this.selectedServicesByPattern[pattern].push(newService);
|
||||
this.ldnServiceByPattern[pattern].push(newService);
|
||||
}
|
||||
|
||||
removeService(pattern: string, serviceIndex: number) {
|
||||
if (this.selectedServicesByPattern[pattern]) {
|
||||
if (this.ldnServiceByPattern[pattern]) {
|
||||
// Remove the service at the specified index from the array
|
||||
this.selectedServicesByPattern[pattern].splice(serviceIndex, 1);
|
||||
this.ldnServiceByPattern[pattern].splice(serviceIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when a form remove event is fired.
|
||||
* Dispatch form operations based on changes.
|
||||
*
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] emitted
|
||||
*/
|
||||
onRemove(event: DynamicFormControlEvent): void {
|
||||
const fieldId = this.formBuilderService.getId(event.model);
|
||||
const fieldIndex = this.formOperationsService.getArrayIndexFromEvent(event);
|
||||
|
||||
// Keep track that this field will be removed
|
||||
if (this.fieldsOnTheirWayToBeRemoved.has(fieldId)) {
|
||||
const indexes = this.fieldsOnTheirWayToBeRemoved.get(fieldId);
|
||||
indexes.push(fieldIndex);
|
||||
this.fieldsOnTheirWayToBeRemoved.set(fieldId, indexes);
|
||||
} else {
|
||||
this.fieldsOnTheirWayToBeRemoved.set(fieldId, [fieldIndex]);
|
||||
}
|
||||
|
||||
this.formOperationsService.dispatchOperationsFromEvent(
|
||||
this.pathCombiner,
|
||||
event,
|
||||
this.previousValue,
|
||||
this.hasStoredValue(fieldId, fieldIndex));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified form field has already a value stored
|
||||
*
|
||||
@@ -288,27 +223,6 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
return this.fieldsOnTheirWayToBeRemoved.has(fieldId) && this.fieldsOnTheirWayToBeRemoved.get(fieldId).includes(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when a form dfFocus event is fired.
|
||||
* Initialize [FormFieldPreviousValueObject] instance.
|
||||
*
|
||||
* @param event
|
||||
* the [[DynamicFormControlEvent]] emitted
|
||||
*/
|
||||
onFocus(event: DynamicFormControlEvent): void {
|
||||
const value = this.formOperationsService.getFieldValueFromChangeEvent(event);
|
||||
const path = this.formBuilderService.getPath(event.model);
|
||||
if (this.formBuilderService.hasMappedGroupValue(event.model)) {
|
||||
this.previousValue.path = path;
|
||||
this.previousValue.value = this.formOperationsService.getQualdropValueMap(event);
|
||||
} else if (isNotEmpty(value) && ((typeof value === 'object' && isNotEmpty(value.value)) || (typeof value === 'string'))) {
|
||||
this.previousValue.path = path;
|
||||
this.previousValue.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Unsubscribe from all subscriptions
|
||||
*/
|
||||
@@ -318,33 +232,26 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
.forEach((subscription) => subscription.unsubscribe());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when section is initialized
|
||||
* Retriev available LdnServices
|
||||
*/
|
||||
fetchLdnServices() {
|
||||
if (!this.ldnServicesRD$) {
|
||||
this.ldnServicesRD$ = this.ldnServicesService.findAll().pipe(
|
||||
getFirstCompletedRemoteData()
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Method called when dropdowns for the section are initialized
|
||||
* Retrieve services with corresponding patterns to the dropdowns.
|
||||
*/
|
||||
filterServices(pattern: string) {
|
||||
return this.ldnServicesRD$.pipe(
|
||||
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),
|
||||
map((rd) => rd.payload.page.filter((service) =>
|
||||
getRemoteDataPayload(),
|
||||
getPaginatedListPayload(),
|
||||
map((res: LdnService[]) => res.filter((service) =>
|
||||
this.hasInboundPattern(service, pattern)))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
hasInboundPattern(service: any, patternType: string): boolean {
|
||||
return service.notifyServiceInboundPatterns.some((pattern: { pattern: string }) => {
|
||||
return pattern.pattern === patternType;
|
||||
@@ -352,7 +259,8 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent
|
||||
}
|
||||
|
||||
protected getSectionStatus(): Observable<boolean> {
|
||||
return undefined;
|
||||
// TODO: check if section is valid
|
||||
return of(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ import { autoserialize, deserialize, deserializeAs, inheritSerialization } from
|
||||
|
||||
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";
|
||||
import { COAR_NOTIFY_WORKSPACEITEM } from './section-coar-notify-service.resource-type';
|
||||
|
||||
|
||||
/** An CoarNotify and its properties. */
|
||||
|
@@ -298,7 +298,6 @@ export class SubmissionService {
|
||||
sectionObject.id = sectionId;
|
||||
sectionObject.sectionType = sections[sectionId].sectionType;
|
||||
availableSections.push(sectionObject);
|
||||
console.log(sectionObject);
|
||||
});
|
||||
return availableSections;
|
||||
}),
|
||||
|
@@ -5010,6 +5010,18 @@
|
||||
|
||||
"submission.workspace.generic.view-help": "Select this option to view the item's metadata.",
|
||||
|
||||
"submission.section.section-coar-notify.control.label": "Request {{ pattern }} at 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.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.",
|
||||
|
||||
"submitter.empty": "N/A",
|
||||
|
||||
"subscriptions.title": "Subscriptions",
|
||||
|
@@ -7461,6 +7461,29 @@
|
||||
// "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.section.section-coar-notify.control.label": "Request {{ pattern }} at the following services",
|
||||
// TODO New key - a translation
|
||||
"submission.section.section-coar-notify.control.label": "Request {{ pattern }} at the following services",
|
||||
|
||||
// "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": "Sottoscrizioni",
|
||||
|
Reference in New Issue
Block a user