From 128dd2f5663b2e9bb67e41d7a53815ab5712c0bf Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 21 Dec 2023 14:46:11 +0100 Subject: [PATCH 1/2] add mutliple request config --- .../ldn-services-model/ldn-services.model.ts | 5 + .../json-patch-operations.actions.ts | 30 ++- .../section-coar-notify.component.html | 212 ++++++++++-------- .../section-coar-notify.component.scss | 1 + .../section-coar-notify.component.ts | 106 +++++---- .../submission-coar-notify.config.ts | 7 +- 6 files changed, 224 insertions(+), 137 deletions(-) diff --git a/src/app/admin/admin-ldn-services/ldn-services-model/ldn-services.model.ts b/src/app/admin/admin-ldn-services/ldn-services-model/ldn-services.model.ts index f3e421c9a2..f81fcbcee4 100644 --- a/src/app/admin/admin-ldn-services/ldn-services-model/ldn-services.model.ts +++ b/src/app/admin/admin-ldn-services/ldn-services-model/ldn-services.model.ts @@ -7,6 +7,11 @@ import {typedObject} from '../../../core/cache/builders/build-decorators'; import {NotifyServicePattern} from './ldn-service-patterns.model'; +export interface LdnServiceByPattern { + allowsMultipleRequests: boolean; + services: LdnService[]; +} + /** An LdnService and its properties. */ @typedObject @inheritSerialization(CacheableObject) diff --git a/src/app/core/json-patch/json-patch-operations.actions.ts b/src/app/core/json-patch/json-patch-operations.actions.ts index 6fea7a58fb..81cce174ec 100644 --- a/src/app/core/json-patch/json-patch-operations.actions.ts +++ b/src/app/core/json-patch/json-patch-operations.actions.ts @@ -20,6 +20,7 @@ export const JsonPatchOperationsActionTypes = { COMMIT_JSON_PATCH_OPERATIONS: type('dspace/core/patch/COMMIT_JSON_PATCH_OPERATIONS'), ROLLBACK_JSON_PATCH_OPERATIONS: type('dspace/core/patch/ROLLBACK_JSON_PATCH_OPERATIONS'), FLUSH_JSON_PATCH_OPERATIONS: type('dspace/core/patch/FLUSH_JSON_PATCH_OPERATIONS'), + FLUSH_JSON_PATCH_OPERATION: type('dspace/core/patch/FLUSH_JSON_PATCH_OPERATION'), START_TRANSACTION_JSON_PATCH_OPERATIONS: type('dspace/core/patch/START_TRANSACTION_JSON_PATCH_OPERATIONS'), DELETE_PENDING_JSON_PATCH_OPERATIONS: type('dspace/core/patch/DELETE_PENDING_JSON_PATCH_OPERATIONS'), }; @@ -120,6 +121,32 @@ export class FlushPatchOperationsAction implements Action { } } + +/** + * An ngrx action to flush a single operation of the JSON Patch operations + */ +export class FlushPatchOperationAction implements Action { + type = JsonPatchOperationsActionTypes.FLUSH_JSON_PATCH_OPERATION; + payload: { + resourceType: string; + resourceId: string; + path: string + }; + + /** + * Create a new FlushPatchOperationsAction + * + * @param resourceType + * the resource's type + * @param resourceId + * the resource's ID + * @param path + * the path of the operation + */ + constructor(resourceType: string, resourceId: string, path: string) { + this.payload = { resourceType, resourceId, path }; + } +} /** * An ngrx action to Add new HTTP/PATCH ADD operations to state */ @@ -284,4 +311,5 @@ export type PatchOperationsActions | NewPatchReplaceOperationAction | RollbacktPatchOperationsAction | StartTransactionPatchOperationsAction - | DeletePendingJsonPatchOperationsAction; + | DeletePendingJsonPatchOperationsAction + | FlushPatchOperationAction; diff --git a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html index e3bdffd065..7356b06b4f 100644 --- a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html +++ b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html @@ -1,115 +1,135 @@
-
+
-
-
-
-
- - -
- -
-
- - {{'submission.section.section-coar-notify.small.notification' | translate : {pattern : pattern} }} - - - - {{ error.message | translate}} - - +
-
- -
-
{{ 'submission.section.section-coar-notify.selection.description' | translate }}
-
- {{ ldnServiceByPattern[pattern][serviceIndex].description }} +
+
+
+ +
- + +
+ +
+ + + {{'submission.section.section-coar-notify.small.notification' | translate : {pattern : ldnPattern.pattern} }} + + + + {{ error.message | translate}} + + +
+
+ +
+
{{ 'submission.section.section-coar-notify.selection.description' | translate }}
+
+ {{ ldnServiceByPattern[ldnPattern.pattern].services[serviceIndex].description }} +
+ {{ 'submission.section.section-coar-notify.selection.no-description' | translate }} - + +
-
-
-
-
+
+
+
{{ 'submission.section.section-coar-notify.notification.error' | translate }} +
+
+
+
+
@@ -118,7 +138,7 @@

- {{'submission.section.section-coar-notify.info.no-pattern' | translate }} + {{ 'submission.section.section-coar-notify.info.no-pattern' | translate }}

diff --git a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.scss b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.scss index 3ac8827f74..4a3e7072a3 100644 --- a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.scss +++ b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.scss @@ -2,3 +2,4 @@ @import '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.scss'; @import '../../../shared/form/form.component.scss'; + diff --git a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.ts b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.ts index 92f56b4f83..a8a3ce7fc5 100644 --- a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.ts +++ b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.ts @@ -12,11 +12,15 @@ import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../../shared/empty 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 { + LdnService, + LdnServiceByPattern +} 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'; +import { LdnPattern } from "./submission-coar-notify.config"; /** * This component represents a section that contains the submission section-coar-notify form. @@ -33,12 +37,12 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent /** * Contains an array of string patterns. */ - patterns: string[] = []; + patterns: LdnPattern[] = []; /** * An object that maps string keys to arrays of LdnService objects. * Used to store LdnService objects by pattern. */ - ldnServiceByPattern: { [key: string]: LdnService[] } = {}; + ldnServiceByPattern: { [key: string]: LdnServiceByPattern } = {}; /** * A map representing all services for each pattern * { @@ -50,7 +54,7 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent * @type {{ [key: string]: {[key: number]: number} }} * @memberof SubmissionSectionCoarNotifyComponent */ - previousServices: { [key: string]: {[key: number]: number} } = {}; + previousServices: { [key: string]: LdnServiceByPattern } = {}; /** * The [[JsonPatchOperationPathCombiner]] object @@ -99,7 +103,17 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent getFirstCompletedRemoteData() ).subscribe((data) => { if (data.hasSucceeded) { - this.patterns = data.payload.page[0].patterns; + // remove mock data after impl + this.patterns = [ { + "pattern":"request-review", + "multipleRequest":true + },{ + "pattern":"request-endorsement", + "multipleRequest":true + },{ + "pattern":"request-ingest", + "multipleRequest":false + } ]; this.initSelectedServicesByPattern(); } })); @@ -112,40 +126,34 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent */ 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) { + if (this.ldnServiceByPattern[pattern].services[index]?.id === selectedService?.id) { return; } // initialize the previousServices object for the pattern if it does not exist if (!this.previousServices[pattern]) { - this.previousServices[pattern] = {}; + this.previousServices[pattern] = { + services: [], + allowsMultipleRequests: this.patterns[pattern]?.multipleRequest + }; } - 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; + this.previousServices[pattern].services[index] = this.ldnServiceByPattern[pattern].services[index]; // set the new value - this.ldnServiceByPattern[pattern][index] = selectedService; + this.ldnServiceByPattern[pattern].services[index] = selectedService; - const hasPrevValueStored = hasValue(this.previousServices[pattern][index]) && this.previousServices[pattern][index] !== selectedService.id; + const hasPrevValueStored = hasValue(this.previousServices[pattern].services[index]) && this.previousServices[pattern].services[index].id !== 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); + 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.previousServices[pattern].services[index] = this.ldnServiceByPattern[pattern].services[index]; this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionData.id); this.chd.detectChanges(); } @@ -158,22 +166,25 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent * 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.patterns.forEach((ldnPattern) => { + if (hasValue(this.sectionData.data[ldnPattern.pattern])) { this.subs.push( - this.filterServices(pattern) + this.filterServices(ldnPattern.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); + const selection = (this.sectionData.data[ldnPattern.pattern] as LdnService[]).find((s: LdnService) => s.id === service.id); + this.addService(ldnPattern, selection); + return this.sectionData.data[ldnPattern.pattern].includes(service.id); }); - this.ldnServiceByPattern[pattern] = selectedServices; + this.ldnServiceByPattern[ldnPattern.pattern].services = selectedServices; }) ); } else { - this.ldnServiceByPattern[pattern] = []; - this.addService(pattern, null); + this.ldnServiceByPattern[ldnPattern.pattern] = { + services: [], + allowsMultipleRequests: ldnPattern.multipleRequest + }; + this.addService(ldnPattern, null); } }); } @@ -183,23 +194,33 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent * @param pattern - The pattern to add the new service to. * @param newService - The new service to add. */ - addService(pattern: string, newService: LdnService) { + addService(ldnPattern: LdnPattern, 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] = []; + if (!this.ldnServiceByPattern[ldnPattern.pattern]) { + this.ldnServiceByPattern[ldnPattern.pattern] = { + services: [], + allowsMultipleRequests: ldnPattern.multipleRequest + }; } - this.ldnServiceByPattern[pattern].push(newService); + this.ldnServiceByPattern[ldnPattern.pattern].services.push(newService); } /** * Removes the service at the specified index from the array corresponding to the pattern. - * (part of next phase of implementation) + * @param ldnPattern - The LDN pattern from which to remove the service + * @param serviceIndex - the service index to remove */ - removeService(pattern: string, serviceIndex: number) { - if (this.ldnServiceByPattern[pattern]) { + removeService(ldnPattern: LdnPattern, serviceIndex: number) { + if (this.ldnServiceByPattern[ldnPattern.pattern]) { // Remove the service at the specified index from the array - this.ldnServiceByPattern[pattern].splice(serviceIndex, 1); + this.ldnServiceByPattern[ldnPattern.pattern].services.splice(serviceIndex, 1); + this.previousServices[ldnPattern.pattern]?.services.splice(serviceIndex, 1); + this.operationsBuilder.replace(this.pathCombiner.getPath([ldnPattern.pattern, serviceIndex.toString()]), null, true); + this.sectionService.dispatchRemoveSectionErrors(this.submissionId, this.sectionData.id); + } + if(!this.ldnServiceByPattern[ldnPattern.pattern].services.length) { + this.addNewService(ldnPattern); } } @@ -290,4 +311,13 @@ export class SubmissionSectionCoarNotifyComponent extends SectionModelComponent .filter((subscription) => hasValue(subscription)) .forEach((subscription) => subscription.unsubscribe()); } + + /** + * Add new row to dropdown for multiple service selection + * @param ldnPattern - the related LDN pattern where the service is added + */ + addNewService(ldnPattern: LdnPattern) : void { + //idle new service for new selection + this.ldnServiceByPattern[ldnPattern.pattern].services.push(null); + } } diff --git a/src/app/submission/sections/section-coar-notify/submission-coar-notify.config.ts b/src/app/submission/sections/section-coar-notify/submission-coar-notify.config.ts index 04973f80c8..4a8116cdde 100644 --- a/src/app/submission/sections/section-coar-notify/submission-coar-notify.config.ts +++ b/src/app/submission/sections/section-coar-notify/submission-coar-notify.config.ts @@ -6,7 +6,10 @@ 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'; - +export interface LdnPattern { + pattern: string, + multipleRequest: boolean +} /** A SubmissionCoarNotifyConfig and its properties. */ @typedObject @inheritSerialization(CacheableObject) @@ -24,7 +27,7 @@ export class SubmissionCoarNotifyConfig extends CacheableObject { uuid: string; @autoserialize - patterns: string[]; + patterns: LdnPattern[]; @deserialize _links: { From 6d16bf3037955a61fab7039634cf6d664802a77d Mon Sep 17 00:00:00 2001 From: FrancescoMolinaro Date: Thu, 21 Dec 2023 16:08:13 +0100 Subject: [PATCH 2/2] add flush operation, fix lint, refactor --- .../builder/json-patch-operations-builder.ts | 15 +++++++ .../json-patch-operations.reducer.ts | 43 +++++++++++++++++-- .../section-coar-notify.component.html | 7 ++- .../section-coar-notify.component.ts | 35 ++++++--------- 4 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/app/core/json-patch/builder/json-patch-operations-builder.ts b/src/app/core/json-patch/builder/json-patch-operations-builder.ts index f5a584fd3d..0982e3ed53 100644 --- a/src/app/core/json-patch/builder/json-patch-operations-builder.ts +++ b/src/app/core/json-patch/builder/json-patch-operations-builder.ts @@ -1,5 +1,6 @@ import { Store } from '@ngrx/store'; import { + FlushPatchOperationAction, NewPatchAddOperationAction, NewPatchMoveOperationAction, NewPatchRemoveOperationAction, @@ -99,6 +100,20 @@ export class JsonPatchOperationsBuilder { path.path)); } + /** + * Dispatches a new FlushPatchOperationAction + * + * @param path + * a JsonPatchOperationPathObject representing path + */ + flushOperation(path: JsonPatchOperationPathObject) { + this.store.dispatch( + new FlushPatchOperationAction( + path.rootElement, + path.subRootElement, + path.path)); + } + protected prepareValue(value: any, plain: boolean, first: boolean) { let operationValue: any = null; if (hasValue(value)) { diff --git a/src/app/core/json-patch/json-patch-operations.reducer.ts b/src/app/core/json-patch/json-patch-operations.reducer.ts index 5e00027edb..a3f972e190 100644 --- a/src/app/core/json-patch/json-patch-operations.reducer.ts +++ b/src/app/core/json-patch/json-patch-operations.reducer.ts @@ -12,7 +12,7 @@ import { CommitPatchOperationsAction, StartTransactionPatchOperationsAction, RollbacktPatchOperationsAction, - DeletePendingJsonPatchOperationsAction + DeletePendingJsonPatchOperationsAction, FlushPatchOperationAction } from './json-patch-operations.actions'; import { JsonPatchOperationModel, JsonPatchOperationType } from './json-patch.model'; @@ -71,7 +71,7 @@ export function jsonPatchOperationsReducer(state = initialState, action: PatchOp } case JsonPatchOperationsActionTypes.FLUSH_JSON_PATCH_OPERATIONS: { - return flushOperation(state, action as FlushPatchOperationsAction); + return flushOperations(state, action as FlushPatchOperationsAction); } case JsonPatchOperationsActionTypes.NEW_JSON_PATCH_ADD_OPERATION: { @@ -106,6 +106,10 @@ export function jsonPatchOperationsReducer(state = initialState, action: PatchOp return deletePendingOperations(state, action as DeletePendingJsonPatchOperationsAction); } + case JsonPatchOperationsActionTypes.FLUSH_JSON_PATCH_OPERATION: { + return flushOperation(state, action as FlushPatchOperationAction); + } + default: { return state; } @@ -197,6 +201,39 @@ function deletePendingOperations(state: JsonPatchOperationsState, action: Delete return null; } +/** + * Flush one operation from JsonPatchOperationsState. + * + * @param state + * the current state + * @param action + * an FlushPatchOperationsAction + * @return JsonPatchOperationsState + * the new state. + */ +function flushOperation(state: JsonPatchOperationsState, action: FlushPatchOperationAction): JsonPatchOperationsState { + const payload = action.payload; + if (state[payload.resourceType] && state[payload.resourceType].children) { + const body = state[payload.resourceType].children[payload.resourceId].body; + const operation = body.filter(operations => operations.operation.path === payload.path)[0]; + const operationIndex = body.indexOf(operation); + const newBody = [...body]; + newBody.splice(operationIndex, 1); + + return Object.assign({}, state, { + [action.payload.resourceType]: Object.assign({}, { + children: { + [action.payload.resourceId]: { + body: newBody, + } + }, + }) + }); + } else { + return state; + } +} + /** * Add new JSON patch operation list. * @@ -273,7 +310,7 @@ function hasValidBody(state: JsonPatchOperationsState, resourceType: any, resour * @return SubmissionObjectState * the new state, with the section new validity status. */ -function flushOperation(state: JsonPatchOperationsState, action: FlushPatchOperationsAction): JsonPatchOperationsState { +function flushOperations(state: JsonPatchOperationsState, action: FlushPatchOperationsAction): JsonPatchOperationsState { if (hasValue(state[ action.payload.resourceType ])) { let newChildren; if (isNotUndefined(action.payload.resourceId)) { diff --git a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html index 7356b06b4f..7b61b68564 100644 --- a/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html +++ b/src/app/submission/sections/section-coar-notify/section-coar-notify.component.html @@ -70,9 +70,12 @@
-