diff --git a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.html b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.html index 45fb1d68a5..61d387ef3b 100644 --- a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.html +++ b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.html @@ -48,27 +48,30 @@ - +
- +
- -
-
+
{{ 'ldn-new-service.form.error.ipRange' | translate }}
+
+ {{ 'ldn-new-service.form.hint.ipRange' | translate }} +
@@ -107,7 +110,7 @@
- +
@@ -168,7 +171,7 @@
+ *ngIf="formModel.get('notifyServiceInboundPatterns')['controls'][i].value.pattern">
diff --git a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts index ba654538a3..41fdd71160 100644 --- a/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts +++ b/src/app/admin/admin-ldn-services/ldn-service-form/ldn-service-form.component.ts @@ -1,11 +1,8 @@ import { ChangeDetectorRef, Component, - EventEmitter, - Input, OnDestroy, OnInit, - Output, TemplateRef, ViewChild } from '@angular/core'; @@ -49,37 +46,26 @@ import { IpV4Validator } from '../../../shared/utils/ipV4.validator'; }) export class LdnServiceFormComponent implements OnInit, OnDestroy { formModel: FormGroup; + @ViewChild('confirmModal', {static: true}) confirmModal: TemplateRef; @ViewChild('resetFormModal', {static: true}) resetFormModal: TemplateRef; public inboundPatterns: string[] = notifyPatterns; public isNewService: boolean; public areControlsInitialized: boolean; - itemfiltersRD$: Observable>>; - config: FindListOptions = Object.assign(new FindListOptions(), { + public itemfiltersRD$: Observable>>; + public config: FindListOptions = Object.assign(new FindListOptions(), { elementsPerPage: 20 }); + public markedForDeletionInboundPattern: number[] = []; + public selectedInboundPatterns: string[]; + public selectedInboundItemfilters: string[]; - @Input() public name: string; - @Input() public description: string; - @Input() public url: string; - @Input() public ldnUrl: string; - @Input() public ipRangeMin: string; - @Input() public ipRangeMax: string; - @Input() public score: number; - @Input() public inboundPattern: string; - @Input() public constraint: string; - @Input() public automatic: boolean; - @Input() public headerKey: string; - @Output() submitForm: EventEmitter = new EventEmitter(); - @Output() cancelForm: EventEmitter = new EventEmitter(); - markedForDeletionInboundPattern: number[] = []; - selectedInboundPatterns: string[]; - selectedInboundItemfilters: string[]; protected serviceId: string; + private deletedInboundPatterns: number[] = []; private modalRef: any; - private service: LdnService; + private ldnService: LdnService; private selectPatternDefaultLabeli18Key = 'ldn-service.form.label.placeholder.default-select'; private routeSubscription: Subscription; @@ -102,8 +88,8 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { description: [''], url: ['', Validators.required], ldnUrl: ['', Validators.required], - ipRangeMin: ['', [Validators.required, new IpV4Validator()]], - ipRangeMax: ['', [new IpV4Validator()]], + lowerIp: ['', [Validators.required, new IpV4Validator()]], + upperIp: ['', [Validators.required, new IpV4Validator()]], score: ['', [Validators.required, Validators.pattern('^0*(\.[0-9]+)?$|^1(\.0+)?$')]], inboundPattern: [''], constraintPattern: [''], enabled: [''], @@ -144,15 +130,9 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { */ createService() { this.formModel.markAllAsTouched(); - - 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); - if (!name || !url || !ldnUrl || (!score && score !== 0) || this.formModel.get('score').invalid) { + if (this.formModel.invalid) { this.closeModal(); return; } @@ -182,9 +162,8 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { if (rd.hasSucceeded) { this.notificationService.success(this.translateService.get('ldn-service-notification.created.success.title'), this.translateService.get('ldn-service-notification.created.success.body')); - - this.sendBack(); this.closeModal(); + this.sendBack(); } else { this.notificationService.error(this.translateService.get('ldn-service-notification.created.failure.title'), this.translateService.get('ldn-service-notification.created.failure.body')); @@ -219,18 +198,21 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { ).subscribe( (data: RemoteData) => { if (data.hasSucceeded) { - this.service = data.payload; + this.ldnService = data.payload; this.formModel.patchValue({ - id: this.service.id, - name: this.service.name, - description: this.service.description, - url: this.service.url, - score: this.service.score, ldnUrl: this.service.ldnUrl, - type: this.service.type, - enabled: this.service.enabled + id: this.ldnService.id, + name: this.ldnService.name, + description: this.ldnService.description, + url: this.ldnService.url, + score: this.ldnService.score, + ldnUrl: this.ldnService.ldnUrl, + type: this.ldnService.type, + enabled: this.ldnService.enabled, + lowerIp: this.ldnService.lowerIp, + upperIp: this.ldnService.upperIp, }); - this.filterPatternObjectsAndPickLabel('notifyServiceInboundPatterns'); + this.filterPatternObjectsAndAssignLabel('notifyServiceInboundPatterns'); } }, ); @@ -240,11 +222,11 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { * 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 */ - filterPatternObjectsAndPickLabel(formArrayName: string) { + filterPatternObjectsAndAssignLabel(formArrayName: string) { const PatternsArray = this.formModel.get(formArrayName) as FormArray; PatternsArray.clear(); - let servicesToUse; - servicesToUse = this.service.notifyServiceInboundPatterns; + + let servicesToUse = this.ldnService.notifyServiceInboundPatterns; servicesToUse.forEach((patternObj: NotifyServicePattern) => { let patternFormGroup; @@ -258,8 +240,6 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { PatternsArray.push(patternFormGroup); this.cdRef.detectChanges(); }); - - } /** @@ -274,6 +254,8 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { this.createReplaceOperation(patchOperations, 'ldnUrl', '/ldnurl'); this.createReplaceOperation(patchOperations, 'url', '/url'); this.createReplaceOperation(patchOperations, 'score', '/score'); + this.createReplaceOperation(patchOperations, 'lowerIp', '/lowerIp'); + this.createReplaceOperation(patchOperations, 'upperIp', '/upperIp'); this.handlePatterns(patchOperations, 'notifyServiceInboundPatterns'); this.deletedInboundPatterns.forEach(index => { @@ -347,11 +329,10 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { value: newStatus, }; - this.ldnServicesService.patch(this.service, [patchOperation]).pipe( + this.ldnServicesService.patch(this.ldnService, [patchOperation]).pipe( getFirstCompletedRemoteData() ).subscribe( () => { - this.formModel.get('enabled').setValue(newStatus); this.cdRef.detectChanges(); } @@ -407,7 +388,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy { return; } - this.ldnServicesService.patch(this.service, patchOperations).pipe( + this.ldnServicesService.patch(this.ldnService, patchOperations).pipe( getFirstCompletedRemoteData() ).subscribe( (rd: RemoteData) => { 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 315d3ff89e..0fcde59d01 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 @@ -41,6 +41,12 @@ export class LdnService extends CacheableObject { @autoserialize ldnUrl: string; + @autoserialize + lowerIp: string; + + @autoserialize + upperIp: string; + @autoserialize notifyServiceInboundPatterns?: NotifyServicePattern[]; diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index fce242914a..f348d0c981 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -285,7 +285,7 @@ import { NgxPaginationModule } from 'ngx-pagination'; import { SplitPipe } from './utils/split.pipe'; import { ThemedUserMenuComponent } from './auth-nav-menu/user-menu/themed-user-menu.component'; import { ThemedLangSwitchComponent } from './lang-switch/themed-lang-switch.component'; -import { IpV4Validator } from "./utils/ipV4.validator"; +import { IpV4Validator } from './utils/ipV4.validator'; const MODULES = [ CommonModule, diff --git a/src/app/shared/utils/ipV4.validator.spec.ts b/src/app/shared/utils/ipV4.validator.spec.ts index fa3e5fd06f..93f5ee86e9 100644 --- a/src/app/shared/utils/ipV4.validator.spec.ts +++ b/src/app/shared/utils/ipV4.validator.spec.ts @@ -1,6 +1,6 @@ -import { IpV4Validator } from "./ipV4.validator"; -import { TestBed } from "@angular/core/testing"; -import { UntypedFormControl, UntypedFormGroup } from "@angular/forms"; +import { IpV4Validator } from './ipV4.validator'; +import { TestBed } from '@angular/core/testing'; +import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; describe('IpV4 validator', () => { @@ -22,15 +22,15 @@ describe('IpV4 validator', () => { it('should return null for valid ipV4', () => { formGroup.controls.ip.setValue(validIp); - expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toBeNull() + expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toBeNull(); }); it('should return {isValidIp: false} for invalid Ip', () => { formGroup.controls.ip.setValue('100.260.45.1'); - expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}) + expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}); formGroup.controls.ip.setValue('100'); - expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}) + expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}); formGroup.controls.ip.setValue('testString'); - expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}) + expect(ipV4Validator.validate(formGroup.controls.ip as UntypedFormControl)).toEqual({isValidIp: false}); }); }); diff --git a/src/app/shared/utils/ipV4.validator.ts b/src/app/shared/utils/ipV4.validator.ts index a5caa144ea..170dbeb547 100644 --- a/src/app/shared/utils/ipV4.validator.ts +++ b/src/app/shared/utils/ipV4.validator.ts @@ -17,10 +17,10 @@ export class IpV4Validator implements Validator { const ipValue = formControl.value; const ipParts = ipValue?.split('.'); - if (ipv4Regex.test(ipValue) && ipParts.every(part => parseInt(part) <= 255)) { + if (ipv4Regex.test(ipValue) && ipParts.every(part => parseInt(part, 10) <= 255)) { return null; } - return {isValidIp: false} + return {isValidIp: false}; } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 87273a199a..785dbe11b9 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -937,7 +937,8 @@ "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.url": "Please input the URL for users to check out more information about the service", - "ldn-new-service.form.placeholder.ipRange": "Please input the IPv4 range of the service", + "ldn-new-service.form.placeholder.lowerIp": "IPv4 range lower bound", + "ldn-new-service.form.placeholder.upperIp": "IPv4 range upper bound", "ldn-new-service.form.placeholder.ldnUrl": "Please specify the URL of the LDN Inbox", "ldn-new-service.form.placeholder.score": "Please enter a value between 0 and 1. Use the “.” as decimal separator", "ldn-service.form.label.placeholder.default-select": "Select a pattern", @@ -1000,6 +1001,7 @@ "ldn-new-service.form.error.name": "Name is required", "ldn-new-service.form.error.url": "URL is required", "ldn-new-service.form.error.ipRange": "Please enter a valid IP range", + "ldn-new-service.form.hint.ipRange": "Please enter a valid IpV4 in both range bounds (note: for single IP, please enter the same value in both fields)", "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",