From f7c3d53ba2ed5f0dec14e9707cdf794cd7dcace6 Mon Sep 17 00:00:00 2001 From: ibering Date: Wed, 24 Sep 2025 11:29:31 +0200 Subject: [PATCH 01/48] #ITC-3595 Import Module: Add support for FlowChief (initial commit) --- .../external-monitorings-add.component.ts | 81 ++++++++++--------- .../external-monitorings-edit.component.ts | 5 +- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts index a57301fdd..075449971 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts @@ -2,19 +2,18 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestro import { BackButtonDirective } from '../../../../../directives/back-button.directive'; import { TranslocoDirective, TranslocoService } from '@jsverse/transloco'; import { - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - ContainerComponent, - FormControlDirective, - FormDirective, - FormLabelDirective, - NavComponent, - NavItemComponent + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + ContainerComponent, + FormControlDirective, + FormDirective, + FormLabelDirective, + NavComponent, + NavItemComponent } from '@coreui/angular'; -import { CoreuiComponent } from '../../../../../layouts/coreui/coreui.component'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { FormErrorDirective } from '../../../../../layouts/coreui/form-error.directive'; import { FormFeedbackComponent } from '../../../../../layouts/coreui/form-feedback/form-feedback.component'; @@ -58,33 +57,33 @@ import { @Component({ selector: 'oitc-external-monitorings-add', imports: [ - BackButtonDirective, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FaIconComponent, - FormControlDirective, - FormDirective, - FormErrorDirective, - FormFeedbackComponent, - FormLabelDirective, - FormsModule, - NavComponent, - NavItemComponent, - PermissionDirective, - ReactiveFormsModule, - RequiredIconComponent, - TranslocoDirective, - XsButtonDirective, - RouterLink, - NgIf, - SelectComponent, - ContainerComponent, - NgForOf, - DynamicalFormFieldsComponent -], + BackButtonDirective, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FaIconComponent, + FormControlDirective, + FormDirective, + FormErrorDirective, + FormFeedbackComponent, + FormLabelDirective, + FormsModule, + NavComponent, + NavItemComponent, + PermissionDirective, + ReactiveFormsModule, + RequiredIconComponent, + TranslocoDirective, + XsButtonDirective, + RouterLink, + NgIf, + SelectComponent, + ContainerComponent, + NgForOf, + DynamicalFormFieldsComponent + ], templateUrl: './external-monitorings-add.component.html', styleUrl: './external-monitorings-add.component.css', changeDetection: ChangeDetectionStrategy.OnPush @@ -105,6 +104,10 @@ export class ExternalMonitoringsAddComponent implements OnInit, OnDestroy { public formFields?: DynamicalFormFields; protected readonly ExternalMonitoringTypes = [ + { + key: 'flowchief', + value: this.TranslocoService.translate('FlowChief') + }, { key: 'icinga2', value: this.TranslocoService.translate('Icinga 2') diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts index 168947546..a4de2f344 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts @@ -13,7 +13,6 @@ import { NavComponent, NavItemComponent } from '@coreui/angular'; -import { CoreuiComponent } from '../../../../../layouts/coreui/coreui.component'; import { DynamicalFormFieldsComponent } from '../../../../../components/dynamical-form-fields/dynamical-form-fields.component'; @@ -96,6 +95,10 @@ export class ExternalMonitoringsEditComponent implements OnInit, OnDestroy { public formFields?: DynamicalFormFields; protected readonly ExternalMonitoringTypes = [ + { + key: 'flowchief', + value: this.TranslocoService.translate('FlowChief') + }, { key: 'icinga2', value: this.TranslocoService.translate('Icinga 2') From 93180ae3758cd1a6a75096b49867c4d6059e99c9 Mon Sep 17 00:00:00 2001 From: nook24 Date: Thu, 25 Sep 2025 08:56:18 +0200 Subject: [PATCH 02/48] ITC-3595 Refactor External Monitoring Systems to use Enum for system_type --- .../external-monitoring-systems.enum.ts | 6 +++++ .../external-monitorings-add.component.html | 2 +- .../external-monitorings-add.component.ts | 24 +++++++++++++------ .../external-monitorings-edit.component.html | 2 +- .../external-monitorings-edit.component.ts | 11 +++++---- .../external-monitorings.interface.ts | 19 +++++++++++---- 6 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 src/app/modules/import_module/pages/externalmonitorings/external-monitoring-systems.enum.ts diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitoring-systems.enum.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitoring-systems.enum.ts new file mode 100644 index 000000000..5f6858a82 --- /dev/null +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitoring-systems.enum.ts @@ -0,0 +1,6 @@ +export enum ExternalMonitoringSystems { + Icinga2 = 'icinga2', + OpManager = 'opmanager', + PRTG = 'prtg', + FlowChief = 'flowchief' +} diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.html b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.html index 540d24b3d..7f7545bb8 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.html @@ -94,7 +94,7 @@
{{ t('Create new external monitoring system') }}
[showClear]="false">
- @if (post.system_type === 'icinga2') { + @if (post.system_type === ExternalMonitoringSystems.Icinga2) { {{ t('Synchronize status information from Icinga 2 with openITCOCKPIT.') }} }
diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts index 075449971..ffa133549 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-add/external-monitorings-add.component.ts @@ -31,6 +31,7 @@ import { SelectKeyValue } from '../../../../../layouts/primeng/select.interface' import { ContainersLoadContainersByStringParams } from '../../../../../pages/containers/containers.interface'; import { ExternalMonitoringConfig, + ExternalMonitoringConfigFlowChief, ExternalMonitoringConfigIcinga2, ExternalMonitoringConfigOpmanager, ExternalMonitoringConfigPrtg, @@ -53,6 +54,7 @@ import { DynamicalFormFields } from '../../../../../components/dynamical-form-fi import { DynamicalFormFieldsComponent } from '../../../../../components/dynamical-form-fields/dynamical-form-fields.component'; +import { ExternalMonitoringSystems } from '../external-monitoring-systems.enum'; @Component({ selector: 'oitc-external-monitorings-add', @@ -105,19 +107,19 @@ export class ExternalMonitoringsAddComponent implements OnInit, OnDestroy { protected readonly ExternalMonitoringTypes = [ { - key: 'flowchief', + key: ExternalMonitoringSystems.FlowChief, value: this.TranslocoService.translate('FlowChief') }, { - key: 'icinga2', + key: ExternalMonitoringSystems.Icinga2, value: this.TranslocoService.translate('Icinga 2') }, { - key: 'opmanager', + key: ExternalMonitoringSystems.OpManager, value: this.TranslocoService.translate('ManageEngine OpManager') }, { - key: 'prtg', + key: ExternalMonitoringSystems.PRTG, value: this.TranslocoService.translate('Paessler PRTG System') } ]; @@ -185,18 +187,25 @@ export class ExternalMonitoringsAddComponent implements OnInit, OnDestroy { .subscribe((result: ExternalMonitoringConfig) => { this.errors = null; switch (this.post.system_type) { - case 'icinga2': + case ExternalMonitoringSystems.Icinga2: const icinga2 = result.config.config as ExternalMonitoringConfigIcinga2; this.post.json_data = icinga2; break; - case 'opmanager': + + case ExternalMonitoringSystems.OpManager: const opmanager = result.config.config as ExternalMonitoringConfigOpmanager; this.post.json_data = opmanager; break; - case 'prtg': + + case ExternalMonitoringSystems.PRTG: const prtg = result.config.config as ExternalMonitoringConfigPrtg; this.post.json_data = prtg; break; + + case ExternalMonitoringSystems.FlowChief: + const flowChief = result.config.config as ExternalMonitoringConfigFlowChief; + this.post.json_data = flowChief; + break; } this.formFields = result.config.formFields; @@ -207,4 +216,5 @@ export class ExternalMonitoringsAddComponent implements OnInit, OnDestroy { } protected readonly Object = Object; + protected readonly ExternalMonitoringSystems = ExternalMonitoringSystems; } diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html index d946b9eb4..22ca05dcc 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html @@ -100,7 +100,7 @@
[showClear]="false">
- @if (post.system_type === 'icinga2') { + @if (post.system_type === ExternalMonitoringSystems.Icinga2) { {{ t('Synchronize status information from Icinga 2 with openITCOCKPIT.') }} }
diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts index a4de2f344..0f92eb9d1 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts @@ -41,6 +41,7 @@ import { ExternalMonitoringConfig, ExternalMonitoringPost } from '../external-mo import { PermissionsService } from '../../../../../permissions/permissions.service'; import { SystemnameService } from '../../../../../services/systemname.service'; import { FormLoaderComponent } from '../../../../../layouts/primeng/loading/form-loader/form-loader.component'; +import { ExternalMonitoringSystems } from '../external-monitoring-systems.enum'; @Component({ @@ -96,19 +97,19 @@ export class ExternalMonitoringsEditComponent implements OnInit, OnDestroy { protected readonly ExternalMonitoringTypes = [ { - key: 'flowchief', + key: ExternalMonitoringSystems.FlowChief, value: this.TranslocoService.translate('FlowChief') }, { - key: 'icinga2', + key: ExternalMonitoringSystems.Icinga2, value: this.TranslocoService.translate('Icinga 2') }, { - key: 'opmanager', + key: ExternalMonitoringSystems.OpManager, value: this.TranslocoService.translate('ManageEngine OpManager') }, { - key: 'prtg', + key: ExternalMonitoringSystems.PRTG, value: this.TranslocoService.translate('Paessler PRTG System') } ]; @@ -184,4 +185,6 @@ export class ExternalMonitoringsEditComponent implements OnInit, OnDestroy { public ngOnDestroy(): void { this.subscriptions.unsubscribe(); } + + protected readonly ExternalMonitoringSystems = ExternalMonitoringSystems; } diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts index 210770f55..727a27f8d 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts @@ -1,6 +1,7 @@ import { PaginateOrScroll } from '../../../../layouts/coreui/paginator/paginator.interface'; import { DynamicalFormFields } from '../../../../components/dynamical-form-fields/dynamical-form-fields.interface'; import { SelectKeyValue } from '../../../../layouts/primeng/select.interface'; +import { ExternalMonitoringSystems } from './external-monitoring-systems.enum'; export interface ExternalMonitoringsIndexRoot extends PaginateOrScroll { externalMonitorings: ExternalMonitoring[] @@ -12,7 +13,7 @@ export interface ExternalMonitoring { name: string container_id: number description: string - system_type: string + system_type: ExternalMonitoringSystems container: string allowEdit: boolean } @@ -22,7 +23,7 @@ export interface ExternalMonitoringPost { container_id: number | null name: string description: string - system_type: string + system_type: ExternalMonitoringSystems | '' json_data: any } @@ -58,7 +59,7 @@ export function getDefaultExternalMonitoringsIndexParams(): ExternalMonitoringsI export interface ExternalMonitoringConfig { config: { - config: ExternalMonitoringConfigIcinga2 | ExternalMonitoringConfigOpmanager | ExternalMonitoringConfigPrtg + config: ExternalMonitoringConfigIcinga2 | ExternalMonitoringConfigOpmanager | ExternalMonitoringConfigPrtg | ExternalMonitoringConfigFlowChief formFields: DynamicalFormFields } } @@ -93,6 +94,16 @@ export interface ExternalMonitoringConfigPrtg { include_channels: number } -export interface ExternalMonitoringsAsList{ +export interface ExternalMonitoringConfigFlowChief { + api_url: string + api_user: string + api_password: string + use_proxy: number + ignore_ssl_certificate: number + node_ids: number[] + is_recursive: number +} + +export interface ExternalMonitoringsAsList { externalMonitorings: SelectKeyValue[] } From 36a9353e56198ff2b681ca914b3f0fbed65cf64d Mon Sep 17 00:00:00 2001 From: nook24 Date: Thu, 25 Sep 2025 17:07:53 +0200 Subject: [PATCH 03/48] ITC-3595 Add FlowChief node selection for external monitoring systems --- .../import_module/import_module.routes.ts | 3 + .../external-monitorings-edit.component.html | 18 ++ .../external-monitorings-edit.component.ts | 12 +- .../external-monitorings-index.component.html | 8 + .../external-monitorings-index.component.ts | 6 +- .../external-monitorings.interface.ts | 40 ++++- .../external-monitorings.service.ts | 41 ++++- .../flowchief-node-selection.component.css | 0 .../flowchief-node-selection.component.html | 119 ++++++++++++ ...flowchief-node-selection.component.spec.ts | 23 +++ .../flowchief-node-selection.component.ts | 170 ++++++++++++++++++ 11 files changed, 424 insertions(+), 16 deletions(-) create mode 100644 src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.css create mode 100644 src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html create mode 100644 src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.spec.ts create mode 100644 src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts diff --git a/src/app/modules/import_module/import_module.routes.ts b/src/app/modules/import_module/import_module.routes.ts index 3834e3ceb..3c4a41467 100644 --- a/src/app/modules/import_module/import_module.routes.ts +++ b/src/app/modules/import_module/import_module.routes.ts @@ -33,6 +33,9 @@ export const importModuleRoutes: Routes = [{ }, { path: 'import_module/ExternalMonitorings/edit/:id', loadComponent: () => import('./pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component').then(m => m.ExternalMonitoringsEditComponent) +}, { + path: 'import_module/ExternalMonitorings/flowchiefNodeSelection/:id', + loadComponent: () => import('./pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component').then(m => m.FlowchiefNodeSelectionComponent) }, { path: 'import_module/ImportedFiles/index', loadComponent: () => import('./pages/importedfiles/imported-files-index/imported-files-index.component').then(m => m.ImportedFilesIndexComponent) diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html index 22ca05dcc..caab22ec9 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.html @@ -123,6 +123,24 @@

[(ngModel)]="post.json_data[formField['ngModel']]"> + + @if (post.system_type === ExternalMonitoringSystems.FlowChief) { + + + + +
+ {{ t('FlowChief Nodes from the Plantexplorer can be assigend') }} + + {{ t('here') }}. + +
+
+
+
+ } + } diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts index 0f92eb9d1..e774d2e3a 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-edit/external-monitorings-edit.component.ts @@ -1,17 +1,20 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestroy, OnInit } from '@angular/core'; import { BackButtonDirective } from '../../../../../directives/back-button.directive'; import { + AlertComponent, CardBodyComponent, CardComponent, CardFooterComponent, CardHeaderComponent, CardTitleDirective, + ColComponent, ContainerComponent, FormControlDirective, FormDirective, FormLabelDirective, NavComponent, - NavItemComponent + NavItemComponent, + RowComponent } from '@coreui/angular'; import { DynamicalFormFieldsComponent @@ -73,7 +76,10 @@ import { ExternalMonitoringSystems } from '../external-monitoring-systems.enum'; TranslocoDirective, XsButtonDirective, RouterLink, - FormLoaderComponent + FormLoaderComponent, + RowComponent, + ColComponent, + AlertComponent ], templateUrl: './external-monitorings-edit.component.html', styleUrl: './external-monitorings-edit.component.css', @@ -150,7 +156,7 @@ export class ExternalMonitoringsEditComponent implements OnInit, OnDestroy { this.subscriptions.add(this.ExternalMonitoringsService.getEdit(this.id) .subscribe((result) => { //Fire on page load - this.post = result.externalMonitoring; + this.post = result; this.cdr.markForCheck(); this.loadContainers(); this.loadConfigFieldsBySystemType(); diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.html b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.html index 15feca3b9..b1628e394 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.html @@ -174,6 +174,14 @@

{{ t('Edit') }} + @if (externalMonitoring.system_type === ExternalMonitoringSystems.FlowChief && externalMonitoring.allowEdit) { + + + {{ t('Select FlowChef Nodes') }} + + } diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.ts index ba1fc50e4..06a0558ab 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings-index/external-monitorings-index.component.ts @@ -17,7 +17,6 @@ import { RowComponent, TableDirective } from '@coreui/angular'; -import { CoreuiComponent } from '../../../../../layouts/coreui/coreui.component'; import { DebounceDirective } from '../../../../../directives/debounce.directive'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -52,6 +51,7 @@ import { import { SelectAllComponent } from '../../../../../layouts/coreui/select-all/select-all.component'; import { DELETE_SERVICE_TOKEN } from '../../../../../tokens/delete-injection.token'; import { IndexPage } from '../../../../../pages.interface'; +import { ExternalMonitoringSystems } from '../external-monitoring-systems.enum'; @Component({ selector: 'oitc-external-monitorings-index', @@ -94,7 +94,7 @@ import { IndexPage } from '../../../../../pages.interface'; TableDirective ], providers: [ - { provide: DELETE_SERVICE_TOKEN, useClass: ExternalMonitoringsService } // Inject the ExternalMonitoringsService into the DeleteAllModalComponent + {provide: DELETE_SERVICE_TOKEN, useClass: ExternalMonitoringsService} // Inject the ExternalMonitoringsService into the DeleteAllModalComponent ], templateUrl: './external-monitorings-index.component.html', styleUrl: './external-monitorings-index.component.css', @@ -204,4 +204,6 @@ export class ExternalMonitoringsIndexComponent implements OnInit, OnDestroy, Ind this.load(); } } + + protected readonly ExternalMonitoringSystems = ExternalMonitoringSystems; } diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts index 727a27f8d..d3b8664a5 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts @@ -27,10 +27,6 @@ export interface ExternalMonitoringPost { json_data: any } -export interface ExternalMonitoringGet { - externalMonitoring: ExternalMonitoringPost -} - export interface ExternalMonitoringsIndexParams { angular: true, scroll: boolean, @@ -100,10 +96,42 @@ export interface ExternalMonitoringConfigFlowChief { api_password: string use_proxy: number ignore_ssl_certificate: number - node_ids: number[] - is_recursive: number + //node_ids: number[] + //is_recursive: number } export interface ExternalMonitoringsAsList { externalMonitorings: SelectKeyValue[] } + + +export interface ExternalMonitoringWithFlowchiefNodesMembershipPost extends ExternalMonitoringPost { + flowchief_nodes_membership: FlowchiefNodesMembership[] +} + +export interface FlowchiefNodesMembership { + id?: number + external_monitoring_id: number + name?: string + path: string + external_flowchief_node_id?: number + external_flowchief_node_parent_id?: number + tag?: string + created?: string + modified?: string + _joinData: { + id?: number + flowchief_node_id: number + external_monitoring_id: number + is_recursive: boolean + } +} + +/********************** + * Global action * + **********************/ +export interface FlowchiefNodesByStringParams { + externalMonitoringId: number, + 'filter[FlowchiefNodes.name]': string, + 'selected[]': number[], +} diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts index 9b2915f97..be11dbaae 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts @@ -1,16 +1,18 @@ import { inject, Injectable } from '@angular/core'; import { ExternalMonitoringConfig, - ExternalMonitoringGet, ExternalMonitoringPost, ExternalMonitoringsIndexParams, - ExternalMonitoringsIndexRoot + ExternalMonitoringsIndexRoot, + ExternalMonitoringWithFlowchiefNodesMembershipPost, + FlowchiefNodesByStringParams } from './external-monitorings.interface'; import { catchError, map, Observable, of } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { PROXY_PATH } from '../../../../tokens/proxy-path.token'; import { DeleteAllItem } from '../../../../layouts/coreui/delete-all-modal/delete-all.interface'; import { GenericIdResponse, GenericResponseWrapper, GenericValidationError } from '../../../../generic-responses'; +import { SelectKeyValue } from '../../../../layouts/primeng/select.interface'; @Injectable({ providedIn: 'root' @@ -38,15 +40,17 @@ export class ExternalMonitoringsService { return this.http.post(`${proxyPath}/import_module/external_monitorings/loadConfigFieldsBySystemType/${system_type}.json?angular=true`, {}); } - public getEdit(id: number): Observable { + public getEdit(id: number): Observable { const proxyPath = this.proxyPath; - return this.http.get(`${proxyPath}/import_module/external_monitorings/edit/${id}.json`, { + return this.http.get<{ + externalMonitoring: ExternalMonitoringPost + }>(`${proxyPath}/import_module/external_monitorings/edit/${id}.json`, { params: { angular: true } }).pipe( map(data => { - return data; + return data.externalMonitoring; }) ); } @@ -107,4 +111,31 @@ export class ExternalMonitoringsService { const proxyPath = this.proxyPath; return this.http.post(`${proxyPath}/import_module/external_monitorings/delete/${item.id}.json?angular=true`, {}); } + + /*************************************** + * flowchiefNodeSelection action * + ***************************************/ + public getFlowchiefNodeSelection(externalMonitoringId: number): Observable { + const proxyPath = this.proxyPath; + return this.http.get<{ + externalMonitoring: ExternalMonitoringWithFlowchiefNodesMembershipPost + }>(`${proxyPath}/import_module/external_monitorings/flowchiefNodeSelection/${externalMonitoringId}.json`).pipe( + map(data => { + return data.externalMonitoring; + }) + ); + } + + public loadFlowchiefNodesByString(params: FlowchiefNodesByStringParams): Observable { + const proxyPath = this.proxyPath; + return this.http.get<{ + nodes: SelectKeyValue[] + }>(`${proxyPath}/import_module/external_monitorings/loadFlowchiefNodesByString.json`, { + params: params as {} + }).pipe( + map(data => { + return data.nodes; + }) + ) + } } diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.css b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html new file mode 100644 index 000000000..501a5b96f --- /dev/null +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html @@ -0,0 +1,119 @@ + + + + + + @if (post) { +
+ + +
{{ t('Select FlowChief Nodes') }}
+ + + + + +
+ + +
+ + + +
+ {{ t('openITCOCKPIT will import all Process Variables from the selected nodes.') }} +
+ {{ t('In case the list is empty, execute the command') }} + oitc import_module.flowchief_import_nodes + --external-monitoring-system-id {{ post.id }} + {{ t('on the openITCOCKPIT server to get the list of available nodes.') }} +
+ +
+ +
+ + @for (nodeMembership of post.flowchief_nodes_membership; track $index) { +
+ + {{ nodeMembership.path }} + + + + + + +
+ } + +
+ +
+ + + + + +
+
+ } +
+ diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.spec.ts b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.spec.ts new file mode 100644 index 000000000..38db1197f --- /dev/null +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FlowchiefNodeSelectionComponent } from './flowchief-node-selection.component'; + +describe('FlowchiefNodeSelectionComponent', () => { + let component: FlowchiefNodeSelectionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FlowchiefNodeSelectionComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FlowchiefNodeSelectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts new file mode 100644 index 000000000..db04b5db1 --- /dev/null +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts @@ -0,0 +1,170 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestroy, OnInit } from '@angular/core'; +import { NotyService } from '../../../../../layouts/coreui/noty.service'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { Subscription } from 'rxjs'; +import { ExternalMonitoringsService } from '../external-monitorings.service'; +import { HistoryService } from '../../../../../history.service'; +import { FormFeedbackComponent } from '../../../../../layouts/coreui/form-feedback/form-feedback.component'; +import { + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FormCheckComponent, + FormCheckInputDirective, + FormCheckLabelDirective, + FormDirective, + FormLabelDirective, + NavComponent, + NavItemComponent +} from '@coreui/angular'; +import { MultiSelectComponent } from '../../../../../layouts/primeng/multi-select/multi-select/multi-select.component'; +import { TranslocoDirective } from '@jsverse/transloco'; +import { BackButtonDirective } from '../../../../../directives/back-button.directive'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { PermissionDirective } from '../../../../../permissions/permission.directive'; +import { XsButtonDirective } from '../../../../../layouts/coreui/xsbutton-directive/xsbutton.directive'; +import { GenericValidationError } from '../../../../../generic-responses'; +import { SelectKeyValue } from '../../../../../layouts/primeng/select.interface'; +import { FormLoaderComponent } from '../../../../../layouts/primeng/loading/form-loader/form-loader.component'; +import { + ExternalMonitoringWithFlowchiefNodesMembershipPost, + FlowchiefNodesByStringParams, + FlowchiefNodesMembership +} from '../external-monitorings.interface'; + +@Component({ + selector: 'oitc-flowchief-node-selection', + imports: [ + FormFeedbackComponent, + FormLabelDirective, + MultiSelectComponent, + TranslocoDirective, + BackButtonDirective, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FaIconComponent, + FormDirective, + FormsModule, + NavComponent, + NavItemComponent, + PermissionDirective, + ReactiveFormsModule, + XsButtonDirective, + RouterLink, + FormLoaderComponent, + FormCheckComponent, + FormCheckInputDirective, + FormCheckLabelDirective + ], + templateUrl: './flowchief-node-selection.component.html', + styleUrl: './flowchief-node-selection.component.css', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FlowchiefNodeSelectionComponent implements OnInit, OnDestroy { + + public post?: ExternalMonitoringWithFlowchiefNodesMembershipPost; + public selectedNodes: number[] = []; + public flowchiefNodes: SelectKeyValue[] = []; + public errors: GenericValidationError | null = null; + + + private subscriptions: Subscription = new Subscription(); + + private readonly ExternalMonitoringsService = inject(ExternalMonitoringsService); + private readonly notyService = inject(NotyService); + private readonly HistoryService: HistoryService = inject(HistoryService); + private readonly router: Router = inject(Router); + private readonly route: ActivatedRoute = inject(ActivatedRoute); + private cdr = inject(ChangeDetectorRef); + + public ngOnInit() { + this.route.queryParams.subscribe(params => { + const id = Number(this.route.snapshot.paramMap.get('id')); + this.loadExternalMonitoringFlowchiefConfig(id); + }); + } + + public ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + + public loadExternalMonitoringFlowchiefConfig(id: number) { + this.subscriptions.add(this.ExternalMonitoringsService.getFlowchiefNodeSelection(id).subscribe(response => { + this.post = response; + this.selectedNodes = response.flowchief_nodes_membership.map(item => item._joinData.flowchief_node_id); + + this.loadFlowchiefNodes(''); + this.cdr.markForCheck(); + })); + } + + public loadFlowchiefNodes = (searchString: string): void => { + const params: FlowchiefNodesByStringParams = { + externalMonitoringId: this.post?.id || 0, + 'filter[FlowchiefNodes.name]': searchString, + 'selected[]': this.selectedNodes + } + + this.subscriptions.add(this.ExternalMonitoringsService.loadFlowchiefNodesByString(params) + .subscribe((result) => { + this.flowchiefNodes = result; + this.cdr.markForCheck(); + }) + ); + }; + + public updateNodesMembership() { + if (!this.post) { + return; + } + + // Cleanup if a node got deselected + const flowchief_nodes_membership: FlowchiefNodesMembership[] = []; + const alreadyInMembership: number[] = []; + + this.post.flowchief_nodes_membership.forEach((flowchief_node) => { + if (this.selectedNodes.includes(flowchief_node._joinData.flowchief_node_id)) { + flowchief_nodes_membership.push(flowchief_node); + } + alreadyInMembership.push(flowchief_node._joinData.flowchief_node_id); + }); + + // All selected nodes to membership (so we can sret is_recursive properly) + this.selectedNodes.forEach((nodeId) => { + let externalMonitoringId = 0; + if (this.post && this.post.id) { + // This is just to make TypeScript happy + externalMonitoringId = this.post.id; + } + + if (!alreadyInMembership.includes(nodeId)) { + + const node = this.flowchiefNodes.find(n => n.key === nodeId); + if (node) { + flowchief_nodes_membership.push({ + external_monitoring_id: externalMonitoringId, + path: node.value, + _joinData: { + flowchief_node_id: nodeId, + external_monitoring_id: externalMonitoringId, + is_recursive: false + } + }); + } + } + }); + + this.post.flowchief_nodes_membership = flowchief_nodes_membership; + } + + public submit() { + + } + +} From da88101323c596efed2a89b1c214565ec91e135d Mon Sep 17 00:00:00 2001 From: ibering Date: Fri, 26 Sep 2025 10:19:02 +0200 Subject: [PATCH 04/48] #ITC-3595 Import Module: Add support for FlowChief: External monitorings (style issues: flowchiefNodeSelection) --- .../flowchief-node-selection.component.html | 12 ++++++++---- .../flowchief-node-selection.component.ts | 7 +++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html index 501a5b96f..ccbf7317d 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html @@ -77,8 +77,13 @@
{{ t('Select FlowChief Nodes') }}
@for (nodeMembership of post.flowchief_nodes_membership; track $index) { -
- +
+ @if (nodeMembership._joinData.is_recursive) { + + } @else { + + } {{ nodeMembership.path }} {{ t('Select FlowChief Nodes') }}
@@ -116,4 +121,3 @@
{{ t('Select FlowChief Nodes') }}
} - diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts index db04b5db1..a7a7e0587 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts @@ -17,7 +17,7 @@ import { FormDirective, FormLabelDirective, NavComponent, - NavItemComponent + NavItemComponent, TextColorDirective } from '@coreui/angular'; import { MultiSelectComponent } from '../../../../../layouts/primeng/multi-select/multi-select/multi-select.component'; import { TranslocoDirective } from '@jsverse/transloco'; @@ -34,6 +34,7 @@ import { FlowchiefNodesByStringParams, FlowchiefNodesMembership } from '../external-monitorings.interface'; +import { NgClass } from '@angular/common'; @Component({ selector: 'oitc-flowchief-node-selection', @@ -60,7 +61,9 @@ import { FormLoaderComponent, FormCheckComponent, FormCheckInputDirective, - FormCheckLabelDirective + FormCheckLabelDirective, + NgClass, + TextColorDirective ], templateUrl: './flowchief-node-selection.component.html', styleUrl: './flowchief-node-selection.component.css', From 76b85954837e9cc694ded417c1df21c57d763083 Mon Sep 17 00:00:00 2001 From: ibering Date: Fri, 26 Sep 2025 10:52:32 +0200 Subject: [PATCH 05/48] #ITC-3595 Import Module: Add support for FlowChief: External monitorings (style issues: flowchiefNodeSelection) --- .../flowchief-node-selection.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html index ccbf7317d..b38ebffae 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html @@ -77,7 +77,7 @@
{{ t('Select FlowChief Nodes') }}
@for (nodeMembership of post.flowchief_nodes_membership; track $index) { -
@if (nodeMembership._joinData.is_recursive) { From 2a8f2184d310df694c65a9c286c6a594872e7c87 Mon Sep 17 00:00:00 2001 From: nook24 Date: Fri, 26 Sep 2025 11:35:10 +0200 Subject: [PATCH 06/48] ITC-3595 Implement submit --- .../external-monitorings.service.ts | 21 ++++++++++++ .../flowchief-node-selection.component.ts | 34 +++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts index be11dbaae..2bd505eee 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.service.ts @@ -126,6 +126,27 @@ export class ExternalMonitoringsService { ); } + public editFlowchiefNodeSelection(externalMonitoring: ExternalMonitoringWithFlowchiefNodesMembershipPost): Observable { + const proxyPath = this.proxyPath; + return this.http.post(`${proxyPath}/import_module/external_monitorings/flowchiefNodeSelection/${externalMonitoring.id}.json`, externalMonitoring) + .pipe( + map(data => { + // Return true on 200 Ok + return { + success: true, + data: data.externalMonitoring as GenericIdResponse + }; + }), + catchError((error: any) => { + const err = error.error.error as GenericValidationError; + return of({ + success: false, + data: err + }); + }) + ); + } + public loadFlowchiefNodesByString(params: FlowchiefNodesByStringParams): Observable { const proxyPath = this.proxyPath; return this.http.get<{ diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts index a7a7e0587..b067d0a59 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.ts @@ -17,16 +17,17 @@ import { FormDirective, FormLabelDirective, NavComponent, - NavItemComponent, TextColorDirective + NavItemComponent, + TextColorDirective } from '@coreui/angular'; import { MultiSelectComponent } from '../../../../../layouts/primeng/multi-select/multi-select/multi-select.component'; -import { TranslocoDirective } from '@jsverse/transloco'; +import { TranslocoDirective, TranslocoService } from '@jsverse/transloco'; import { BackButtonDirective } from '../../../../../directives/back-button.directive'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { PermissionDirective } from '../../../../../permissions/permission.directive'; import { XsButtonDirective } from '../../../../../layouts/coreui/xsbutton-directive/xsbutton.directive'; -import { GenericValidationError } from '../../../../../generic-responses'; +import { GenericIdResponse, GenericValidationError } from '../../../../../generic-responses'; import { SelectKeyValue } from '../../../../../layouts/primeng/select.interface'; import { FormLoaderComponent } from '../../../../../layouts/primeng/loading/form-loader/form-loader.component'; import { @@ -80,6 +81,7 @@ export class FlowchiefNodeSelectionComponent implements OnInit, OnDestroy { private subscriptions: Subscription = new Subscription(); private readonly ExternalMonitoringsService = inject(ExternalMonitoringsService); + private readonly TranslocoService = inject(TranslocoService); private readonly notyService = inject(NotyService); private readonly HistoryService: HistoryService = inject(HistoryService); private readonly router: Router = inject(Router); @@ -151,6 +153,7 @@ export class FlowchiefNodeSelectionComponent implements OnInit, OnDestroy { const node = this.flowchiefNodes.find(n => n.key === nodeId); if (node) { flowchief_nodes_membership.push({ + id: externalMonitoringId, external_monitoring_id: externalMonitoringId, path: node.value, _joinData: { @@ -167,7 +170,32 @@ export class FlowchiefNodeSelectionComponent implements OnInit, OnDestroy { } public submit() { + if (!this.post) { + return; + } + + this.subscriptions.add(this.ExternalMonitoringsService.editFlowchiefNodeSelection(this.post) + .subscribe((result) => { + this.cdr.markForCheck(); + if (result.success) { + const response = result.data as GenericIdResponse; + const title = this.TranslocoService.translate('FlowChief Nodes'); + const msg = this.TranslocoService.translate('updated successfully'); + const url = ['import_module', 'ExternalMonitorings', 'flowchiefNodeSelection', response.id]; + + this.notyService.genericSuccess(msg, title, url); + this.HistoryService.navigateWithFallback(['/import_module/ExternalMonitorings/index']); + this.notyService.scrollContentDivToTop(); + return; + } + // Error + const errorResponse = result.data as GenericValidationError; + this.notyService.genericError(); + if (result) { + this.errors = errorResponse; + } + })); } } From 55d1ceeb61d5567bc2fbee0e03c6d92b626cfbc2 Mon Sep 17 00:00:00 2001 From: ibering Date: Fri, 26 Sep 2025 11:36:58 +0200 Subject: [PATCH 07/48] #ITC-3595 Import Module: Add support for FlowChief: External monitorings (flowchiefNodeSelection - copy to clipboard added) --- .../flowchief-node-selection.component.html | 7 +++++-- .../flowchief-node-selection.component.ts | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html index b38ebffae..6ff5caa5c 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html @@ -66,8 +66,11 @@
{{ t('Select FlowChief Nodes') }}
{{ t('openITCOCKPIT will import all Process Variables from the selected nodes.') }}
{{ t('In case the list is empty, execute the command') }} - oitc import_module.flowchief_import_nodes - --external-monitoring-system-id {{ post.id }} + + oitc import_module.flowchief_import_nodes + --external-monitoring-system-id {{ post.id }} + {{ t('on the openITCOCKPIT server to get the list of available nodes.') }}
Date: Fri, 26 Sep 2025 15:03:13 +0200 Subject: [PATCH 08/48] ITC-3595 Save sub-tree selection per flowchief system --- .../external-monitorings.interface.ts | 18 ++++-------------- .../flowchief-node-selection.component.html | 4 ++-- .../flowchief-node-selection.component.ts | 16 ++++++---------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts index d3b8664a5..23b46a973 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts +++ b/src/app/modules/import_module/pages/externalmonitorings/external-monitorings.interface.ts @@ -110,21 +110,11 @@ export interface ExternalMonitoringWithFlowchiefNodesMembershipPost extends Exte } export interface FlowchiefNodesMembership { - id?: number + id?: number // auto increment of linking table external_monitoring_id: number - name?: string - path: string - external_flowchief_node_id?: number - external_flowchief_node_parent_id?: number - tag?: string - created?: string - modified?: string - _joinData: { - id?: number - flowchief_node_id: number - external_monitoring_id: number - is_recursive: boolean - } + flowchief_node_id: number + is_recursive: boolean + path?: string // only used by the Angular Frontend } /********************** diff --git a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html index 6ff5caa5c..10f8541e7 100644 --- a/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html +++ b/src/app/modules/import_module/pages/externalmonitorings/flowchief-node-selection/flowchief-node-selection.component.html @@ -82,7 +82,7 @@
{{ t('Select FlowChief Nodes') }}
@for (nodeMembership of post.flowchief_nodes_membership; track $index) {
- @if (nodeMembership._joinData.is_recursive) { + @if (nodeMembership.is_recursive) { } @else { @@ -95,7 +95,7 @@
{{ t('Select FlowChief Nodes') }}
[id]="'is_recursive'+$index" [name]="'is_recursive'+$index" type="checkbox" - [(ngModel)]="nodeMembership._joinData.is_recursive"/> + [(ngModel)]="nodeMembership.is_recursive"/>
From 4e510129b8780358d7e6734e9393476fc5fed15f Mon Sep 17 00:00:00 2001 From: Jan Nox Date: Wed, 1 Oct 2025 15:48:34 +0200 Subject: [PATCH 13/48] * Add BroadcomProxy Front-End --- src/app/app.routes.ts | 4 +- .../broadcomproxy_module.routes.ts | 9 + .../broadcom-proxy-wizard.interface.ts | 110 +++++++++ .../broadcom-proxy-wizard.service.ts | 39 ++++ .../broadcom-proxy.component.css | 0 .../broadcom-proxy.component.html | 218 ++++++++++++++++++ .../broadcom-proxy.component.spec.ts | 23 ++ .../broadcom-proxy.component.ts | 98 ++++++++ 8 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 src/app/modules/broadcomproxy_module/broadcomproxy_module.routes.ts create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.interface.ts create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.service.ts create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.css create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.html create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.spec.ts create mode 100644 src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.ts diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 1a052dc6a..db4a65aa8 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -40,6 +40,7 @@ import { servicenowModuleRoutes } from './modules/servicenow_module/servicenow_m import { dellModuleRoutes } from './modules/dell_module/dell_module.routes'; import { proxmoxModuleRoutes } from './modules/proxmox_module/proxmox_module.routes'; import { ms365ModuleRoutes } from './modules/ms365_module/ms365_module.routes'; +import { broadcomProxyModuleRoutes } from './modules/broadcomproxy_module/broadcomproxy_module.routes'; @Component({ selector: 'legacy-redirect', @@ -101,7 +102,8 @@ const moduleRoutes: Routes = [ ...servicenowModuleRoutes, ...dellModuleRoutes, ...proxmoxModuleRoutes, - ...ms365ModuleRoutes + ...ms365ModuleRoutes, + ...broadcomProxyModuleRoutes ]; /*** Core routes ***/ const coreRoutes: Routes = [{ diff --git a/src/app/modules/broadcomproxy_module/broadcomproxy_module.routes.ts b/src/app/modules/broadcomproxy_module/broadcomproxy_module.routes.ts new file mode 100644 index 000000000..df3840623 --- /dev/null +++ b/src/app/modules/broadcomproxy_module/broadcomproxy_module.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { BroadcomProxyComponent } from './pages/wizards/broadcom-proxy/broadcom-proxy.component'; + +export const broadcomProxyModuleRoutes: Routes = [ + { + path: 'broadcom_proxy_module/wizards/broadcom_proxy/:hostId', + loadComponent: () => import('./pages/wizards/broadcom-proxy/broadcom-proxy.component').then(m => BroadcomProxyComponent) + }, +]; diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.interface.ts b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.interface.ts new file mode 100644 index 000000000..2554f6894 --- /dev/null +++ b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.interface.ts @@ -0,0 +1,110 @@ +import { WizardGet, WizardPost } from '../../../../../pages/wizards/wizards.interface'; + +// WIZARD GET +export interface BroadcomProxyWizardGet extends WizardGet { + interfaceServicetemplate: InterfaceServicetemplate +} + + +export interface InterfaceServicetemplate { + id: number + uuid: string + template_name: string + name: string + container_id: number + servicetemplatetype_id: number + check_period_id: number + notify_period_id: number + description: string + command_id: number + check_command_args: string + checkcommand_info: string + eventhandler_command_id: number + timeperiod_id: number + check_interval: number + retry_interval: number + max_check_attempts: number + first_notification_delay: number + notification_interval: number + notify_on_warning: number + notify_on_unknown: number + notify_on_critical: number + notify_on_recovery: number + notify_on_flapping: number + notify_on_downtime: number + flap_detection_enabled: number + flap_detection_on_ok: number + flap_detection_on_warning: number + flap_detection_on_unknown: number + flap_detection_on_critical: number + low_flap_threshold: number + high_flap_threshold: number + process_performance_data: number + freshness_checks_enabled: number + freshness_threshold: any + passive_checks_enabled: number + event_handler_enabled: number + active_checks_enabled: number + retain_status_information: number + retain_nonstatus_information: number + notifications_enabled: number + notes: string + priority: number + tags: string + service_url: any + sla_relevant: number + is_volatile: number + check_freshness: number + created: string + modified: string + check_command: { + id: number + name: string + command_line: string + command_type: number + human_args: any + uuid: string + description: string + commandarguments: { + id: number + command_id: number + name: string + human_name: string + created: string + modified: string + }[] + } + servicetemplatecommandargumentvalues: Servicecommandargumentvalue[] +} + +export interface Servicecommandargumentvalue { + commandargument: Commandargument + commandargument_id: number + created: string + id: number + modified: string + servicetemplate_id: number + value: string +} + +export interface Commandargument { + command_id: number + created: string + human_name: string + id: number + modified: string + name: string +} + + +// WIZARD POST +export interface BroadcomProxyWizardPost extends WizardPost { + authPassword: string + authProtocol: string + privacyPassword: string + privacyProtocol: string + securityLevel: string + securityName: string + snmpCommunity: string + snmpVersion: string +} diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.service.ts b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.service.ts new file mode 100644 index 000000000..70c56ac34 --- /dev/null +++ b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy-wizard.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { catchError, map, Observable, of } from 'rxjs'; +import { WizardsService } from '../../../../../pages/wizards/wizards.service'; +import { GenericResponseWrapper, GenericValidationError } from '../../../../../generic-responses'; +import { BroadcomProxyWizardGet, BroadcomProxyWizardPost } from './broadcom-proxy-wizard.interface'; + +@Injectable({ + providedIn: 'root' +}) +export class BroadcomProxyWizardService extends WizardsService { + + public fetch(hostId: number): Observable { + return this.http.get(`${this.proxyPath}/broadcom_proxy_module/wizards/broadcomProxy/${hostId}.json?angular=true`).pipe( + map((data: BroadcomProxyWizardGet): BroadcomProxyWizardGet => { + return data; + }) + ); + } + + public submit(post: BroadcomProxyWizardPost): Observable { + return this.http.post(`${this.proxyPath}/broadcom_proxy_module/wizards/broadcomProxy.json?angular=true`, post) + .pipe( + map(data => { + return { + success: true, + data: null + }; + }), + catchError((error: any) => { + const err = error.error.error as GenericValidationError; + return of({ + success: false, + data: err + }); + }) + ); + + } +} diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.css b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.html b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.html new file mode 100644 index 000000000..9cd208b5c --- /dev/null +++ b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.html @@ -0,0 +1,218 @@ + + + + + + +
+ {{ t('Configuration Wizard: Broadcom Proxy') }} +
+
+ + +
+
+ + + {{ t('Host Information') }} + +
+
+ + + {{ t('Configure SNMP for Broadcom Proxy Monitoring') }} + +
+
+
+
+
+ + + +
+
+
+
+ + + +
+ +

+ {{ t('SNMP Server Settings') }} +

+
+ +
+ + + + +
+ +
+ + + + +
+ {{ t('Communication with authentication and privacy. The protocols used for Authentication are MD5 and SHA and for Privacy, DES (Data Encryption Standard) and AES (Advanced Encryption Standard).') }} + {{ t('Communication with authentication and without privacy. The protocols used for Authentication are MD5 and SHA (Secure Hash Algorithm).') }} + {{ t('Communication without authentication and privacy.') }} +
+
+ + +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+
+ + + + +
+
+ +
diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.spec.ts b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.spec.ts new file mode 100644 index 000000000..f8169a62b --- /dev/null +++ b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BroadcomProxyComponent } from './broadcom-proxy.component'; + +describe('BroadcomProxyComponent', () => { + let component: BroadcomProxyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [BroadcomProxyComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(BroadcomProxyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.ts b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.ts new file mode 100644 index 000000000..70039d806 --- /dev/null +++ b/src/app/modules/broadcomproxy_module/pages/wizards/broadcom-proxy/broadcom-proxy.component.ts @@ -0,0 +1,98 @@ +import { ChangeDetectionStrategy, Component, inject, ViewChild } from '@angular/core'; +import { WizardsAbstractComponent } from '../../../../../pages/wizards/wizards-abstract/wizards-abstract.component'; +import { SelectKeyValueString } from '../../../../../layouts/primeng/select.interface'; +import { + WizardsDynamicfieldsComponent +} from '../../../../../components/wizards/wizards-dynamicfields/wizards-dynamicfields.component'; +import { RouterLink } from '@angular/router'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { + CardBodyComponent, + CardComponent, + CardHeaderComponent, + CardTitleDirective, + FormControlDirective, + FormLabelDirective +} from '@coreui/angular'; +import { TranslocoDirective, TranslocoPipe } from '@jsverse/transloco'; +import { RequiredIconComponent } from '../../../../../components/required-icon/required-icon.component'; +import { BackButtonDirective } from '../../../../../directives/back-button.directive'; +import { BroadcomProxyWizardPost } from './broadcom-proxy-wizard.interface'; +import { BroadcomProxyWizardService } from './broadcom-proxy-wizard.service'; +import { SelectComponent } from '../../../../../layouts/primeng/select/select/select.component'; +import { FormErrorDirective } from '../../../../../layouts/coreui/form-error.directive'; +import { FormFeedbackComponent } from '../../../../../layouts/coreui/form-feedback/form-feedback.component'; +import { FormsModule } from '@angular/forms'; +import { NgIf } from '@angular/common'; + +@Component({ + selector: 'oitc-broadcom-proxy', + imports: [ + RouterLink, + FaIconComponent, + CardComponent, + CardHeaderComponent, + CardBodyComponent, + BackButtonDirective, + TranslocoPipe, + RequiredIconComponent, + FormLabelDirective, + SelectComponent, + FormErrorDirective, + FormFeedbackComponent, + FormsModule, + FormControlDirective, + WizardsDynamicfieldsComponent, + TranslocoDirective, + CardTitleDirective, + NgIf + ], + templateUrl: './broadcom-proxy.component.html', + styleUrl: './broadcom-proxy.component.css', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class BroadcomProxyComponent extends WizardsAbstractComponent { + @ViewChild(WizardsDynamicfieldsComponent) childComponentLocal!: WizardsDynamicfieldsComponent; + protected override WizardService: BroadcomProxyWizardService = inject(BroadcomProxyWizardService); + public checked: boolean = false; + + protected override post: BroadcomProxyWizardPost = { +// Default fields from the base wizard + host_id: 0, + services: [], +// Fields for the wizard + authPassword: '', + authProtocol: 'md5', + privacyPassword: '', + privacyProtocol: 'des', + securityLevel: '1', + securityName: '', + snmpCommunity: '', + snmpVersion: '2' + } as BroadcomProxyWizardPost; + protected snmpVersions: SelectKeyValueString[] = [ + {value: '1', key: 'SNMP V 1'}, + {value: '2', key: 'SNMP V 2c'}, + {value: '3', key: 'SNMP V 3'}, + ] + + + protected securityLevels: SelectKeyValueString[] = [ + {key: 'authPriv', value: '1'}, + {key: 'authNoPriv', value: '2'}, + {key: 'noAuthNoPriv', value: '3'}, + ]; + protected authProtocols: SelectKeyValueString[] = [ + {key: 'MD5', value: 'md5'}, + {key: 'SHA', value: 'sha'}, + ]; + protected privacyProtocols: SelectKeyValueString[] = [ + {key: 'DES', value: 'des'}, + {key: 'AES', value: 'aes'}, + {key: 'AES128', value: 'aes128'}, + {key: '3DES', value: '3des'}, + {key: '3DESDE', value: '3desde'}, + ]; + +} + From 259440e4bf98f3682898c471c9817f9c0ffdb636 Mon Sep 17 00:00:00 2001 From: Jan Nox Date: Wed, 8 Oct 2025 08:40:22 +0200 Subject: [PATCH 14/48] * Add Wizard front-end --- .../cisconetwork_module.routes.ts | 9 + .../cisco-network-wizard.interface.ts | 110 +++++++++ .../cisco-network-wizard.service.ts | 39 ++++ .../cisco-network/cisco-network.component.css | 0 .../cisco-network.component.html | 218 ++++++++++++++++++ .../cisco-network.component.spec.ts | 23 ++ .../cisco-network/cisco-network.component.ts | 98 ++++++++ 7 files changed, 497 insertions(+) create mode 100644 src/app/modules/cisconetwork_module/cisconetwork_module.routes.ts create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.interface.ts create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.css create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.html create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.spec.ts create mode 100644 src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.ts diff --git a/src/app/modules/cisconetwork_module/cisconetwork_module.routes.ts b/src/app/modules/cisconetwork_module/cisconetwork_module.routes.ts new file mode 100644 index 000000000..904e11a68 --- /dev/null +++ b/src/app/modules/cisconetwork_module/cisconetwork_module.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { CiscoNetworkComponent } from './pages/wizards/cisco-network/cisco-network.component'; + +export const ciscoNetworkModuleRoutes: Routes = [ + { + path: 'cisco_network_module/wizards/cisco_network/:hostId', + loadComponent: () => import('./pages/wizards/cisco-network/cisco-network.component').then(m => CiscoNetworkComponent) + }, +]; diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.interface.ts b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.interface.ts new file mode 100644 index 000000000..9e9f57b88 --- /dev/null +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.interface.ts @@ -0,0 +1,110 @@ +import { WizardGet, WizardPost } from '../../../../../pages/wizards/wizards.interface'; + +// WIZARD GET +export interface CiscoNetworkWizardGet extends WizardGet { + interfaceServicetemplate: InterfaceServicetemplate +} + + +export interface InterfaceServicetemplate { + id: number + uuid: string + template_name: string + name: string + container_id: number + servicetemplatetype_id: number + check_period_id: number + notify_period_id: number + description: string + command_id: number + check_command_args: string + checkcommand_info: string + eventhandler_command_id: number + timeperiod_id: number + check_interval: number + retry_interval: number + max_check_attempts: number + first_notification_delay: number + notification_interval: number + notify_on_warning: number + notify_on_unknown: number + notify_on_critical: number + notify_on_recovery: number + notify_on_flapping: number + notify_on_downtime: number + flap_detection_enabled: number + flap_detection_on_ok: number + flap_detection_on_warning: number + flap_detection_on_unknown: number + flap_detection_on_critical: number + low_flap_threshold: number + high_flap_threshold: number + process_performance_data: number + freshness_checks_enabled: number + freshness_threshold: any + passive_checks_enabled: number + event_handler_enabled: number + active_checks_enabled: number + retain_status_information: number + retain_nonstatus_information: number + notifications_enabled: number + notes: string + priority: number + tags: string + service_url: any + sla_relevant: number + is_volatile: number + check_freshness: number + created: string + modified: string + check_command: { + id: number + name: string + command_line: string + command_type: number + human_args: any + uuid: string + description: string + commandarguments: { + id: number + command_id: number + name: string + human_name: string + created: string + modified: string + }[] + } + servicetemplatecommandargumentvalues: Servicecommandargumentvalue[] +} + +export interface Servicecommandargumentvalue { + commandargument: Commandargument + commandargument_id: number + created: string + id: number + modified: string + servicetemplate_id: number + value: string +} + +export interface Commandargument { + command_id: number + created: string + human_name: string + id: number + modified: string + name: string +} + + +// WIZARD POST +export interface CiscoNetworkWizardPost extends WizardPost { + authPassword: string + authProtocol: string + privacyPassword: string + privacyProtocol: string + securityLevel: string + securityName: string + snmpCommunity: string + snmpVersion: string +} diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts new file mode 100644 index 000000000..c4b87340d --- /dev/null +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { catchError, map, Observable, of } from 'rxjs'; +import { WizardsService } from '../../../../../pages/wizards/wizards.service'; +import { GenericResponseWrapper, GenericValidationError } from '../../../../../generic-responses'; +import { CiscoNetworkWizardGet, CiscoNetworkWizardPost } from './cisco-network-wizard.interface'; + +@Injectable({ + providedIn: 'root' +}) +export class CiscoNetworkWizardService extends WizardsService { + + public fetch(hostId: number): Observable { + return this.http.get(`${this.proxyPath}/cisco_network_module/wizards/CiscoNetwork/${hostId}.json?angular=true`).pipe( + map((data: CiscoNetworkWizardGet): CiscoNetworkWizardGet => { + return data; + }) + ); + } + + public submit(post: CiscoNetworkWizardPost): Observable { + return this.http.post(`${this.proxyPath}/cisco_network_module/wizards/CiscoNetwork.json?angular=true`, post) + .pipe( + map(data => { + return { + success: true, + data: null + }; + }), + catchError((error: any) => { + const err = error.error.error as GenericValidationError; + return of({ + success: false, + data: err + }); + }) + ); + + } +} diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.css b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.html b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.html new file mode 100644 index 000000000..87cebd080 --- /dev/null +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.html @@ -0,0 +1,218 @@ + + + + + + +
+ {{ t('Configuration Wizard: Cisco Network') }} +
+
+ + +
+
+ + + {{ t('Host Information') }} + +
+
+ + + {{ t('Configure SNMP for Cisco Network Monitoring') }} + +
+
+
+
+
+ + + +
+
+
+
+ + + +
+ +

+ {{ t('SNMP Server Settings') }} +

+
+ +
+ + + + +
+ +
+ + + + +
+ {{ t('Communication with authentication and privacy. The protocols used for Authentication are MD5 and SHA and for Privacy, DES (Data Encryption Standard) and AES (Advanced Encryption Standard).') }} + {{ t('Communication with authentication and without privacy. The protocols used for Authentication are MD5 and SHA (Secure Hash Algorithm).') }} + {{ t('Communication without authentication and privacy.') }} +
+
+ + +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+
+ + + + +
+
+ +
diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.spec.ts b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.spec.ts new file mode 100644 index 000000000..3e4f1f55a --- /dev/null +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CiscoNetworkComponent } from './cisco-network.component'; + +describe('CiscoNetworkComponent', () => { + let component: CiscoNetworkComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CiscoNetworkComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CiscoNetworkComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.ts b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.ts new file mode 100644 index 000000000..eaef94118 --- /dev/null +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network.component.ts @@ -0,0 +1,98 @@ +import { ChangeDetectionStrategy, Component, inject, ViewChild } from '@angular/core'; +import { WizardsAbstractComponent } from '../../../../../pages/wizards/wizards-abstract/wizards-abstract.component'; +import { SelectKeyValueString } from '../../../../../layouts/primeng/select.interface'; +import { + WizardsDynamicfieldsComponent +} from '../../../../../components/wizards/wizards-dynamicfields/wizards-dynamicfields.component'; +import { RouterLink } from '@angular/router'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { + CardBodyComponent, + CardComponent, + CardHeaderComponent, + CardTitleDirective, + FormControlDirective, + FormLabelDirective +} from '@coreui/angular'; +import { TranslocoDirective, TranslocoPipe } from '@jsverse/transloco'; +import { RequiredIconComponent } from '../../../../../components/required-icon/required-icon.component'; +import { BackButtonDirective } from '../../../../../directives/back-button.directive'; +import { CiscoNetworkWizardPost } from './cisco-network-wizard.interface'; +import { CiscoNetworkWizardService } from './cisco-network-wizard.service'; +import { SelectComponent } from '../../../../../layouts/primeng/select/select/select.component'; +import { FormErrorDirective } from '../../../../../layouts/coreui/form-error.directive'; +import { FormFeedbackComponent } from '../../../../../layouts/coreui/form-feedback/form-feedback.component'; +import { FormsModule } from '@angular/forms'; +import { NgIf } from '@angular/common'; + +@Component({ + selector: 'oitc-cisco-network', + imports: [ + RouterLink, + FaIconComponent, + CardComponent, + CardHeaderComponent, + CardBodyComponent, + BackButtonDirective, + TranslocoPipe, + RequiredIconComponent, + FormLabelDirective, + SelectComponent, + FormErrorDirective, + FormFeedbackComponent, + FormsModule, + FormControlDirective, + WizardsDynamicfieldsComponent, + TranslocoDirective, + CardTitleDirective, + NgIf + ], + templateUrl: './cisco-network.component.html', + styleUrl: './cisco-network.component.css', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CiscoNetworkComponent extends WizardsAbstractComponent { + @ViewChild(WizardsDynamicfieldsComponent) childComponentLocal!: WizardsDynamicfieldsComponent; + protected override WizardService: CiscoNetworkWizardService = inject(CiscoNetworkWizardService); + public checked: boolean = false; + + protected override post: CiscoNetworkWizardPost = { +// Default fields from the base wizard + host_id: 0, + services: [], +// Fields for the wizard + authPassword: '', + authProtocol: 'md5', + privacyPassword: '', + privacyProtocol: 'des', + securityLevel: '1', + securityName: '', + snmpCommunity: '', + snmpVersion: '2' + } as CiscoNetworkWizardPost; + protected snmpVersions: SelectKeyValueString[] = [ + {value: '1', key: 'SNMP V 1'}, + {value: '2', key: 'SNMP V 2c'}, + {value: '3', key: 'SNMP V 3'}, + ] + + + protected securityLevels: SelectKeyValueString[] = [ + {key: 'authPriv', value: '1'}, + {key: 'authNoPriv', value: '2'}, + {key: 'noAuthNoPriv', value: '3'}, + ]; + protected authProtocols: SelectKeyValueString[] = [ + {key: 'MD5', value: 'md5'}, + {key: 'SHA', value: 'sha'}, + ]; + protected privacyProtocols: SelectKeyValueString[] = [ + {key: 'DES', value: 'des'}, + {key: 'AES', value: 'aes'}, + {key: 'AES128', value: 'aes128'}, + {key: '3DES', value: '3des'}, + {key: '3DESDE', value: '3desde'}, + ]; + +} + From 99bd8dbf9c78f0afafe0483a2a108966e1b067ec Mon Sep 17 00:00:00 2001 From: Jan Nox Date: Wed, 8 Oct 2025 08:40:40 +0200 Subject: [PATCH 15/48] * Add new Routes. --- src/app/app.routes.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 1a052dc6a..9f4edbdcb 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -40,6 +40,7 @@ import { servicenowModuleRoutes } from './modules/servicenow_module/servicenow_m import { dellModuleRoutes } from './modules/dell_module/dell_module.routes'; import { proxmoxModuleRoutes } from './modules/proxmox_module/proxmox_module.routes'; import { ms365ModuleRoutes } from './modules/ms365_module/ms365_module.routes'; +import { ciscoNetworkModuleRoutes } from './modules/cisconetwork_module/cisconetwork_module.routes'; @Component({ selector: 'legacy-redirect', @@ -101,7 +102,8 @@ const moduleRoutes: Routes = [ ...servicenowModuleRoutes, ...dellModuleRoutes, ...proxmoxModuleRoutes, - ...ms365ModuleRoutes + ...ms365ModuleRoutes, + ...ciscoNetworkModuleRoutes ]; /*** Core routes ***/ const coreRoutes: Routes = [{ From 5c7c9d658f534c992b9d8ef76be6f188449c247c Mon Sep 17 00:00:00 2001 From: Jan Nox Date: Wed, 8 Oct 2025 11:39:48 +0200 Subject: [PATCH 16/48] * Fix case --- .../wizards/cisco-network/cisco-network-wizard.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts index c4b87340d..a76a23cc3 100644 --- a/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts +++ b/src/app/modules/cisconetwork_module/pages/wizards/cisco-network/cisco-network-wizard.service.ts @@ -10,7 +10,7 @@ import { CiscoNetworkWizardGet, CiscoNetworkWizardPost } from './cisco-network-w export class CiscoNetworkWizardService extends WizardsService { public fetch(hostId: number): Observable { - return this.http.get(`${this.proxyPath}/cisco_network_module/wizards/CiscoNetwork/${hostId}.json?angular=true`).pipe( + return this.http.get(`${this.proxyPath}/cisco_network_module/wizards/ciscoNetwork/${hostId}.json?angular=true`).pipe( map((data: CiscoNetworkWizardGet): CiscoNetworkWizardGet => { return data; }) @@ -18,7 +18,7 @@ export class CiscoNetworkWizardService extends WizardsService { } public submit(post: CiscoNetworkWizardPost): Observable { - return this.http.post(`${this.proxyPath}/cisco_network_module/wizards/CiscoNetwork.json?angular=true`, post) + return this.http.post(`${this.proxyPath}/cisco_network_module/wizards/ciscoNetwork.json?angular=true`, post) .pipe( map(data => { return { From f20463279ab2d3b6158ba4509cec11bc04df5a3a Mon Sep 17 00:00:00 2001 From: ibering Date: Tue, 14 Oct 2025 09:33:01 +0200 Subject: [PATCH 17/48] #ITC-3610 Host - edit_details bug when shared --- .../hosts-edit-details.component.html | 11 ++------- .../hosts-index/hosts-index.component.html | 24 ++++++++----------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/app/pages/hosts/hosts-edit-details/hosts-edit-details.component.html b/src/app/pages/hosts/hosts-edit-details/hosts-edit-details.component.html index 5eee13abe..0bbad5b92 100644 --- a/src/app/pages/hosts/hosts-edit-details/hosts-edit-details.component.html +++ b/src/app/pages/hosts/hosts-edit-details/hosts-edit-details.component.html @@ -471,21 +471,14 @@
- - - - - - - - diff --git a/src/app/pages/hosts/hosts-index/hosts-index.component.html b/src/app/pages/hosts/hosts-index/hosts-index.component.html index bcc46d0f1..efc1eea22 100644 --- a/src/app/pages/hosts/hosts-index/hosts-index.component.html +++ b/src/app/pages/hosts/hosts-index/hosts-index.component.html @@ -1088,7 +1088,6 @@
- } - - @@ -1182,17 +1179,16 @@
{{ t('Copy') }} - -
  • - - - - {{ t('Delete') }} - - - + @if (host.Host.allow_edit && ( PermissionsService.hasPermissionObservable(['hosts', 'delete'])|async )) { +
  • + + + + {{ t('Delete') }} + + + } From 569fd90ef97b0e97295a6f6e24b31d2c1b850857 Mon Sep 17 00:00:00 2001 From: Jan Nox Date: Tue, 14 Oct 2025 15:43:41 +0200 Subject: [PATCH 18/48] * Add new wizard and module for Cisco WLC --- src/app/app.routes.ts | 4 +- .../cisco_wlc_module.routes.ts | 9 + .../cisco-wlc/cisco-wlc-wizard.interface.ts | 137 +++++++++++ .../cisco-wlc/cisco-wlc-wizard.service.ts | 39 ++++ .../wizards/cisco-wlc/cisco-wlc.component.css | 0 .../cisco-wlc/cisco-wlc.component.html | 217 ++++++++++++++++++ .../cisco-wlc/cisco-wlc.component.spec.ts | 23 ++ .../wizards/cisco-wlc/cisco-wlc.component.ts | 191 +++++++++++++++ 8 files changed, 619 insertions(+), 1 deletion(-) create mode 100644 src/app/modules/cisco_wlc_module/cisco_wlc_module.routes.ts create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.interface.ts create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.service.ts create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.css create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.html create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.spec.ts create mode 100644 src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.ts diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 1a052dc6a..1faf37bc8 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -40,6 +40,7 @@ import { servicenowModuleRoutes } from './modules/servicenow_module/servicenow_m import { dellModuleRoutes } from './modules/dell_module/dell_module.routes'; import { proxmoxModuleRoutes } from './modules/proxmox_module/proxmox_module.routes'; import { ms365ModuleRoutes } from './modules/ms365_module/ms365_module.routes'; +import { ciscoWlcModuleRoutes } from './modules/cisco_wlc_module/cisco_wlc_module.routes'; @Component({ selector: 'legacy-redirect', @@ -101,7 +102,8 @@ const moduleRoutes: Routes = [ ...servicenowModuleRoutes, ...dellModuleRoutes, ...proxmoxModuleRoutes, - ...ms365ModuleRoutes + ...ms365ModuleRoutes, + ...ciscoWlcModuleRoutes ]; /*** Core routes ***/ const coreRoutes: Routes = [{ diff --git a/src/app/modules/cisco_wlc_module/cisco_wlc_module.routes.ts b/src/app/modules/cisco_wlc_module/cisco_wlc_module.routes.ts new file mode 100644 index 000000000..a811a1c44 --- /dev/null +++ b/src/app/modules/cisco_wlc_module/cisco_wlc_module.routes.ts @@ -0,0 +1,9 @@ +import { Routes } from '@angular/router'; +import { CiscoWlcComponent } from './pages/wizards/cisco-wlc/cisco-wlc.component'; + +export const ciscoWlcModuleRoutes: Routes = [ + { + path: 'cisco_wlc_module/wizards/cisco_wlc/:hostId', + loadComponent: () => import('./pages/wizards/cisco-wlc/cisco-wlc.component').then(m => CiscoWlcComponent) + }, +]; diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.interface.ts b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.interface.ts new file mode 100644 index 000000000..c5e156fcb --- /dev/null +++ b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.interface.ts @@ -0,0 +1,137 @@ +import { WizardGet, WizardPost } from '../../../../../pages/wizards/wizards.interface'; +import { GenericValidationError } from '../../../../../generic-responses'; + +// WIZARD GET +export interface CiscoWlcWizardGet extends WizardGet { + interfaceServicetemplate: InterfaceServicetemplate +} + + +export interface InterfaceServicetemplate { + id: number + uuid: string + template_name: string + name: string + container_id: number + servicetemplatetype_id: number + check_period_id: number + notify_period_id: number + description: string + command_id: number + check_command_args: string + checkcommand_info: string + eventhandler_command_id: number + timeperiod_id: number + check_interval: number + retry_interval: number + max_check_attempts: number + first_notification_delay: number + notification_interval: number + notify_on_warning: number + notify_on_unknown: number + notify_on_critical: number + notify_on_recovery: number + notify_on_flapping: number + notify_on_downtime: number + flap_detection_enabled: number + flap_detection_on_ok: number + flap_detection_on_warning: number + flap_detection_on_unknown: number + flap_detection_on_critical: number + low_flap_threshold: number + high_flap_threshold: number + process_performance_data: number + freshness_checks_enabled: number + freshness_threshold: any + passive_checks_enabled: number + event_handler_enabled: number + active_checks_enabled: number + retain_status_information: number + retain_nonstatus_information: number + notifications_enabled: number + notes: string + priority: number + tags: string + service_url: any + sla_relevant: number + is_volatile: number + check_freshness: number + created: string + modified: string + check_command: { + id: number + name: string + command_line: string + command_type: number + human_args: any + uuid: string + description: string + commandarguments: { + id: number + command_id: number + name: string + human_name: string + created: string + modified: string + }[] + } + servicetemplatecommandargumentvalues: Servicecommandargumentvalue[] +} + +export interface Servicecommandargumentvalue { + commandargument: Commandargument + commandargument_id: number + created: string + id: number + modified: string + servicetemplate_id: number + value: string +} + +export interface Commandargument { + command_id: number + created: string + human_name: string + id: number + modified: string + name: string +} + + +// WIZARD POST +export interface CiscoWlcWizardPost extends WizardPost { + authPassword: string + authProtocol: string + interfaces: N0[] + privacyPassword: string + privacyProtocol: string + securityLevel: string + securityName: string + snmpCommunity: string + snmpVersion: string +} + +export interface N0 { + createService: boolean + description: string + host_id: number + name: string + servicecommandargumentvalues: Servicecommandargumentvalue[] + servicetemplate_id: number +} + +// SNMP Discovery +export interface SnmpDiscovery { + interfaces: Interface[] + success: boolean + errors: GenericValidationError | undefined + _csrfToken: any +} + +export interface Interface { + key: number + value: { + number: string + name: string + } +} diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.service.ts b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.service.ts new file mode 100644 index 000000000..36f37dbe1 --- /dev/null +++ b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc-wizard.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { catchError, map, Observable, of } from 'rxjs'; +import { WizardsService } from '../../../../../pages/wizards/wizards.service'; +import { GenericResponseWrapper, GenericValidationError } from '../../../../../generic-responses'; +import { CiscoWlcWizardGet, CiscoWlcWizardPost } from './cisco-wlc-wizard.interface'; + +@Injectable({ + providedIn: 'root' +}) +export class CiscoWlcWizardService extends WizardsService { + + public fetch(hostId: number): Observable { + return this.http.get(`${this.proxyPath}/cisco_wlc_module/wizards/cisco_wlc/${hostId}.json?angular=true`).pipe( + map((data: CiscoWlcWizardGet): CiscoWlcWizardGet => { + return data; + }) + ); + } + + public submit(post: CiscoWlcWizardPost): Observable { + return this.http.post(`${this.proxyPath}/cisco_wlc_module/wizards/cisco_wlc.json?angular=true`, post) + .pipe( + map(data => { + return { + success: true, + data: null + }; + }), + catchError((error: any) => { + const err = error.error.error as GenericValidationError; + return of({ + success: false, + data: err + }); + }) + ); + } + +} diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.css b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.html b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.html new file mode 100644 index 000000000..e6fb10e64 --- /dev/null +++ b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.html @@ -0,0 +1,217 @@ + + + + + + +
    + {{ t('Configuration Wizard: Cisco WLC') }} +
    +
    + + +
    +
    + + + {{ t('Host Information') }} + +
    +
    + + + {{ t('Configure SNMP for Cisco WLC') }} + +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    + +

    + {{ t('SNMP Server Settings') }} +

    +
    + +
    + + + + +
    + +
    + + + + +
    + {{ t('Communication with authentication and privacy. The protocols used for Authentication are MD5 and SHA and for Privacy, DES (Data Encryption Standard) and AES (Advanced Encryption Standard).') }} + {{ t('Communication with authentication and without privacy. The protocols used for Authentication are MD5 and SHA (Secure Hash Algorithm).') }} + {{ t('Communication without authentication and privacy.') }} +
    +
    + + +
    + + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    + + + + +
    + +
    + + + +
    + +
    + + + +
    +
    + + + +
    +
    + +
    diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.spec.ts b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.spec.ts new file mode 100644 index 000000000..59c208bee --- /dev/null +++ b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CiscoWlcComponent } from './cisco-wlc.component'; + +describe('CiscoWlcComponent', () => { + let component: CiscoWlcComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CiscoWlcComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CiscoWlcComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.ts b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.ts new file mode 100644 index 000000000..45ad96b2c --- /dev/null +++ b/src/app/modules/cisco_wlc_module/pages/wizards/cisco-wlc/cisco-wlc.component.ts @@ -0,0 +1,191 @@ +import { ChangeDetectionStrategy, Component, inject, ViewChild, ViewChildren } from '@angular/core'; +import { WizardsAbstractComponent } from '../../../../../pages/wizards/wizards-abstract/wizards-abstract.component'; +import { SelectKeyValueString } from '../../../../../layouts/primeng/select.interface'; +import { CiscoWlcWizardService } from './cisco-wlc-wizard.service'; +import { CiscoWlcWizardGet, CiscoWlcWizardPost, InterfaceServicetemplate, N0 } from './cisco-wlc-wizard.interface'; +import { RouterLink } from '@angular/router'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { + AccordionItemComponent, + CardBodyComponent, + CardComponent, + CardHeaderComponent, + CardTitleDirective, + FormControlDirective, + FormLabelDirective +} from '@coreui/angular'; +import { TranslocoDirective, TranslocoPipe } from '@jsverse/transloco'; +import { RequiredIconComponent } from '../../../../../components/required-icon/required-icon.component'; +import { SelectComponent } from '../../../../../layouts/primeng/select/select/select.component'; +import { FormFeedbackComponent } from '../../../../../layouts/coreui/form-feedback/form-feedback.component'; +import { FormErrorDirective } from '../../../../../layouts/coreui/form-error.directive'; +import { FormsModule } from '@angular/forms'; +import { NgIf } from '@angular/common'; +import { + WizardsDynamicfieldsComponent +} from '../../../../../components/wizards/wizards-dynamicfields/wizards-dynamicfields.component'; +import { ProgressBarModule } from 'primeng/progressbar'; +import { GenericResponseWrapper, GenericValidationError } from '../../../../../generic-responses'; +import { Service } from '../../../../../pages/wizards/wizards.interface'; +import { BackButtonDirective } from '../../../../../directives/back-button.directive'; + +@Component({ + selector: 'oitc-cisco-wlc', + imports: [ + RouterLink, + FaIconComponent, + CardComponent, + CardHeaderComponent, + CardBodyComponent, + TranslocoPipe, + RequiredIconComponent, + SelectComponent, + FormLabelDirective, + FormControlDirective, + NgIf, + WizardsDynamicfieldsComponent, + TranslocoDirective, + ProgressBarModule, + CardTitleDirective, + BackButtonDirective, + FormFeedbackComponent, + FormErrorDirective, + FormsModule + ], + templateUrl: './cisco-wlc.component.html', + styleUrl: './cisco-wlc.component.css', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CiscoWlcComponent extends WizardsAbstractComponent { + @ViewChildren('accordionItem') accordionItems: AccordionItemComponent[] = []; + @ViewChild(WizardsDynamicfieldsComponent) childComponentLocal!: WizardsDynamicfieldsComponent; + protected override WizardService: CiscoWlcWizardService = inject(CiscoWlcWizardService); + public checked: boolean = false; + public accordionClosed: boolean = true; + + protected override post: CiscoWlcWizardPost = { +// Default fields from the base wizard + host_id: 0, + services: [], +// Fields for the wizard + authPassword: '', + authProtocol: 'md5', + interfaces: [], + privacyPassword: '', + privacyProtocol: 'des', + securityLevel: '1', + securityName: '', + snmpCommunity: '', + snmpVersion: '2' + } as CiscoWlcWizardPost; + protected snmpVersions: SelectKeyValueString[] = [ + {value: '1', key: 'SNMP V 1'}, + {value: '2', key: 'SNMP V 2c'}, + {value: '3', key: 'SNMP V 3'}, + ] + protected searchedTags: string[] = []; + + + protected securityLevels: SelectKeyValueString[] = [ + {key: 'authPriv', value: '1'}, + {key: 'authNoPriv', value: '2'}, + {key: 'noAuthNoPriv', value: '3'}, + ]; + protected authProtocols: SelectKeyValueString[] = [ + {key: 'MD5', value: 'md5'}, + {key: 'SHA', value: 'sha'}, + ]; + protected privacyProtocols: SelectKeyValueString[] = [ + {key: 'DES', value: 'des'}, + {key: 'AES', value: 'aes'}, + {key: 'AES128', value: 'aes128'}, + {key: '3DES', value: '3des'}, + {key: '3DESDE', value: '3desde'}, + ]; + protected interfaceServicetemplate: InterfaceServicetemplate = {} as InterfaceServicetemplate; + + protected override wizardLoad(result: CiscoWlcWizardGet): void { + this.interfaceServicetemplate = result.interfaceServicetemplate; + + super.wizardLoad(result); + } + + public override submit(): void { + // let request = this.post; // Clone the original post object here! + let request: CiscoWlcWizardPost = JSON.parse(JSON.stringify(this.post)); + + // Remove all services from request where createService is false. + request.services = request.services.filter((service: Service) => { + return service.createService && this.childComponent.hasName(service.name); + }); + // Remove all interfaces from request where createService is false. + request.interfaces = []; + + this.subscriptions.add(this.WizardService.submit(request) + .subscribe((result: GenericResponseWrapper) => { + this.errors = {} as GenericValidationError; + if (result.success) { + const title: string = this.TranslocoService.translate('Success'); + const msg: string = this.TranslocoService.translate('Data saved successfully'); + + this.notyService.genericSuccess(msg, title); + this.router.navigate(['/services/notMonitored']); + this.cdr.markForCheck(); + return; + } + // Error + this.notyService.genericError(); + this.notyService.scrollContentDivToTop(); + const errorResponse: GenericValidationError = result.data as GenericValidationError; + if (result) { + this.errors = errorResponse; + + } + this.cdr.markForCheck(); + }) + ); + } + + protected toggleCheck(checked: boolean): void { + this.checked = checked; + this.post.interfaces.forEach((service: N0) => { + if (!this.hasName(service.name)) { + return; + } + service.createService = this.checked; + }); + this.cdr.markForCheck(); + } + + protected toggleAccordionClose(checked: boolean): void { + this.accordionClosed = checked; + this.accordionItems.forEach((accordionItem: AccordionItemComponent) => { + if ((accordionItem.visible && this.accordionClosed) || (!accordionItem.visible && !this.accordionClosed)) { + accordionItem.toggleItem(); + } + }); + this.cdr.markForCheck(); + } + + protected detectColor = function (label: string): string { + if (label.match(/warning/gi)) { + return 'warning'; + } + + if (label.match(/critical/gi)) { + return 'critical'; + } + + return ''; + }; + + protected hasName = (name: string): boolean => { + if (this.searchedTags.length === 0) { + return true; + } + return this.searchedTags.some((tag) => { + return name.toLowerCase().includes(tag.toLowerCase()); + }); + } + +} From 5ff0dfb8a0939f9fa0ed8ec9c68811bb7031b9b6 Mon Sep 17 00:00:00 2001 From: ibering Date: Wed, 15 Oct 2025 10:37:31 +0200 Subject: [PATCH 19/48] #ITC-3595 Import Module: Add support for FlowChief: External monitorings (ImportedHosts edit view - tags added) --- .../imported-hosts-edit.component.html | 23 +++++++++++++++++++ .../imported-hosts-edit.component.ts | 10 ++++++-- .../importedhosts/importedhosts.interface.ts | 1 + .../importedhosts/importedhosts.service.ts | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/modules/import_module/pages/importedhosts/imported-hosts-edit/imported-hosts-edit.component.html b/src/app/modules/import_module/pages/importedhosts/imported-hosts-edit/imported-hosts-edit.component.html index b2b792118..fd4db054c 100644 --- a/src/app/modules/import_module/pages/importedhosts/imported-hosts-edit/imported-hosts-edit.component.html +++ b/src/app/modules/import_module/pages/importedhosts/imported-hosts-edit/imported-hosts-edit.component.html @@ -140,6 +140,29 @@
    +
    + + + + + + +
    + {{ t('Press return to separate tags') }} +
    +
    +
    diff --git a/src/app/pages/hostgroups/hostgroups-append/hostgroups-append.component.ts b/src/app/pages/hostgroups/hostgroups-append/hostgroups-append.component.ts index 7c531a929..26ed5602f 100644 --- a/src/app/pages/hostgroups/hostgroups-append/hostgroups-append.component.ts +++ b/src/app/pages/hostgroups/hostgroups-append/hostgroups-append.component.ts @@ -2,24 +2,19 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestro import { BackButtonDirective } from '../../../directives/back-button.directive'; import { HistoryService } from '../../../history.service'; import { - AlertComponent, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FormDirective, - FormLabelDirective, - NavComponent, - NavItemComponent + AlertComponent, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FormDirective, + FormLabelDirective, + NavComponent, + NavItemComponent } from '@coreui/angular'; -import { CoreuiComponent } from '../../../layouts/coreui/coreui.component'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; - - import { FormsModule } from '@angular/forms'; - - import { PaginatorModule } from 'primeng/paginator'; import { PermissionDirective } from '../../../permissions/permission.directive'; import { RequiredIconComponent } from '../../../components/required-icon/required-icon.component'; @@ -30,40 +25,45 @@ import { HostgroupsService } from '../hostgroups.service'; import { HostgroupAppend, HostgroupsLoadHostgroupsByStringParams } from '../hostgroups.interface'; import { Subscription } from 'rxjs'; import { SelectKeyValue } from '../../../layouts/primeng/select.interface'; -import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { ActivatedRoute, RouterLink } from '@angular/router'; import { NotyService } from '../../../layouts/coreui/noty.service'; -import { GenericResponseWrapper } from '../../../generic-responses'; +import { GenericIdResponse, GenericValidationError } from '../../../generic-responses'; +import { FormErrorDirective } from '../../../layouts/coreui/form-error.directive'; +import { FormFeedbackComponent } from '../../../layouts/coreui/form-feedback/form-feedback.component'; + @Component({ selector: 'oitc-hostgroups-append', imports: [ - BackButtonDirective, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FaIconComponent, - FormDirective, - FormLabelDirective, - FormsModule, - NavComponent, - NavItemComponent, - PaginatorModule, - PermissionDirective, - RequiredIconComponent, - SelectComponent, - TranslocoDirective, - XsButtonDirective, - AlertComponent, - RouterLink -], + BackButtonDirective, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FaIconComponent, + FormDirective, + FormLabelDirective, + FormErrorDirective, + FormsModule, + NavComponent, + NavItemComponent, + PaginatorModule, + PermissionDirective, + RequiredIconComponent, + SelectComponent, + TranslocoDirective, + XsButtonDirective, + AlertComponent, + RouterLink, + FormFeedbackComponent + ], templateUrl: './hostgroups-append.component.html', styleUrl: './hostgroups-append.component.css', changeDetection: ChangeDetectionStrategy.OnPush }) export class HostgroupsAppendComponent implements OnInit, OnDestroy { - private readonly Subscription: Subscription = new Subscription(); + private readonly subscriptions: Subscription = new Subscription(); private readonly HostgroupsService: HostgroupsService = inject(HostgroupsService); private readonly notyService: NotyService = inject(NotyService); private readonly TranslocoService: TranslocoService = inject(TranslocoService); @@ -78,34 +78,57 @@ export class HostgroupsAppendComponent implements OnInit, OnDestroy { } }; protected hostgroups: SelectKeyValue[] = []; + public errors: GenericValidationError | null = null; private cdr = inject(ChangeDetectorRef); + public ngOnInit() { + this.loadHostgroups(''); + this.cdr.markForCheck(); + } + + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); + } + + protected loadHostgroups = (search: string) => { + this.subscriptions.add(this.HostgroupsService.loadHostgroupsByString({ + 'filter[Containers.name]': search + } as HostgroupsLoadHostgroupsByStringParams).subscribe((data: SelectKeyValue[]) => { + this.hostgroups = data; + this.cdr.markForCheck(); + })); + } + protected submit(): void { const hostIds = this.route.snapshot.paramMap.get('hostids'); if (hostIds) { this.post.Hostgroup.hosts._ids = hostIds.split(',').map(Number); } - this.Subscription.add(this.HostgroupsService.appendHosts(this.post).subscribe((result: GenericResponseWrapper) => { - this.cdr.markForCheck(); - const title = this.TranslocoService.translate('Host group'); - const msg = this.TranslocoService.translate('saved successfully'); - const url = ['hostgroups', 'edit', this.post.Hostgroup.id]; + this.subscriptions.add(this.HostgroupsService.appendHosts(this.post) + .subscribe((result) => { + this.cdr.markForCheck(); + if (result.success) { + const response = result.data as GenericIdResponse; - this.notyService.genericSuccess(msg, title, url); - this.HistoryService.navigateWithFallback(['/hostgroups/index']); - })); - } + const title = this.TranslocoService.translate('Append hosts to host group'); + const msg = this.TranslocoService.translate(' successfully'); + const url = ['hostgroups', 'edit', response.id]; - public ngOnInit() { - this.Subscription.add(this.HostgroupsService.loadHostgroupsByString({} as HostgroupsLoadHostgroupsByStringParams).subscribe((data: SelectKeyValue[]) => { - this.hostgroups = data; - this.cdr.markForCheck(); - })); - } + this.notyService.genericSuccess(msg, title, url); - ngOnDestroy(): void { - this.Subscription.unsubscribe(); - } + this.notyService.scrollContentDivToTop(); + this.HistoryService.navigateWithFallback(['/hosts/index']); + return; + } + // Error + const errorResponse = result.data as GenericValidationError; + this.notyService.genericError(); + if (result) { + this.errors = errorResponse; + } + }) + ); + } } diff --git a/src/app/pages/hostgroups/hostgroups.service.ts b/src/app/pages/hostgroups/hostgroups.service.ts index d1e894c4c..62c77eed1 100644 --- a/src/app/pages/hostgroups/hostgroups.service.ts +++ b/src/app/pages/hostgroups/hostgroups.service.ts @@ -24,7 +24,12 @@ import { } from "./hostgroups.interface"; import { HttpClient } from "@angular/common/http"; import { PROXY_PATH } from "../../tokens/proxy-path.token"; -import { GenericIdResponse, GenericResponseWrapper, GenericValidationError } from "../../generic-responses"; +import { + GenericActionErrorResponse, + GenericIdResponse, + GenericResponseWrapper, + GenericValidationError +} from "../../generic-responses"; import { DeleteAllItem } from "../../layouts/coreui/delete-all-modal/delete-all.interface"; import { SelectKeyValue } from '../../layouts/primeng/select.interface'; @@ -243,7 +248,27 @@ export class HostgroupsService { public appendHosts(param: HostgroupAppend): Observable { const proxyPath: string = this.proxyPath; - return this.http.post(`${proxyPath}/hostgroups/append/.json?angular=true`, param); + return this.http.post(`${proxyPath}/hostgroups/append/.json?angular=true`, param) + .pipe( + map(data => { + // Return true on 200 Ok + return { + success: true, + data: data as GenericIdResponse + }; + }), + catchError((error: any) => { + const err = error.error.message as GenericActionErrorResponse; + return of({ + success: false, + data: { + hostgroup_id: { + err + } + } + }); + }) + ); } public loadHostgroupsByContainerId(containerId: number, selected: any[], resolveContainerIds: boolean = true): Observable { diff --git a/src/app/pages/hosts/hosts-index/hosts-index.component.html b/src/app/pages/hosts/hosts-index/hosts-index.component.html index bcc46d0f1..4ef15ac7c 100644 --- a/src/app/pages/hosts/hosts-index/hosts-index.component.html +++ b/src/app/pages/hosts/hosts-index/hosts-index.component.html @@ -1254,7 +1254,7 @@
    - + {{ t('Add to host group') }} diff --git a/src/app/pages/hosts/hosts-index/hosts-index.component.ts b/src/app/pages/hosts/hosts-index/hosts-index.component.ts index 44892f19d..a4facddae 100644 --- a/src/app/pages/hosts/hosts-index/hosts-index.component.ts +++ b/src/app/pages/hosts/hosts-index/hosts-index.component.ts @@ -317,7 +317,7 @@ export class HostsIndexComponent implements OnInit, OnDestroy, IndexPage { this.filter['Hosts.address'] = address; } - let address_regex = params['address_regex'] ; + let address_regex = params['address_regex']; if (address_regex === 'true') { this.filter['Hosts.address_regex'] = true; } @@ -596,7 +596,7 @@ export class HostsIndexComponent implements OnInit, OnDestroy, IndexPage { let ids = this.SelectionServiceService.getSelectedItems().map(item => item.Host.id).join(','); if (ids) { this.router.navigate(['/', 'hosts', 'copy', ids]); - }else { + } else { const message = this.TranslocoService.translate('No items selected!'); this.notyService.genericError(message); return; diff --git a/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.html b/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.html index 2499474c6..583ba31dd 100644 --- a/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.html +++ b/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.html @@ -54,8 +54,12 @@
    [(ngModel)]="post.Servicegroup.id" optionValue="key" optionLabel="value" - [options]="servicegroups"> + [options]="servicegroups" + [searchCallback]="loadServicegroups" + oitcFormError [errors]="errors" errorField="servicegroup_id"> +
    @@ -82,4 +86,3 @@
    - diff --git a/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.ts b/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.ts index ba6680a40..2b1e9ba2a 100644 --- a/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.ts +++ b/src/app/pages/servicegroups/servicegroups-append/servicegroups-append.component.ts @@ -2,18 +2,17 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestro import { BackButtonDirective } from '../../../directives/back-button.directive'; import { HistoryService } from '../../../history.service'; import { - AlertComponent, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FormDirective, - FormLabelDirective, - NavComponent, - NavItemComponent + AlertComponent, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FormDirective, + FormLabelDirective, + NavComponent, + NavItemComponent } from '@coreui/angular'; -import { CoreuiComponent } from '../../../layouts/coreui/coreui.component'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; @@ -27,43 +26,48 @@ import { SelectComponent } from '../../../layouts/primeng/select/select/select.c import { TranslocoDirective, TranslocoService } from '@jsverse/transloco'; import { XsButtonDirective } from '../../../layouts/coreui/xsbutton-directive/xsbutton.directive'; import { ServicegroupsService } from '../servicegroups.service'; -import { ServicegroupAppend, ServicegroupsLoadServicegroupsByStringParams } from '../servicegroups.interface'; +import { ServicegroupAppend } from '../servicegroups.interface'; import { Subscription } from 'rxjs'; import { SelectKeyValue } from '../../../layouts/primeng/select.interface'; import { ActivatedRoute, RouterLink } from '@angular/router'; import { NotyService } from '../../../layouts/coreui/noty.service'; -import { GenericResponseWrapper } from '../../../generic-responses'; +import { GenericIdResponse, GenericValidationError } from '../../../generic-responses'; +import { HostgroupsLoadHostgroupsByStringParams } from '../../hostgroups/hostgroups.interface'; +import { FormErrorDirective } from '../../../layouts/coreui/form-error.directive'; +import { FormFeedbackComponent } from '../../../layouts/coreui/form-feedback/form-feedback.component'; @Component({ selector: 'oitc-servicegroups-append', imports: [ - BackButtonDirective, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FaIconComponent, - FormDirective, - FormLabelDirective, - FormsModule, - NavComponent, - NavItemComponent, - PaginatorModule, - PermissionDirective, - RequiredIconComponent, - SelectComponent, - TranslocoDirective, - XsButtonDirective, - AlertComponent, - RouterLink -], + BackButtonDirective, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FaIconComponent, + FormDirective, + FormLabelDirective, + FormsModule, + NavComponent, + NavItemComponent, + PaginatorModule, + PermissionDirective, + RequiredIconComponent, + SelectComponent, + TranslocoDirective, + XsButtonDirective, + AlertComponent, + RouterLink, + FormErrorDirective, + FormFeedbackComponent + ], templateUrl: './servicegroups-append.component.html', styleUrl: './servicegroups-append.component.css', changeDetection: ChangeDetectionStrategy.OnPush }) export class ServicegroupsAppendComponent implements OnInit, OnDestroy { - private readonly Subscription: Subscription = new Subscription(); + private readonly subscriptions: Subscription = new Subscription(); private readonly ServicegroupsService: ServicegroupsService = inject(ServicegroupsService); private readonly notyService: NotyService = inject(NotyService); private readonly TranslocoService: TranslocoService = inject(TranslocoService); @@ -72,6 +76,7 @@ export class ServicegroupsAppendComponent implements OnInit, OnDestroy { private readonly cdr = inject(ChangeDetectorRef); protected servicegroups: SelectKeyValue[] = []; + public errors: GenericValidationError | null = null; protected post: ServicegroupAppend = { Servicegroup: { services: { @@ -81,36 +86,56 @@ export class ServicegroupsAppendComponent implements OnInit, OnDestroy { } }; - protected submit(): void { - const serviceIds = this.route.snapshot.paramMap.get('serviceids'); - if (serviceIds) { - this.post.Servicegroup.services._ids = serviceIds.split(',').map(Number); - } - - this.Subscription.add(this.ServicegroupsService.appendServices(this.post).subscribe((result: GenericResponseWrapper) => { - - this.cdr.markForCheck(); - - const title = this.TranslocoService.translate('Service group'); - const msg = this.TranslocoService.translate('saved successfully'); - const url = ['servicegroups', 'edit', this.post.Servicegroup.id]; - - this.notyService.genericSuccess(msg, title, url); + public ngOnInit() { + this.loadServicegroups(''); + this.cdr.markForCheck(); + } - this.HistoryService.navigateWithFallback(['/servicegroups/index']); - })); + ngOnDestroy(): void { + this.subscriptions.unsubscribe(); } - public ngOnInit() { - this.Subscription.add(this.ServicegroupsService.loadServicegroupsByString({} as ServicegroupsLoadServicegroupsByStringParams).subscribe((data: SelectKeyValue[]) => { + protected loadServicegroups = (search: string) => { + this.subscriptions.add(this.ServicegroupsService.loadServicegroupsByString({ + 'filter[Containers.name]': search + } as HostgroupsLoadHostgroupsByStringParams).subscribe((data: SelectKeyValue[]) => { this.servicegroups = data; this.cdr.markForCheck(); })); } - ngOnDestroy(): void { - this.Subscription.unsubscribe(); + protected submit(): void { + const serviceIds = this.route.snapshot.paramMap.get('serviceids'); + if (serviceIds) { + this.post.Servicegroup.services._ids = serviceIds.split(',').map(Number); + } + + this.subscriptions.add(this.ServicegroupsService.appendServices(this.post) + .subscribe((result) => { + this.cdr.markForCheck(); + if (result.success) { + const response = result.data as GenericIdResponse; + + const title = this.TranslocoService.translate('Append services to service group'); + const msg = this.TranslocoService.translate(' successfully'); + const url = ['servicegroups', 'edit', response.id]; + + this.notyService.genericSuccess(msg, title, url); + + this.notyService.scrollContentDivToTop(); + this.HistoryService.navigateWithFallback(['/services/index']); + return; + } + + // Error + const errorResponse = result.data as GenericValidationError; + this.notyService.genericError(); + if (result) { + this.errors = errorResponse; + } + }) + ); } } diff --git a/src/app/pages/servicegroups/servicegroups.service.ts b/src/app/pages/servicegroups/servicegroups.service.ts index 78ba438f3..7e99c7f8a 100644 --- a/src/app/pages/servicegroups/servicegroups.service.ts +++ b/src/app/pages/servicegroups/servicegroups.service.ts @@ -23,7 +23,12 @@ import { } from "./servicegroups.interface"; import { HttpClient } from "@angular/common/http"; import { PROXY_PATH } from "../../tokens/proxy-path.token"; -import { GenericIdResponse, GenericResponseWrapper, GenericValidationError } from "../../generic-responses"; +import { + GenericActionErrorResponse, + GenericIdResponse, + GenericResponseWrapper, + GenericValidationError +} from "../../generic-responses"; import { DeleteAllItem } from "../../layouts/coreui/delete-all-modal/delete-all.interface"; import { SelectKeyValue } from '../../layouts/primeng/select.interface'; @@ -228,7 +233,27 @@ export class ServicegroupsService { public appendServices(param: ServicegroupAppend): Observable { const proxyPath: string = this.proxyPath; - return this.http.post(`${proxyPath}/servicegroups/append/.json?angular=true`, param); + return this.http.post(`${proxyPath}/servicegroups/append/.json?angular=true`, param) + .pipe( + map(data => { + // Return true on 200 Ok + return { + success: true, + data: data as GenericIdResponse + }; + }), + catchError((error: any) => { + const err = error.error.message as GenericActionErrorResponse; + return of({ + success: false, + data: { + servicegroup_id: { + err + } + } + }); + }) + ); } public loadServicegroupsByContainerId(containerId: number, selected: any[], resolveContainerIds: boolean = true): Observable { diff --git a/src/app/pages/services/services-index/services-index.component.html b/src/app/pages/services/services-index/services-index.component.html index 7126b3613..0bbb5a6c6 100644 --- a/src/app/pages/services/services-index/services-index.component.html +++ b/src/app/pages/services/services-index/services-index.component.html @@ -941,7 +941,7 @@
  • - + {{ t('Add to service group') }}
  • From 312396e1aea0478df9812cb3ed7d83c2979dc511 Mon Sep 17 00:00:00 2001 From: ibering Date: Wed, 15 Oct 2025 15:48:09 +0200 Subject: [PATCH 21/48] #ITC-3612 Append to hostgroup/servicegroup search won't load new elements and missing validation in service template groups assignments (allocateToHost, allocateToHostgroup) --- ...lategroups-allocate-to-host.component.html | 11 +- ...mplategroups-allocate-to-host.component.ts | 102 ++++++++---------- ...roups-allocate-to-hostgroup.component.html | 15 +-- ...egroups-allocate-to-hostgroup.component.ts | 76 ++++++------- .../servicetemplategroups.service.ts | 33 ++++-- 5 files changed, 120 insertions(+), 117 deletions(-) diff --git a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.html b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.html index 4560f1d75..87c0fbc7c 100644 --- a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.html +++ b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.html @@ -20,7 +20,7 @@ -
    +
    @@ -55,7 +55,7 @@
    id="servicetemplategroupId" [(ngModel)]="servicetemplategroupId" optionValue="key" - (ngModelChange)="hostIdChanged()" + (onChange)="loadServices()" optionLabel="value" [searchCallback]="loadServicetemplategroups" [options]="servicetemplategroups" @@ -78,7 +78,7 @@
    name="hostId" id="hostId" [(ngModel)]="hostId" - (ngModelChange)="hostIdChanged()" + (onChange)="loadServices()" optionValue="key" optionLabel="value" [searchCallback]="loadHosts" @@ -115,7 +115,7 @@
    {{ t('Service/s to deploy on target host:') }}
    + *ngFor="let hostWithServicesToDeploy of hostsWithServicetemplatesForDeploy; let i = index;">
    - - - diff --git a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.ts b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.ts index 1203fb4b3..a7b41e89f 100644 --- a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.ts +++ b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-host/servicetemplategroups-allocate-to-host.component.ts @@ -1,19 +1,18 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnDestroy, OnInit } from '@angular/core'; import { BackButtonDirective } from '../../../directives/back-button.directive'; import { - AlertComponent, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FormCheckInputDirective, - FormDirective, - FormLabelDirective, - NavComponent, - NavItemComponent, - ProgressComponent, - TooltipDirective + AlertComponent, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FormCheckInputDirective, + FormDirective, + FormLabelDirective, + NavComponent, + NavItemComponent, + TooltipDirective } from '@coreui/angular'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { FormErrorDirective } from '../../../layouts/coreui/form-error.directive'; @@ -48,35 +47,34 @@ import { HistoryService } from '../../../history.service'; @Component({ selector: 'oitc-servicetemplategroups-allocate-to-host', imports: [ - BackButtonDirective, - CardBodyComponent, - CardComponent, - CardFooterComponent, - CardHeaderComponent, - CardTitleDirective, - FaIconComponent, - FormCheckInputDirective, - FormDirective, - FormErrorDirective, - FormFeedbackComponent, - FormLabelDirective, - FormsModule, - NavComponent, - NavItemComponent, - NgForOf, - NgIf, - NgSelectModule, - PermissionDirective, - RequiredIconComponent, - TranslocoDirective, - XsButtonDirective, - AlertComponent, - TranslocoPipe, - ProgressComponent, - RouterLink, - SelectComponent, - TooltipDirective -], + BackButtonDirective, + CardBodyComponent, + CardComponent, + CardFooterComponent, + CardHeaderComponent, + CardTitleDirective, + FaIconComponent, + FormCheckInputDirective, + FormDirective, + FormErrorDirective, + FormFeedbackComponent, + FormLabelDirective, + FormsModule, + NavComponent, + NavItemComponent, + NgForOf, + NgIf, + NgSelectModule, + PermissionDirective, + RequiredIconComponent, + TranslocoDirective, + XsButtonDirective, + AlertComponent, + TranslocoPipe, + RouterLink, + SelectComponent, + TooltipDirective + ], templateUrl: './servicetemplategroups-allocate-to-host.component.html', styleUrl: './servicetemplategroups-allocate-to-host.component.css', changeDetection: ChangeDetectionStrategy.OnPush @@ -100,14 +98,11 @@ export class ServicetemplategroupsAllocateToHostComponent implements OnInit, OnD protected hostsWithServicetemplatesForDeploy: AllocateToHostGetServicetemplatesForDeploy[] = []; protected servicetemplategroupId: number = 0; protected hostId: number = 0; - protected percentage: number = 0; - protected isProcessing: boolean = false; public ngOnInit() { this.servicetemplategroupId = Number(this.route.snapshot.paramMap.get('id')); let hostId: number = Number(this.route.snapshot.paramMap.get('hostId')); if (hostId > 0) { - this.hostId = hostId; } this.loadServicetemplategroups(''); @@ -119,7 +114,7 @@ export class ServicetemplategroupsAllocateToHostComponent implements OnInit, OnD } - private loadServices(): void { + public loadServices(): void { if (this.servicetemplategroupId === 0 || this.hostId === 0) { return; } @@ -131,10 +126,6 @@ export class ServicetemplategroupsAllocateToHostComponent implements OnInit, OnD ) } - protected hostIdChanged(): void { - this.loadServices(); - } - protected selectAll(): void { if (typeof this.hostsWithServicetemplatesForDeploy === "undefined") { return; @@ -155,7 +146,7 @@ export class ServicetemplategroupsAllocateToHostComponent implements OnInit, OnD } - protected allocateToHost(): void { + protected submit(): void { let item: AllocateToHostPost = { Host: { @@ -170,19 +161,10 @@ export class ServicetemplategroupsAllocateToHostComponent implements OnInit, OnD item.Servicetemplates._ids.push(this.hostsWithServicetemplatesForDeploy[hostIndex].servicetemplate.id); } } - this.isProcessing = true; - let i = 0; - let count = item.Servicetemplates._ids.length; - this.ServicetemplategroupsService.allocateToHost(this.servicetemplategroupId, item); - - this.subscriptions.add(this.ServicetemplategroupsService.allocateToHost(this.servicetemplategroupId, item) .subscribe((result: GenericResponseWrapper) => { this.cdr.markForCheck(); if (result.success) { - i++; - this.percentage = Math.round(i / count * 100); - this.notyService.genericSuccess(); this.HistoryService.navigateWithFallback(['/servicetemplategroups/index']); return; diff --git a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-hostgroup/servicetemplategroups-allocate-to-hostgroup.component.html b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-hostgroup/servicetemplategroups-allocate-to-hostgroup.component.html index c6d5258f9..812f27d08 100644 --- a/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-hostgroup/servicetemplategroups-allocate-to-hostgroup.component.html +++ b/src/app/pages/servicetemplategroups/servicetemplategroups-allocate-to-hostgroup/servicetemplategroups-allocate-to-hostgroup.component.html @@ -20,7 +20,7 @@ - +
    @@ -55,7 +55,7 @@
    id="servicetemplategroupId" [(ngModel)]="servicetemplategroupId" optionValue="key" - (ngModelChange)="hostGroupIdChanged()" + (onChange)="loadServices()" optionLabel="value" [searchCallback]="loadServicetemplategroups" [options]="servicetemplategroups" @@ -78,7 +78,7 @@
    name="hostgroupId" id="hostgroupId" [(ngModel)]="hostgroupId" - (ngModelChange)="hostGroupIdChanged()" + (onChange)="loadServices()" optionValue="key" optionLabel="value" [searchCallback]="loadHostgroups" @@ -114,7 +114,8 @@
    + *ngFor="let hostWithServicesToDeploy of hostsWithServicetemplatesForDeploy; let i = index;" + class="mb-3">