diff --git a/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.html b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.html new file mode 100644 index 0000000000..b3df6f83e5 --- /dev/null +++ b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.html @@ -0,0 +1,24 @@ + + + diff --git a/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.scss b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.spec.ts b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.spec.ts new file mode 100644 index 0000000000..e493915162 --- /dev/null +++ b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.spec.ts @@ -0,0 +1,165 @@ +import { EditExternalSourceModalComponent } from './edit-external-source-modal.component'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { fakeAsync, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { of } from 'rxjs'; +import { MockI18nModule } from '../../../i18n/mock-i18n.spec'; +import { DefaultValidationErrorsComponent } from '../../components/shared/default-validation-errors/default-validation-errors.component'; +import { ExternalSourceService } from '../../services/external-source.service'; +import { ExternalSourceCommandDTO, ExternalSourceDTO } from '../../model/external-sources.model'; + +class EditExternalSourceModalComponentTester extends ComponentTester { + constructor() { + super(EditExternalSourceModalComponent); + } + + get reference() { + return this.input('#reference')!; + } + + get description() { + return this.textarea('#description')!; + } + + get validationErrors() { + return this.elements('val-errors div'); + } + + get save() { + return this.button('#save-button')!; + } + + get cancel() { + return this.button('#cancel-button')!; + } +} + +describe('EditExternalSourceModalComponent', () => { + let tester: EditExternalSourceModalComponentTester; + let fakeActiveModal: NgbActiveModal; + let externalSourceService: jasmine.SpyObj; + + beforeEach(() => { + fakeActiveModal = createMock(NgbActiveModal); + externalSourceService = createMock(ExternalSourceService); + + TestBed.configureTestingModule({ + imports: [ + MockI18nModule, + ReactiveFormsModule, + HttpClientTestingModule, + EditExternalSourceModalComponent, + DefaultValidationErrorsComponent + ], + providers: [ + { provide: NgbActiveModal, useValue: fakeActiveModal }, + { provide: ExternalSourceService, useValue: externalSourceService } + ] + }); + + TestBed.createComponent(DefaultValidationErrorsComponent).detectChanges(); + + tester = new EditExternalSourceModalComponentTester(); + }); + + describe('create mode', () => { + beforeEach(() => { + tester.componentInstance.prepareForCreation(); + tester.detectChanges(); + }); + + it('should have an empty form', () => { + expect(tester.reference).toHaveValue(''); + expect(tester.description).toHaveValue(''); + }); + + it('should not save if invalid', () => { + tester.save.click(); + + // reference + expect(tester.validationErrors.length).toBe(1); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + tester.reference.fillWith('ref'); + tester.description.fillWith('desc'); + + tester.detectChanges(); + + const createdExternalSource = { + id: 'id1' + } as ExternalSourceDTO; + externalSourceService.createExternalSource.and.returnValue(of(createdExternalSource)); + + tester.save.click(); + + const expectedCommand: ExternalSourceCommandDTO = { + reference: 'ref', + description: 'desc' + }; + + expect(externalSourceService.createExternalSource).toHaveBeenCalledWith(expectedCommand); + expect(fakeActiveModal.close).toHaveBeenCalledWith(createdExternalSource); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); + + describe('edit mode', () => { + const externalSourceToUpdate: ExternalSourceDTO = { + id: 'id1', + reference: 'ref1', + description: 'My External source 1' + }; + + beforeEach(() => { + externalSourceService.getExternalSource.and.returnValue(of(externalSourceToUpdate)); + + tester.componentInstance.prepareForEdition(externalSourceToUpdate); + tester.detectChanges(); + }); + + it('should have a populated form', () => { + expect(tester.reference).toHaveValue(externalSourceToUpdate.reference); + expect(tester.description).toHaveValue(externalSourceToUpdate.description); + }); + + it('should not save if invalid', () => { + tester.reference.fillWith(''); + tester.save.click(); + + // reference + expect(tester.validationErrors.length).toBe(1); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + externalSourceService.updateExternalSource.and.returnValue(of(undefined)); + + tester.reference.fillWith('External source 1 (updated)'); + tester.description.fillWith('A longer and updated description of my external source'); + + tester.save.click(); + + const expectedCommand: ExternalSourceCommandDTO = { + reference: 'External source 1 (updated)', + description: 'A longer and updated description of my external source' + }; + + expect(externalSourceService.updateExternalSource).toHaveBeenCalledWith('id1', expectedCommand); + expect(externalSourceService.getExternalSource).toHaveBeenCalledWith('id1'); + expect(fakeActiveModal.close).toHaveBeenCalledWith(externalSourceToUpdate); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); +}); diff --git a/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.ts b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.ts new file mode 100644 index 0000000000..e2595fe502 --- /dev/null +++ b/frontend/src/app/engine/edit-external-source-modal/edit-external-source-modal.component.ts @@ -0,0 +1,77 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Observable, switchMap } from 'rxjs'; +import { ObservableState, SaveButtonComponent } from '../../components/shared/save-button/save-button.component'; +import { ValidationErrorsComponent } from 'ngx-valdemort'; +import { TranslateModule } from '@ngx-translate/core'; +import { ExternalSourceCommandDTO, ExternalSourceDTO } from '../../model/external-sources.model'; +import { ExternalSourceService } from '../../services/external-source.service'; + +@Component({ + selector: 'oib-edit-external-source-modal', + templateUrl: './edit-external-source-modal.component.html', + styleUrls: ['./edit-external-source-modal.component.scss'], + imports: [ReactiveFormsModule, TranslateModule, ValidationErrorsComponent, SaveButtonComponent], + standalone: true +}) +export class EditExternalSourceModalComponent { + mode: 'create' | 'edit' = 'create'; + state = new ObservableState(); + externalSource: ExternalSourceDTO | null = null; + form = this.fb.group({ + reference: ['', Validators.required], + description: '' + }); + + constructor(private modal: NgbActiveModal, private fb: FormBuilder, private externalSourceService: ExternalSourceService) {} + + /** + * Prepares the component for creation. + */ + prepareForCreation() { + this.mode = 'create'; + } + + /** + * Prepares the component for edition. + */ + prepareForEdition(externalSource: ExternalSourceDTO) { + this.mode = 'edit'; + this.externalSource = externalSource; + + this.form.patchValue({ + reference: externalSource.reference, + description: externalSource.description + }); + } + + cancel() { + this.modal.dismiss(); + } + + save() { + if (!this.form.valid) { + return; + } + + const formValue = this.form.value; + + const command: ExternalSourceCommandDTO = { + reference: formValue.reference!, + description: formValue.description! + }; + + let obs: Observable; + if (this.mode === 'create') { + obs = this.externalSourceService.createExternalSource(command); + } else { + obs = this.externalSourceService + .updateExternalSource(this.externalSource!.id, command) + .pipe(switchMap(() => this.externalSourceService.getExternalSource(this.externalSource!.id))); + } + obs.pipe(this.state.pendingUntilFinalization()).subscribe(externalSource => { + this.modal.close(externalSource); + }); + } +} diff --git a/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.html b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.html new file mode 100644 index 0000000000..b6adf9635d --- /dev/null +++ b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.html @@ -0,0 +1,24 @@ + + + diff --git a/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.scss b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.spec.ts b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.spec.ts new file mode 100644 index 0000000000..0c44d8c936 --- /dev/null +++ b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.spec.ts @@ -0,0 +1,159 @@ +import { EditIpFilterModalComponent } from './edit-ip-filter-modal.component'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { fakeAsync, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { of } from 'rxjs'; +import { MockI18nModule } from '../../../i18n/mock-i18n.spec'; +import { DefaultValidationErrorsComponent } from '../../components/shared/default-validation-errors/default-validation-errors.component'; +import { IpFilterService } from '../../services/ip-filter.service'; +import { IpFilterCommandDTO, IpFilterDTO } from '../../model/ip-filter.model'; + +class EditIpFilterModalComponentTester extends ComponentTester { + constructor() { + super(EditIpFilterModalComponent); + } + + get address() { + return this.input('#address')!; + } + + get description() { + return this.textarea('#description')!; + } + + get validationErrors() { + return this.elements('val-errors div'); + } + + get save() { + return this.button('#save-button')!; + } + + get cancel() { + return this.button('#cancel-button')!; + } +} + +describe('EditIpFilterModalComponent', () => { + let tester: EditIpFilterModalComponentTester; + let fakeActiveModal: NgbActiveModal; + let ipFilterService: jasmine.SpyObj; + + beforeEach(() => { + fakeActiveModal = createMock(NgbActiveModal); + ipFilterService = createMock(IpFilterService); + + TestBed.configureTestingModule({ + imports: [MockI18nModule, ReactiveFormsModule, HttpClientTestingModule, EditIpFilterModalComponent, DefaultValidationErrorsComponent], + providers: [ + { provide: NgbActiveModal, useValue: fakeActiveModal }, + { provide: IpFilterService, useValue: ipFilterService } + ] + }); + + TestBed.createComponent(DefaultValidationErrorsComponent).detectChanges(); + + tester = new EditIpFilterModalComponentTester(); + }); + + describe('create mode', () => { + beforeEach(() => { + tester.componentInstance.prepareForCreation(); + tester.detectChanges(); + }); + + it('should have an empty form', () => { + expect(tester.address).toHaveValue(''); + expect(tester.description).toHaveValue(''); + }); + + it('should not save if invalid', () => { + tester.save.click(); + + // address + expect(tester.validationErrors.length).toBe(1); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + tester.address.fillWith('127.0.0.1'); + tester.description.fillWith('desc'); + + tester.detectChanges(); + + const createdProxy = { + id: 'id1' + } as IpFilterDTO; + ipFilterService.createIpFilter.and.returnValue(of(createdProxy)); + + tester.save.click(); + + const expectedCommand: IpFilterCommandDTO = { + address: '127.0.0.1', + description: 'desc' + }; + + expect(ipFilterService.createIpFilter).toHaveBeenCalledWith(expectedCommand); + expect(fakeActiveModal.close).toHaveBeenCalledWith(createdProxy); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); + + describe('edit mode', () => { + const ipFilterToUpdate: IpFilterDTO = { + id: 'id1', + address: '127.0.0.1', + description: 'My IP Filter 1' + }; + + beforeEach(() => { + ipFilterService.getIpFilter.and.returnValue(of(ipFilterToUpdate)); + + tester.componentInstance.prepareForEdition(ipFilterToUpdate); + tester.detectChanges(); + }); + + it('should have a populated form', () => { + expect(tester.address).toHaveValue(ipFilterToUpdate.address); + expect(tester.description).toHaveValue(ipFilterToUpdate.description); + }); + + it('should not save if invalid', () => { + tester.address.fillWith(''); + tester.save.click(); + + // address + expect(tester.validationErrors.length).toBe(1); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + ipFilterService.updateIpFilter.and.returnValue(of(undefined)); + + tester.address.fillWith('192.168.0.1'); + tester.description.fillWith('A longer and updated description of my IP filter'); + + tester.save.click(); + + const expectedCommand: IpFilterCommandDTO = { + address: '192.168.0.1', + description: 'A longer and updated description of my IP filter' + }; + + expect(ipFilterService.updateIpFilter).toHaveBeenCalledWith('id1', expectedCommand); + expect(ipFilterService.getIpFilter).toHaveBeenCalledWith('id1'); + expect(fakeActiveModal.close).toHaveBeenCalledWith(ipFilterToUpdate); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); +}); diff --git a/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.ts b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.ts new file mode 100644 index 0000000000..3693973b0a --- /dev/null +++ b/frontend/src/app/engine/edit-ip-filter-modal/edit-ip-filter-modal.component.ts @@ -0,0 +1,77 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Observable, switchMap } from 'rxjs'; +import { ObservableState, SaveButtonComponent } from '../../components/shared/save-button/save-button.component'; +import { ValidationErrorsComponent } from 'ngx-valdemort'; +import { TranslateModule } from '@ngx-translate/core'; +import { IpFilterCommandDTO, IpFilterDTO } from '../../model/ip-filter.model'; +import { IpFilterService } from '../../services/ip-filter.service'; + +@Component({ + selector: 'oib-edit-ip-filter-modal', + templateUrl: './edit-ip-filter-modal.component.html', + styleUrls: ['./edit-ip-filter-modal.component.scss'], + imports: [ReactiveFormsModule, TranslateModule, ValidationErrorsComponent, SaveButtonComponent], + standalone: true +}) +export class EditIpFilterModalComponent { + mode: 'create' | 'edit' = 'create'; + state = new ObservableState(); + ipFilter: IpFilterDTO | null = null; + form = this.fb.group({ + address: ['', Validators.required], + description: '' + }); + + constructor(private modal: NgbActiveModal, private fb: FormBuilder, private ipFilterService: IpFilterService) {} + + /** + * Prepares the component for creation. + */ + prepareForCreation() { + this.mode = 'create'; + } + + /** + * Prepares the component for edition. + */ + prepareForEdition(ipFilter: IpFilterDTO) { + this.mode = 'edit'; + this.ipFilter = ipFilter; + + this.form.patchValue({ + address: ipFilter.address, + description: ipFilter.description + }); + } + + cancel() { + this.modal.dismiss(); + } + + save() { + if (!this.form.valid) { + return; + } + + const formValue = this.form.value; + + const command: IpFilterCommandDTO = { + address: formValue.address!, + description: formValue.description! + }; + + let obs: Observable; + if (this.mode === 'create') { + obs = this.ipFilterService.createIpFilter(command); + } else { + obs = this.ipFilterService + .updateIpFilter(this.ipFilter!.id, command) + .pipe(switchMap(() => this.ipFilterService.getIpFilter(this.ipFilter!.id))); + } + obs.pipe(this.state.pendingUntilFinalization()).subscribe(ipFilter => { + this.modal.close(ipFilter); + }); + } +} diff --git a/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.html b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.html new file mode 100644 index 0000000000..8a98711e34 --- /dev/null +++ b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.html @@ -0,0 +1,31 @@ + + + diff --git a/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.scss b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.spec.ts b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.spec.ts new file mode 100644 index 0000000000..20fbb7dab4 --- /dev/null +++ b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.spec.ts @@ -0,0 +1,168 @@ +import { EditScanModeModalComponent } from './edit-scan-mode-modal.component'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { fakeAsync, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { of } from 'rxjs'; +import { MockI18nModule } from '../../../i18n/mock-i18n.spec'; +import { DefaultValidationErrorsComponent } from '../../components/shared/default-validation-errors/default-validation-errors.component'; +import { ScanModeService } from '../../services/scan-mode.service'; +import { ScanModeCommandDTO, ScanModeDTO } from '../../model/scan-mode.model'; + +class EditScanModeModalComponentTester extends ComponentTester { + constructor() { + super(EditScanModeModalComponent); + } + + get name() { + return this.input('#name')!; + } + + get description() { + return this.textarea('#description')!; + } + + get cron() { + return this.input('#cron')!; + } + + get validationErrors() { + return this.elements('val-errors div'); + } + + get save() { + return this.button('#save-button')!; + } + + get cancel() { + return this.button('#cancel-button')!; + } +} + +describe('EditScanModeModalComponent', () => { + let tester: EditScanModeModalComponentTester; + let fakeActiveModal: NgbActiveModal; + let scanModeService: jasmine.SpyObj; + + beforeEach(() => { + fakeActiveModal = createMock(NgbActiveModal); + scanModeService = createMock(ScanModeService); + + TestBed.configureTestingModule({ + imports: [MockI18nModule, ReactiveFormsModule, HttpClientTestingModule, EditScanModeModalComponent, DefaultValidationErrorsComponent], + providers: [ + { provide: NgbActiveModal, useValue: fakeActiveModal }, + { provide: ScanModeService, useValue: scanModeService } + ] + }); + + TestBed.createComponent(DefaultValidationErrorsComponent).detectChanges(); + + tester = new EditScanModeModalComponentTester(); + }); + + describe('create mode', () => { + beforeEach(() => { + tester.componentInstance.prepareForCreation(); + tester.detectChanges(); + }); + + it('should have an empty form', () => { + expect(tester.name).toHaveValue(''); + expect(tester.description).toHaveValue(''); + expect(tester.cron).toHaveValue(''); + }); + + it('should not save if invalid', () => { + tester.save.click(); + + // name, cron + expect(tester.validationErrors.length).toBe(2); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + tester.name.fillWith('test'); + tester.description.fillWith('desc'); + tester.cron.fillWith('* * * * * *'); + + tester.detectChanges(); + + const createdScanMode = { + id: 'id1' + } as ScanModeDTO; + scanModeService.createScanMode.and.returnValue(of(createdScanMode)); + + tester.save.click(); + + const expectedCommand: ScanModeCommandDTO = { + name: 'test', + description: 'desc', + cron: '* * * * * *' + }; + + expect(scanModeService.createScanMode).toHaveBeenCalledWith(expectedCommand); + expect(fakeActiveModal.close).toHaveBeenCalledWith(createdScanMode); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); + + describe('edit mode', () => { + const scanModeToUpdate: ScanModeDTO = { + id: 'id1', + name: 'proxy1', + description: 'My Proxy 1', + cron: '* * * * * *' + }; + + beforeEach(() => { + scanModeService.getScanMode.and.returnValue(of(scanModeToUpdate)); + + tester.componentInstance.prepareForEdition(scanModeToUpdate); + tester.detectChanges(); + }); + + it('should have a populated form', () => { + expect(tester.name).toHaveValue(scanModeToUpdate.name); + expect(tester.description).toHaveValue(scanModeToUpdate.description); + }); + + it('should not save if invalid', () => { + tester.name.fillWith(''); + tester.save.click(); + + // name + expect(tester.validationErrors.length).toBe(1); + expect(fakeActiveModal.close).not.toHaveBeenCalled(); + }); + + it('should save if valid', fakeAsync(() => { + scanModeService.updateScanMode.and.returnValue(of(undefined)); + + tester.name.fillWith('Scan Mode 1 (updated)'); + tester.description.fillWith('A longer and updated description of my Scan Mode'); + + tester.save.click(); + + const expectedCommand: ScanModeCommandDTO = { + name: 'Scan Mode 1 (updated)', + description: 'A longer and updated description of my Scan Mode', + cron: scanModeToUpdate.cron + }; + + expect(scanModeService.updateScanMode).toHaveBeenCalledWith('id1', expectedCommand); + expect(scanModeService.getScanMode).toHaveBeenCalledWith('id1'); + expect(fakeActiveModal.close).toHaveBeenCalledWith(scanModeToUpdate); + })); + + it('should cancel', () => { + tester.cancel.click(); + expect(fakeActiveModal.dismiss).toHaveBeenCalled(); + }); + }); +}); diff --git a/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.ts b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.ts new file mode 100644 index 0000000000..f9f8e99aaf --- /dev/null +++ b/frontend/src/app/engine/edit-scan-mode-modal/edit-scan-mode-modal.component.ts @@ -0,0 +1,80 @@ +import { Component } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Observable, switchMap } from 'rxjs'; +import { ObservableState, SaveButtonComponent } from '../../components/shared/save-button/save-button.component'; +import { ValidationErrorsComponent } from 'ngx-valdemort'; +import { TranslateModule } from '@ngx-translate/core'; +import { ScanModeService } from '../../services/scan-mode.service'; +import { ScanModeCommandDTO, ScanModeDTO } from '../../model/scan-mode.model'; + +@Component({ + selector: 'oib-edit-scan-mode-modal', + templateUrl: './edit-scan-mode-modal.component.html', + styleUrls: ['./edit-scan-mode-modal.component.scss'], + imports: [ReactiveFormsModule, TranslateModule, ValidationErrorsComponent, SaveButtonComponent], + standalone: true +}) +export class EditScanModeModalComponent { + mode: 'create' | 'edit' = 'create'; + state = new ObservableState(); + scanMode: ScanModeDTO | null = null; + form = this.fb.group({ + name: ['', Validators.required], + description: '', + cron: ['', Validators.required] + }); + + constructor(private modal: NgbActiveModal, private fb: FormBuilder, private scanModeService: ScanModeService) {} + + /** + * Prepares the component for creation. + */ + prepareForCreation() { + this.mode = 'create'; + } + + /** + * Prepares the component for edition. + */ + prepareForEdition(scanMode: ScanModeDTO) { + this.mode = 'edit'; + this.scanMode = scanMode; + + this.form.patchValue({ + name: scanMode.name, + description: scanMode.description, + cron: scanMode.cron + }); + } + + cancel() { + this.modal.dismiss(); + } + + save() { + if (!this.form.valid) { + return; + } + + const formValue = this.form.value; + + const command: ScanModeCommandDTO = { + name: formValue.name!, + description: formValue.description!, + cron: formValue.cron! + }; + + let obs: Observable; + if (this.mode === 'create') { + obs = this.scanModeService.createScanMode(command); + } else { + obs = this.scanModeService + .updateScanMode(this.scanMode!.id, command) + .pipe(switchMap(() => this.scanModeService.getScanMode(this.scanMode!.id))); + } + obs.pipe(this.state.pendingUntilFinalization()).subscribe(scanMode => { + this.modal.close(scanMode); + }); + } +} diff --git a/frontend/src/app/engine/engine.component.html b/frontend/src/app/engine/engine.component.html index ef4c39402c..828808cb8e 100644 --- a/frontend/src/app/engine/engine.component.html +++ b/frontend/src/app/engine/engine.component.html @@ -60,7 +60,10 @@

- + + + + diff --git a/frontend/src/app/engine/engine.component.spec.ts b/frontend/src/app/engine/engine.component.spec.ts index 88bd9a94f6..7f83073732 100644 --- a/frontend/src/app/engine/engine.component.spec.ts +++ b/frontend/src/app/engine/engine.component.spec.ts @@ -9,6 +9,9 @@ import { provideTestingI18n } from '../../i18n/mock-i18n'; import { ProxyListComponent } from './proxy-list/proxy-list.component'; import { provideHttpClient } from '@angular/common/http'; import { provideRouter } from '@angular/router'; +import { ScanModeListComponent } from './scan-mode-list/scan-mode-list.component'; +import { ExternalSourceListComponent } from './external-source-list/external-source-list.component'; +import { IpFilterListComponent } from './ip-filter-list/ip-filter-list.component'; class EngineComponentTester extends ComponentTester { constructor() { @@ -58,6 +61,18 @@ class EngineComponentTester extends ComponentTester { get proxyList() { return this.element(ProxyListComponent); } + + get scanModeList() { + return this.element(ScanModeListComponent); + } + + get externalSourceList() { + return this.element(ExternalSourceListComponent); + } + + get ipFilterList() { + return this.element(IpFilterListComponent); + } } describe('EngineComponent', () => { @@ -119,5 +134,8 @@ describe('EngineComponent', () => { expect(tester.editButton).toContainText('Edit settings'); expect(tester.proxyList).toBeDefined(); + expect(tester.scanModeList).toBeDefined(); + expect(tester.externalSourceList).toBeDefined(); + expect(tester.ipFilterList).toBeDefined(); }); }); diff --git a/frontend/src/app/engine/engine.component.ts b/frontend/src/app/engine/engine.component.ts index bce5a1fd39..c57d9d8ac0 100644 --- a/frontend/src/app/engine/engine.component.ts +++ b/frontend/src/app/engine/engine.component.ts @@ -5,11 +5,22 @@ import { RouterLink } from '@angular/router'; import { EngineService } from '../services/engine.service'; import { EngineSettingsDTO } from '../model/engine.model'; import { NgIf } from '@angular/common'; +import { ScanModeListComponent } from './scan-mode-list/scan-mode-list.component'; +import { ExternalSourceListComponent } from './external-source-list/external-source-list.component'; +import { IpFilterListComponent } from './ip-filter-list/ip-filter-list.component'; @Component({ selector: 'oib-engine', standalone: true, - imports: [NgIf, TranslateModule, RouterLink, ProxyListComponent], + imports: [ + NgIf, + TranslateModule, + RouterLink, + ProxyListComponent, + ScanModeListComponent, + ExternalSourceListComponent, + IpFilterListComponent + ], templateUrl: './engine.component.html', styleUrls: ['./engine.component.scss'] }) diff --git a/frontend/src/app/engine/external-source-list/external-source-list.component.html b/frontend/src/app/engine/external-source-list/external-source-list.component.html new file mode 100644 index 0000000000..b02838c043 --- /dev/null +++ b/frontend/src/app/engine/external-source-list/external-source-list.component.html @@ -0,0 +1,43 @@ +

+ +

+ +
+ + + + + + + + + + + + + + + +
{{ externalSource.reference }}{{ externalSource.description }} +
+ + + + +
+
+
+ +
+
diff --git a/frontend/src/app/engine/external-source-list/external-source-list.component.scss b/frontend/src/app/engine/external-source-list/external-source-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/external-source-list/external-source-list.component.spec.ts b/frontend/src/app/engine/external-source-list/external-source-list.component.spec.ts new file mode 100644 index 0000000000..c3af0be1cb --- /dev/null +++ b/frontend/src/app/engine/external-source-list/external-source-list.component.spec.ts @@ -0,0 +1,77 @@ +import { TestBed } from '@angular/core/testing'; + +import { ExternalSourceListComponent } from './external-source-list.component'; +import { provideTestingI18n } from '../../../i18n/mock-i18n'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { of } from 'rxjs'; +import { ExternalSourceService } from '../../services/external-source.service'; +import { ExternalSourceDTO } from '../../model/external-sources.model'; + +class ExternalSourceListComponentTester extends ComponentTester { + constructor() { + super(ExternalSourceListComponent); + } + + get title() { + return this.element('h2')!; + } + + get addExternalSource() { + return this.button('#add-external-source')!; + } + + get noExternalSource() { + return this.element('#no-external-source'); + } + get externalSources() { + return this.elements('tbody tr'); + } +} + +describe('ExternalSourceListComponent', () => { + let tester: ExternalSourceListComponentTester; + let externalSourceService: jasmine.SpyObj; + + beforeEach(() => { + externalSourceService = createMock(ExternalSourceService); + + TestBed.configureTestingModule({ + imports: [ExternalSourceListComponent], + providers: [provideTestingI18n(), { provide: ExternalSourceService, useValue: externalSourceService }] + }); + + tester = new ExternalSourceListComponentTester(); + }); + + it('should display a list of external sources', () => { + const externalSources: Array = [ + { + id: 'id1', + reference: 'ref1', + description: 'My external source 1' + }, + { + id: 'id2', + reference: 'ref2', + description: 'My external source 2' + } + ]; + + externalSourceService.getExternalSources.and.returnValue(of(externalSources)); + tester.detectChanges(); + + expect(tester.title).toContainText('External source list'); + expect(tester.externalSources.length).toEqual(2); + expect(tester.externalSources[0].elements('td').length).toEqual(3); + expect(tester.externalSources[1].elements('td')[0]).toContainText('ref2'); + expect(tester.externalSources[1].elements('td')[1]).toContainText('My external source 2'); + }); + + it('should display an empty list', () => { + externalSourceService.getExternalSources.and.returnValue(of([])); + tester.detectChanges(); + + expect(tester.title).toContainText('External source list'); + expect(tester.noExternalSource).toContainText('No external source'); + }); +}); diff --git a/frontend/src/app/engine/external-source-list/external-source-list.component.ts b/frontend/src/app/engine/external-source-list/external-source-list.component.ts new file mode 100644 index 0000000000..e752853300 --- /dev/null +++ b/frontend/src/app/engine/external-source-list/external-source-list.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { NgForOf, NgIf } from '@angular/common'; +import { switchMap } from 'rxjs'; +import { Modal, ModalService } from '../../components/shared/modal.service'; +import { ConfirmationService } from '../../components/shared/confirmation.service'; +import { NotificationService } from '../../components/shared/notification.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { ExternalSourceDTO } from '../../model/external-sources.model'; +import { ExternalSourceService } from '../../services/external-source.service'; +import { EditExternalSourceModalComponent } from '../edit-external-source-modal/edit-external-source-modal.component'; + +@Component({ + selector: 'oib-external-source-list', + standalone: true, + imports: [NgIf, NgForOf, TranslateModule], + templateUrl: './external-source-list.component.html', + styleUrls: ['./external-source-list.component.scss'] +}) +export class ExternalSourceListComponent implements OnInit { + externalSources: Array = []; + + constructor( + private confirmationService: ConfirmationService, + private modalService: ModalService, + private notificationService: NotificationService, + private externalSourceService: ExternalSourceService + ) {} + + ngOnInit() { + this.externalSourceService.getExternalSources().subscribe(externalSources => { + this.externalSources = externalSources; + }); + } + + /** + * Open a modal to edit an external source + */ + openEditExternalSourceModal(externalSource: ExternalSourceDTO) { + const modalRef = this.modalService.open(EditExternalSourceModalComponent); + const component: EditExternalSourceModalComponent = modalRef.componentInstance; + component.prepareForEdition(externalSource); + this.refreshAfterEditExternalSourceModalClosed(modalRef, 'updated'); + } + + /** + * Open a modal to create an external source + */ + openCreationExternalSourceModal() { + const modalRef = this.modalService.open(EditExternalSourceModalComponent); + const component: EditExternalSourceModalComponent = modalRef.componentInstance; + component.prepareForCreation(); + this.refreshAfterEditExternalSourceModalClosed(modalRef, 'created'); + } + + /** + * Refresh the IP filter list when the external source is edited + */ + private refreshAfterEditExternalSourceModalClosed(modalRef: Modal, mode: 'created' | 'updated') { + modalRef.result.subscribe((ipFilter: ExternalSourceDTO) => { + this.externalSourceService.getExternalSources().subscribe(externalSources => { + this.externalSources = externalSources; + }); + this.notificationService.success(`engine.external-source.${mode}`, { + reference: ipFilter.reference + }); + }); + } + + /** + * Delete an IP Filter by its ID + */ + deleteExternalSource(externalSource: ExternalSourceDTO) { + this.confirmationService + .confirm({ + messageKey: 'engine.external-source.confirm-deletion', + interpolateParams: { reference: externalSource.reference } + }) + .pipe( + switchMap(() => { + return this.externalSourceService.deleteExternalSource(externalSource.id); + }) + ) + .subscribe(() => { + this.externalSourceService.getExternalSources().subscribe(externalSources => { + this.externalSources = externalSources; + }); + this.notificationService.success('engine.external-source.deleted', { + address: externalSource.reference + }); + }); + } +} diff --git a/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.html b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.html new file mode 100644 index 0000000000..6dd18de20c --- /dev/null +++ b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.html @@ -0,0 +1,39 @@ +

+ +

+ +
+ + + + + + + + + + + + + + + +
{{ ipFilter.address }}{{ ipFilter.description }} +
+ + + + +
+
+
+ +
+
diff --git a/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.scss b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.spec.ts b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.spec.ts new file mode 100644 index 0000000000..8daee1747e --- /dev/null +++ b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.spec.ts @@ -0,0 +1,77 @@ +import { TestBed } from '@angular/core/testing'; + +import { IpFilterListComponent } from './ip-filter-list.component'; +import { provideTestingI18n } from '../../../i18n/mock-i18n'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { of } from 'rxjs'; +import { IpFilterService } from '../../services/ip-filter.service'; +import { IpFilterDTO } from '../../model/ip-filter.model'; + +class IpFilterListComponentTester extends ComponentTester { + constructor() { + super(IpFilterListComponent); + } + + get title() { + return this.element('h2')!; + } + + get addIpFilter() { + return this.button('#add-ip-filter')!; + } + + get noIpFilter() { + return this.element('#no-ip-filter'); + } + get ipFilters() { + return this.elements('tbody tr'); + } +} + +describe('IpFilterListComponent', () => { + let tester: IpFilterListComponentTester; + let ipFilterService: jasmine.SpyObj; + + beforeEach(() => { + ipFilterService = createMock(IpFilterService); + + TestBed.configureTestingModule({ + imports: [IpFilterListComponent], + providers: [provideTestingI18n(), { provide: IpFilterService, useValue: ipFilterService }] + }); + + tester = new IpFilterListComponentTester(); + }); + + it('should display a list of ip filters', () => { + const ipFilters: Array = [ + { + id: 'id1', + address: 'http://localhost', + description: 'My IP filter 1' + }, + { + id: 'id2', + address: 'http://localhost', + description: 'My IP filter 2' + } + ]; + + ipFilterService.getIpFilters.and.returnValue(of(ipFilters)); + tester.detectChanges(); + + expect(tester.title).toContainText('IP filter list'); + expect(tester.ipFilters.length).toEqual(2); + expect(tester.ipFilters[0].elements('td').length).toEqual(3); + expect(tester.ipFilters[1].elements('td')[0]).toContainText('http://localhost'); + expect(tester.ipFilters[1].elements('td')[1]).toContainText('My IP filter 2'); + }); + + it('should display an empty list', () => { + ipFilterService.getIpFilters.and.returnValue(of([])); + tester.detectChanges(); + + expect(tester.title).toContainText('IP filter list'); + expect(tester.noIpFilter).toContainText('No IP filter'); + }); +}); diff --git a/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.ts b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.ts new file mode 100644 index 0000000000..faf734ac80 --- /dev/null +++ b/frontend/src/app/engine/ip-filter-list/ip-filter-list.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { NgForOf, NgIf } from '@angular/common'; +import { switchMap } from 'rxjs'; +import { Modal, ModalService } from '../../components/shared/modal.service'; +import { ConfirmationService } from '../../components/shared/confirmation.service'; +import { NotificationService } from '../../components/shared/notification.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { IpFilterService } from '../../services/ip-filter.service'; +import { IpFilterDTO } from '../../model/ip-filter.model'; +import { EditIpFilterModalComponent } from '../edit-ip-filter-modal/edit-ip-filter-modal.component'; + +@Component({ + selector: 'oib-ip-filter-list', + standalone: true, + imports: [NgIf, NgForOf, TranslateModule], + templateUrl: './ip-filter-list.component.html', + styleUrls: ['./ip-filter-list.component.scss'] +}) +export class IpFilterListComponent implements OnInit { + ipFilters: Array = []; + + constructor( + private confirmationService: ConfirmationService, + private modalService: ModalService, + private notificationService: NotificationService, + private ipFilterService: IpFilterService + ) {} + + ngOnInit() { + this.ipFilterService.getIpFilters().subscribe(ipFilterList => { + this.ipFilters = ipFilterList; + }); + } + + /** + * Open a modal to edit an IP filter + */ + openEditIpFilterModal(ipFilter: IpFilterDTO) { + const modalRef = this.modalService.open(EditIpFilterModalComponent); + const component: EditIpFilterModalComponent = modalRef.componentInstance; + component.prepareForEdition(ipFilter); + this.refreshAfterEditIpFilterModalClosed(modalRef, 'updated'); + } + + /** + * Open a modal to create an IP filter + */ + openCreationIpFilterModal() { + const modalRef = this.modalService.open(EditIpFilterModalComponent); + const component: EditIpFilterModalComponent = modalRef.componentInstance; + component.prepareForCreation(); + this.refreshAfterEditIpFilterModalClosed(modalRef, 'created'); + } + + /** + * Refresh the IP filter list when the IP filter is edited + */ + private refreshAfterEditIpFilterModalClosed(modalRef: Modal, mode: 'created' | 'updated') { + modalRef.result.subscribe((ipFilter: IpFilterDTO) => { + this.ipFilterService.getIpFilters().subscribe(ipFilters => { + this.ipFilters = ipFilters; + }); + this.notificationService.success(`engine.ip-filter.${mode}`, { + address: ipFilter.address + }); + }); + } + + /** + * Delete an IP Filter by its ID + */ + deleteIpFilter(ipFilter: IpFilterDTO) { + this.confirmationService + .confirm({ + messageKey: 'engine.ip-filter.confirm-deletion', + interpolateParams: { address: ipFilter.address } + }) + .pipe( + switchMap(() => { + return this.ipFilterService.deleteIpFilter(ipFilter.id); + }) + ) + .subscribe(() => { + this.ipFilterService.getIpFilters().subscribe(ipFilters => { + this.ipFilters = ipFilters; + }); + this.notificationService.success('engine.ip-filter.deleted', { + address: ipFilter.address + }); + }); + } +} diff --git a/frontend/src/app/engine/proxy-list/proxy-list.component.html b/frontend/src/app/engine/proxy-list/proxy-list.component.html index ccf5023a11..c1705f2754 100644 --- a/frontend/src/app/engine/proxy-list/proxy-list.component.html +++ b/frontend/src/app/engine/proxy-list/proxy-list.component.html @@ -1,5 +1,5 @@

- diff --git a/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.html b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.html new file mode 100644 index 0000000000..aa360083fb --- /dev/null +++ b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.html @@ -0,0 +1,41 @@ +

+ +

+ +
+ + + + + + + + + + + + + + + + + +
{{ scanMode.name }}{{ scanMode.description }}{{ scanMode.cron }} +
+ + + + +
+
+
+ +
+
diff --git a/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.scss b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.spec.ts b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.spec.ts new file mode 100644 index 0000000000..a5968d3322 --- /dev/null +++ b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.spec.ts @@ -0,0 +1,80 @@ +import { TestBed } from '@angular/core/testing'; + +import { ScanModeListComponent } from './scan-mode-list.component'; +import { provideTestingI18n } from '../../../i18n/mock-i18n'; +import { ComponentTester, createMock } from 'ngx-speculoos'; +import { of } from 'rxjs'; +import { ScanModeService } from '../../services/scan-mode.service'; +import { ScanModeDTO } from '../../model/scan-mode.model'; + +class ScanModeListComponentTester extends ComponentTester { + constructor() { + super(ScanModeListComponent); + } + + get title() { + return this.element('h2')!; + } + + get addScanMode() { + return this.button('#add-scan-mode')!; + } + + get noScanMode() { + return this.element('#no-scan-mode'); + } + get scanModes() { + return this.elements('tbody tr'); + } +} + +describe('ScanModeListComponent', () => { + let tester: ScanModeListComponentTester; + let scanModeService: jasmine.SpyObj; + + beforeEach(() => { + scanModeService = createMock(ScanModeService); + + TestBed.configureTestingModule({ + imports: [ScanModeListComponent], + providers: [provideTestingI18n(), { provide: ScanModeService, useValue: scanModeService }] + }); + + tester = new ScanModeListComponentTester(); + }); + + it('should display a list of scan modes', () => { + const scanModes: Array = [ + { + id: 'id1', + name: 'scanMode1', + description: 'My Scan Mode 1', + cron: '* * * * * *' + }, + { + id: 'id2', + name: 'scanMode2', + description: 'My Scan Mode 2', + cron: '* * * * * *' + } + ]; + + scanModeService.getScanModes.and.returnValue(of(scanModes)); + tester.detectChanges(); + + expect(tester.title).toContainText('Scan mode list'); + expect(tester.scanModes.length).toEqual(2); + expect(tester.scanModes[0].elements('td').length).toEqual(4); + expect(tester.scanModes[1].elements('td')[0]).toContainText('scanMode2'); + expect(tester.scanModes[1].elements('td')[1]).toContainText('My Scan Mode 2'); + expect(tester.scanModes[1].elements('td')[2]).toContainText('* * * * * *'); + }); + + it('should display an empty list', () => { + scanModeService.getScanModes.and.returnValue(of([])); + tester.detectChanges(); + + expect(tester.title).toContainText('Scan mode list'); + expect(tester.noScanMode).toContainText('No scan mode'); + }); +}); diff --git a/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.ts b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.ts new file mode 100644 index 0000000000..3ecc063574 --- /dev/null +++ b/frontend/src/app/engine/scan-mode-list/scan-mode-list.component.ts @@ -0,0 +1,92 @@ +import { Component, OnInit } from '@angular/core'; +import { NgForOf, NgIf } from '@angular/common'; +import { switchMap } from 'rxjs'; +import { Modal, ModalService } from '../../components/shared/modal.service'; +import { ConfirmationService } from '../../components/shared/confirmation.service'; +import { NotificationService } from '../../components/shared/notification.service'; +import { TranslateModule } from '@ngx-translate/core'; +import { ScanModeDTO } from '../../model/scan-mode.model'; +import { ScanModeService } from '../../services/scan-mode.service'; +import { EditScanModeModalComponent } from '../edit-scan-mode-modal/edit-scan-mode-modal.component'; + +@Component({ + selector: 'oib-scan-mode-list', + standalone: true, + imports: [NgIf, NgForOf, TranslateModule], + templateUrl: './scan-mode-list.component.html', + styleUrls: ['./scan-mode-list.component.scss'] +}) +export class ScanModeListComponent implements OnInit { + scanModes: Array = []; + + constructor( + private confirmationService: ConfirmationService, + private modalService: ModalService, + private notificationService: NotificationService, + private scanModeService: ScanModeService + ) {} + + ngOnInit() { + this.scanModeService.getScanModes().subscribe(scanModeList => { + this.scanModes = scanModeList; + }); + } + + /** + * Open a modal to edit a scan mode + */ + openEditScanModeModal(scanMode: ScanModeDTO) { + const modalRef = this.modalService.open(EditScanModeModalComponent); + const component: EditScanModeModalComponent = modalRef.componentInstance; + component.prepareForEdition(scanMode); + this.refreshAfterEditScanModeModalClosed(modalRef, 'updated'); + } + + /** + * Open a modal to create a scan mode + */ + openCreationScanModeModal() { + const modalRef = this.modalService.open(EditScanModeModalComponent); + const component: EditScanModeModalComponent = modalRef.componentInstance; + component.prepareForCreation(); + this.refreshAfterEditScanModeModalClosed(modalRef, 'created'); + } + + /** + * Refresh the scan mode list when the scan mode is edited + */ + private refreshAfterEditScanModeModalClosed(modalRef: Modal, mode: 'created' | 'updated') { + modalRef.result.subscribe((scanMode: ScanModeDTO) => { + this.scanModeService.getScanModes().subscribe(scanModes => { + this.scanModes = scanModes; + }); + this.notificationService.success(`engine.scan-mode.${mode}`, { + name: scanMode.name + }); + }); + } + + /** + * Delete a scan mode by its ID + */ + deleteScanMode(scanMode: ScanModeDTO) { + this.confirmationService + .confirm({ + messageKey: 'engine.scan-mode.confirm-deletion', + interpolateParams: { name: scanMode.name } + }) + .pipe( + switchMap(() => { + return this.scanModeService.deleteScanMode(scanMode.id); + }) + ) + .subscribe(() => { + this.scanModeService.getScanModes().subscribe(scanModes => { + this.scanModes = scanModes; + }); + this.notificationService.success('engine.scan-mode.deleted', { + name: scanMode.name + }); + }); + } +} diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index a7d953ccde..cc138cd0da 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -138,8 +138,49 @@ "address": "Address", "username": "Username", "password": "Password" + }, + "scan-mode": { + "list": "Scan mode list", + "title-create": "Create a scan mode", + "title-edit": "Edit scan mode", + "confirm-deletion": "Are you sure you want to delete the scan mode {{ name }}? Beforehand, be sure it is not used.", + "updated": "Scan mode {{ name }} successfully updated", + "created": "Scan mode {{ name }} successfully created", + "deleted": "Scan mode {{ name }} deleted", + "add": "Add", + "none": "No scan mode", + "name": "Name", + "description": "Description", + "cron": "Cron" + }, + "ip-filter": { + "list": "IP filter list", + "title-create": "Create an IP filter", + "title-edit": "Edit IP filter", + "confirm-deletion": "Are you sure you want to delete the IP filter {{ address }}? Beforehand, be sure it is not used.", + "updated": "IP filter {{ address }} successfully updated", + "created": "IP filter {{ address }} successfully created", + "deleted": "IP filter {{ address }} deleted", + "add": "Add", + "none": "No IP filter", + "name": "Name", + "description": "Description", + "address": "Address" + }, + "external-source": { + "list": "External source list", + "title-create": "Create an external source", + "title-edit": "Edit external source", + "confirm-deletion": "Are you sure you want to delete the external source {{ reference }}? Beforehand, be sure it is not used.", + "updated": "External source {{ reference }} successfully updated", + "created": "External source {{ reference }} successfully created", + "deleted": "External source {{ reference }} deleted", + "add": "Add", + "none": "No external source", + "name": "Name", + "description": "Description", + "reference": "Reference" } - }, "south-list": { "title": "South list"