From bbd8d7fd8da5861c94d52eb3fe520ffad6f9e054 Mon Sep 17 00:00:00 2001 From: Scott Aslan Date: Tue, 9 Jan 2024 11:48:19 -0500 Subject: [PATCH] [NIFI-12563] configure reporting task (#8208) * [NIFI-12563] configure reporting task * move types to appropriate place * address dialog resizing issue for reporting task configuration * add configureReportingTask to reducer * final touches * remove unused inputs * remove unused import This closes #8208 --- .../feature/settings-routing.module.ts | 8 +- .../service/reporting-task.service.ts | 19 +- .../management-controller-services.effects.ts | 6 +- .../settings/state/reporting-tasks/index.ts | 27 +- .../reporting-tasks.actions.ts | 25 +- .../reporting-tasks.effects.ts | 273 +++++++++++- .../reporting-tasks.reducer.ts | 13 +- .../reporting-tasks.selectors.ts | 17 +- .../edit-reporting-task.component.html | 111 +++++ .../edit-reporting-task.component.scss | 43 ++ .../edit-reporting-task.component.spec.ts | 398 ++++++++++++++++++ .../edit-reporting-task.component.ts | 214 ++++++++++ .../reporting-task-table.component.html | 6 +- .../reporting-task-table.component.ts | 6 + .../reporting-tasks.component.html | 1 + .../reporting-tasks.component.ts | 50 ++- .../reporting-tasks/reporting-tasks.module.ts | 10 +- .../main/nifi/src/app/state/shared/index.ts | 5 + .../enable-controller-service.component.html | 4 +- 19 files changed, 1210 insertions(+), 26 deletions(-) create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.html create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.scss create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.spec.ts create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.ts diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts index 9675c24b41..85a5965a87 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts @@ -57,7 +57,13 @@ const routes: Routes = [ children: [ { path: ':id', - component: ReportingTasks + component: ReportingTasks, + children: [ + { + path: 'edit', + component: ReportingTasks + } + ] } ] }, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/reporting-task.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/reporting-task.service.ts index 6b736d9732..102fab05c5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/reporting-task.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/reporting-task.service.ts @@ -16,11 +16,12 @@ */ import { Injectable } from '@angular/core'; -import { Observable, throwError } from 'rxjs'; +import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { Client } from '../../../service/client.service'; import { NiFiCommon } from '../../../service/nifi-common.service'; import { + ConfigureReportingTaskRequest, CreateReportingTaskRequest, DeleteReportingTaskRequest, ReportingTaskEntity, @@ -91,7 +92,17 @@ export class ReportingTaskService { return this.httpClient.put(`${this.stripProtocol(entity.uri)}/run-status`, payload); } - // updateControllerConfig(controllerEntity: ControllerEntity): Observable { - // return this.httpClient.put(`${ControllerServiceService.API}/controller/config`, controllerEntity); - // } + getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable { + const params: any = { + propertyName, + sensitive + }; + return this.httpClient.get(`${ReportingTaskService.API}/reporting-tasks/${id}/descriptors`, { + params + }); + } + + updateReportingTask(configureReportingTask: ConfigureReportingTaskRequest): Observable { + return this.httpClient.put(this.stripProtocol(configureReportingTask.uri), configureReportingTask.payload); + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts index bb9454c979..f800808ed9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts @@ -300,13 +300,13 @@ export class ManagementControllerServicesEffects { }) .pipe( take(1), - switchMap((createReponse) => { + switchMap((createResponse) => { // dispatch an inline create service success action so the new service is in the state this.store.dispatch( ManagementControllerServicesActions.inlineCreateControllerServiceSuccess( { response: { - controllerService: createReponse + controllerService: createResponse } } ) @@ -321,7 +321,7 @@ export class ManagementControllerServicesEffects { createServiceDialogReference.close(); return { - value: createReponse.id, + value: createResponse.id, descriptor: descriptorResponse.propertyDescriptor }; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/index.ts index a6987234c3..bd3022812e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/index.ts @@ -38,6 +38,31 @@ export interface CreateReportingTaskSuccess { reportingTask: ReportingTaskEntity; } +export interface ConfigureReportingTaskRequest { + id: string; + uri: string; + payload: any; + postUpdateNavigation?: string[]; +} + +export interface ConfigureReportingTaskSuccess { + id: string; + reportingTask: ReportingTaskEntity; + postUpdateNavigation?: string[]; +} + +export interface ConfigureReportingTaskRequest { + id: string; + uri: string; + payload: any; + postUpdateNavigation?: string[]; +} + +export interface EditReportingTaskDialogRequest { + id: string; + reportingTask: ReportingTaskEntity; +} + export interface StartReportingTaskRequest { reportingTask: ReportingTaskEntity; } @@ -63,7 +88,7 @@ export interface DeleteReportingTaskSuccess { } export interface SelectReportingTaskRequest { - reportingTask: ReportingTaskEntity; + id: string; } export interface ReportingTaskEntity { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.actions.ts index afbe85006a..ada2a743cd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.actions.ts @@ -21,12 +21,15 @@ import { CreateReportingTaskSuccess, DeleteReportingTaskRequest, DeleteReportingTaskSuccess, + EditReportingTaskDialogRequest, LoadReportingTasksResponse, SelectReportingTaskRequest, StartReportingTaskRequest, StartReportingTaskSuccess, StopReportingTaskRequest, - StopReportingTaskSuccess + StopReportingTaskSuccess, + ConfigureReportingTaskRequest, + ConfigureReportingTaskSuccess } from './index'; export const resetReportingTasksState = createAction('[Reporting Tasks] Reset Reporting Tasks State'); @@ -38,6 +41,21 @@ export const loadReportingTasksSuccess = createAction( props<{ response: LoadReportingTasksResponse }>() ); +export const openConfigureReportingTaskDialog = createAction( + '[Reporting Tasks] Open Reporting Task Dialog', + props<{ request: EditReportingTaskDialogRequest }>() +); + +export const configureReportingTask = createAction( + '[Reporting Tasks] Configure Reporting Task', + props<{ request: ConfigureReportingTaskRequest }>() +); + +export const configureReportingTaskSuccess = createAction( + '[Reporting Tasks] Configure Reporting Task Success', + props<{ response: ConfigureReportingTaskSuccess }>() +); + export const reportingTasksApiError = createAction( '[Reporting Tasks] Load Reporting Tasks Error', props<{ error: string }>() @@ -55,6 +73,11 @@ export const createReportingTaskSuccess = createAction( props<{ response: CreateReportingTaskSuccess }>() ); +export const navigateToEditReportingTask = createAction( + '[Reporting Tasks] Navigate To Edit Reporting Task', + props<{ id: string }>() +); + export const startReportingTask = createAction( '[Reporting Tasks] Start Reporting Task', props<{ request: StartReportingTaskRequest }>() diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.effects.ts index 44bc9619a0..c08215a8ad 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.effects.ts @@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import * as ReportingTaskActions from './reporting-tasks.actions'; -import { catchError, from, map, of, switchMap, take, tap, withLatestFrom } from 'rxjs'; +import { catchError, from, map, NEVER, Observable, of, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; @@ -27,13 +27,34 @@ import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.c import { ReportingTaskService } from '../../service/reporting-task.service'; import { CreateReportingTask } from '../../ui/reporting-tasks/create-reporting-task/create-reporting-task.component'; import { Router } from '@angular/router'; +import { selectSaving } from '../management-controller-services/management-controller-services.selectors'; +import { + InlineServiceCreationRequest, + InlineServiceCreationResponse, + NewPropertyDialogRequest, + NewPropertyDialogResponse, + Property, + PropertyDescriptor, + UpdateControllerServiceRequest +} from '../../../../state/shared'; +import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component'; +import { EditReportingTask } from '../../ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component'; +import { CreateReportingTaskSuccess } from './index'; +import { ExtensionTypesService } from '../../../../service/extension-types.service'; +import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component'; +import { ManagementControllerServiceService } from '../../service/management-controller-service.service'; +import * as ManagementControllerServicesActions from '../management-controller-services/management-controller-services.actions'; +import { Client } from '../../../../service/client.service'; @Injectable() export class ReportingTasksEffects { constructor( private actions$: Actions, private store: Store, + private client: Client, private reportingTaskService: ReportingTaskService, + private managementControllerServiceService: ManagementControllerServiceService, + private extensionTypesService: ExtensionTypesService, private dialog: MatDialog, private router: Router ) {} @@ -112,11 +133,11 @@ export class ReportingTasksEffects { tap(() => { this.dialog.closeAll(); }), - switchMap((response) => + switchMap((response: CreateReportingTaskSuccess) => of( ReportingTaskActions.selectReportingTask({ request: { - reportingTask: response.reportingTask + id: response.reportingTask.id } }) ) @@ -175,6 +196,250 @@ export class ReportingTasksEffects { ) ); + navigateToEditReportingTask$ = createEffect( + () => + this.actions$.pipe( + ofType(ReportingTaskActions.navigateToEditReportingTask), + map((action) => action.id), + tap((id) => { + this.router.navigate(['/settings', 'reporting-tasks', id, 'edit']); + }) + ), + { dispatch: false } + ); + + openConfigureReportingTaskDialog$ = createEffect( + () => + this.actions$.pipe( + ofType(ReportingTaskActions.openConfigureReportingTaskDialog), + map((action) => action.request), + tap((request) => { + const taskId: string = request.id; + + const editDialogReference = this.dialog.open(EditReportingTask, { + data: { + reportingTask: request.reportingTask + }, + id: taskId, + panelClass: 'large-dialog' + }); + + editDialogReference.componentInstance.saving$ = this.store.select(selectSaving); + + editDialogReference.componentInstance.createNewProperty = ( + existingProperties: string[], + allowsSensitive: boolean + ): Observable => { + const dialogRequest: NewPropertyDialogRequest = { existingProperties, allowsSensitive }; + const newPropertyDialogReference = this.dialog.open(NewPropertyDialog, { + data: dialogRequest, + panelClass: 'small-dialog' + }); + + return newPropertyDialogReference.componentInstance.newProperty.pipe( + take(1), + switchMap((dialogResponse: NewPropertyDialogResponse) => { + return this.reportingTaskService + .getPropertyDescriptor(request.id, dialogResponse.name, dialogResponse.sensitive) + .pipe( + take(1), + map((response) => { + newPropertyDialogReference.close(); + + return { + property: dialogResponse.name, + value: null, + descriptor: response.propertyDescriptor + }; + }) + ); + }) + ); + }; + + const goTo = (commands: string[], destination: string): void => { + if (editDialogReference.componentInstance.editReportingTaskForm.dirty) { + const saveChangesDialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Controller Service Configuration', + message: `Save changes before going to this ${destination}?` + }, + panelClass: 'small-dialog' + }); + + saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + editDialogReference.componentInstance.submitForm(commands); + }); + + saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + }); + } else { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + } + }; + + editDialogReference.componentInstance.goToService = (serviceId: string) => { + const commands: string[] = ['/settings', 'management-controller-services', serviceId]; + goTo(commands, 'Controller Service'); + }; + + editDialogReference.componentInstance.createNewService = ( + request: InlineServiceCreationRequest + ): Observable => { + const descriptor: PropertyDescriptor = request.descriptor; + + // fetch all services that implement the requested service api + return this.extensionTypesService + .getImplementingControllerServiceTypes( + // @ts-ignore + descriptor.identifiesControllerService, + descriptor.identifiesControllerServiceBundle + ) + .pipe( + take(1), + switchMap((implementingTypesResponse) => { + // show the create controller service dialog with the types that implemented the interface + const createServiceDialogReference = this.dialog.open(CreateControllerService, { + data: { + controllerServiceTypes: implementingTypesResponse.controllerServiceTypes + }, + panelClass: 'medium-dialog' + }); + + return createServiceDialogReference.componentInstance.createControllerService.pipe( + take(1), + switchMap((controllerServiceType) => { + // typically this sequence would be implemented with ngrx actions, however we are + // currently in an edit session and we need to return both the value (new service id) + // and updated property descriptor so the table renders correctly + return this.managementControllerServiceService + .createControllerService({ + revision: { + clientId: this.client.getClientId(), + version: 0 + }, + controllerServiceType: controllerServiceType.type, + controllerServiceBundle: controllerServiceType.bundle + }) + .pipe( + take(1), + switchMap((createResponse) => { + // dispatch an inline create service success action so the new service is in the state + this.store.dispatch( + ManagementControllerServicesActions.inlineCreateControllerServiceSuccess( + { + response: { + controllerService: createResponse + } + } + ) + ); + + // fetch an updated property descriptor + return this.reportingTaskService + .getPropertyDescriptor(taskId, descriptor.name, false) + .pipe( + take(1), + map((descriptorResponse) => { + createServiceDialogReference.close(); + + return { + value: createResponse.id, + descriptor: + descriptorResponse.propertyDescriptor + }; + }) + ); + }), + catchError((error) => { + // TODO - show error + return NEVER; + }) + ); + }) + ); + }) + ); + }; + + editDialogReference.componentInstance.editReportingTask + .pipe(takeUntil(editDialogReference.afterClosed())) + .subscribe((updateControllerServiceRequest: UpdateControllerServiceRequest) => { + this.store.dispatch( + ReportingTaskActions.configureReportingTask({ + request: { + id: request.reportingTask.id, + uri: request.reportingTask.uri, + payload: updateControllerServiceRequest.payload, + postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation + } + }) + ); + }); + + editDialogReference.afterClosed().subscribe((response) => { + if (response != 'ROUTED') { + this.store.dispatch( + ReportingTaskActions.selectReportingTask({ + request: { + id: taskId + } + }) + ); + } + }); + }) + ), + { dispatch: false } + ); + + configureReportingTask$ = createEffect(() => + this.actions$.pipe( + ofType(ReportingTaskActions.configureReportingTask), + map((action) => action.request), + switchMap((request) => + from(this.reportingTaskService.updateReportingTask(request)).pipe( + map((response) => + ReportingTaskActions.configureReportingTaskSuccess({ + response: { + id: request.id, + reportingTask: response, + postUpdateNavigation: request.postUpdateNavigation + } + }) + ), + catchError((error) => + of( + ReportingTaskActions.reportingTasksApiError({ + error: error.error + }) + ) + ) + ) + ) + ) + ); + + configureReportingTaskSuccess$ = createEffect( + () => + this.actions$.pipe( + ofType(ReportingTaskActions.configureReportingTaskSuccess), + map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } + }) + ), + { dispatch: false } + ); + startReportingTask$ = createEffect(() => this.actions$.pipe( ofType(ReportingTaskActions.startReportingTask), @@ -231,7 +496,7 @@ export class ReportingTasksEffects { ofType(ReportingTaskActions.selectReportingTask), map((action) => action.request), tap((request) => { - this.router.navigate(['/settings', 'reporting-tasks', request.reportingTask.id]); + this.router.navigate(['/settings', 'reporting-tasks', request.id]); }) ), { dispatch: false } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.reducer.ts index 598d926f30..7595438e8a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.reducer.ts @@ -18,6 +18,8 @@ import { createReducer, on } from '@ngrx/store'; import { ReportingTasksState } from './index'; import { + configureReportingTask, + configureReportingTaskSuccess, createReportingTask, createReportingTaskSuccess, deleteReportingTask, @@ -61,7 +63,16 @@ export const reportingTasksReducer = createReducer( error, status: 'error' as const })), - on(createReportingTask, deleteReportingTask, (state, { request }) => ({ + on(configureReportingTaskSuccess, (state, { response }) => { + return produce(state, (draftState) => { + const componentIndex: number = draftState.reportingTasks.findIndex((f: any) => response.id === f.id); + if (componentIndex > -1) { + draftState.reportingTasks[componentIndex] = response.reportingTask; + } + draftState.saving = false; + }); + }), + on(createReportingTask, deleteReportingTask, configureReportingTask, (state, { request }) => ({ ...state, saving: true })), diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.selectors.ts index c30bed4f59..ae9f7ae120 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.selectors.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/reporting-tasks/reporting-tasks.selectors.ts @@ -17,7 +17,7 @@ import { createSelector } from '@ngrx/store'; import { selectSettingsState, SettingsState } from '../index'; -import { reportingTasksFeatureKey, ReportingTasksState } from './index'; +import { ReportingTaskEntity, reportingTasksFeatureKey, ReportingTasksState } from './index'; import { selectCurrentRoute } from '../../../../state/router/router.selectors'; export const selectReportingTasksState = createSelector( @@ -34,3 +34,18 @@ export const selectReportingTaskIdFromRoute = createSelector(selectCurrentRoute, } return null; }); + +export const selectSingleEditedReportingTask = createSelector(selectCurrentRoute, (route) => { + if (route?.routeConfig?.path == 'edit') { + return route.params.id; + } + return null; +}); + +export const selectReportingTasks = createSelector( + selectReportingTasksState, + (state: ReportingTasksState) => state.reportingTasks +); + +export const selectTask = (id: string) => + createSelector(selectReportingTasks, (tasks: ReportingTaskEntity[]) => tasks.find((task) => id == task.id)); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.html new file mode 100644 index 0000000000..98115cb083 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.html @@ -0,0 +1,111 @@ + + +

Edit Reporting Task

+
+ + + +
+
+
+ + Name + + + Enabled +
+
+
Id
+
{{ request.reportingTask.id }}
+
+
+
Type
+
{{ formatType(request.reportingTask) }}
+
+
+
Bundle
+
{{ formatBundle(request.reportingTask) }}
+
+
+
+
+ + Scheduling Strategy + + + {{ option.text }} + + + +
+
+ + Run Schedule + + +
+
+
+
+ +
+ + +
+
+ +
+ + Comments + + +
+
+
+
+ + + + +
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.scss new file mode 100644 index 0000000000..2a17b60fbf --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.scss @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@use '@angular/material' as mat; + +.reporting-task-edit-form { + @include mat.button-density(-1); + + .mdc-dialog__content { + padding: 0 16px; + font-size: 14px; + + .tab-content { + height: 475px; + overflow-y: auto; + } + } + + .mat-mdc-form-field { + width: 100%; + } + + .supports-reporting-tasks { + ul { + list-style: disc outside; + margin-left: 1em; + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.spec.ts new file mode 100644 index 0000000000..b252b762d7 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.spec.ts @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditReportingTask } from './edit-reporting-task.component'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { EditReportingTaskDialogRequest } from '../../../state/reporting-tasks'; + +describe('EditReportingTask', () => { + let component: EditReportingTask; + let fixture: ComponentFixture; + + const data: EditReportingTaskDialogRequest = { + id: 'd5142be7-018c-1000-7105-2b1163fe0355', + reportingTask: { + revision: { + clientId: 'da266443-018c-1000-7dd0-9fee5271e3e1', + version: 22 + }, + id: 'd5142be7-018c-1000-7105-2b1163fe0355', + uri: 'https://localhost:8443/nifi-api/reporting-tasks/d5142be7-018c-1000-7105-2b1163fe0355', + permissions: { + canRead: true, + canWrite: true + }, + bulletins: [], + component: { + id: 'd5142be7-018c-1000-7105-2b1163fe0355', + name: 'SiteToSiteMetricsReportingTask', + type: 'org.apache.nifi.reporting.SiteToSiteMetricsReportingTask', + bundle: { + group: 'org.apache.nifi', + artifact: 'nifi-site-to-site-reporting-nar', + version: '2.0.0-SNAPSHOT' + }, + state: 'DISABLED', + comments: 'iutfiugviugv', + persistsState: false, + restricted: false, + deprecated: false, + multipleVersionsAvailable: false, + supportsSensitiveDynamicProperties: false, + schedulingPeriod: '5 mins', + schedulingStrategy: 'TIMER_DRIVEN', + defaultSchedulingPeriod: { + TIMER_DRIVEN: '0 sec', + CRON_DRIVEN: '* * * * * ?' + }, + properties: { + 'Destination URL': null, + 'Input Port Name': null, + 'SSL Context Service': null, + 'Instance URL': 'http://${hostname(true)}:8080/nifi', + 'Compress Events': 'true', + 'Communications Timeout': '30 secs', + 's2s-transport-protocol': 'RAW', + 's2s-http-proxy-hostname': null, + 's2s-http-proxy-port': null, + 's2s-http-proxy-username': null, + 's2s-http-proxy-password': null, + 'record-writer': null, + 'include-null-values': 'false', + 's2s-metrics-hostname': '${hostname(true)}', + 's2s-metrics-application-id': 'nifi', + 's2s-metrics-format': 'ambari-format' + }, + descriptors: { + 'Destination URL': { + name: 'Destination URL', + displayName: 'Destination URL', + description: + 'The URL of the destination NiFi instance or, if clustered, a comma-separated list of address in the format of http(s)://host:port/nifi. This destination URL will only be used to initiate the Site-to-Site connection. The data sent by this reporting task will be load-balanced on all the nodes of the destination (if clustered).', + required: true, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables defined at JVM level and system properties', + dependencies: [] + }, + 'Input Port Name': { + name: 'Input Port Name', + displayName: 'Input Port Name', + description: 'The name of the Input Port to deliver data to.', + required: true, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables defined at JVM level and system properties', + dependencies: [] + }, + 'SSL Context Service': { + name: 'SSL Context Service', + displayName: 'SSL Context Service', + description: + 'The SSL Context Service to use when communicating with the destination. If not specified, communications will not be secure.', + allowableValues: [ + { + allowableValue: { + displayName: 'StandardRestrictedSSLContextService', + value: 'd636f255-018c-1000-42a8-822c72a22795' + }, + canRead: true + } + ], + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + identifiesControllerService: 'org.apache.nifi.ssl.RestrictedSSLContextService', + identifiesControllerServiceBundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + }, + dependencies: [] + }, + 'Instance URL': { + name: 'Instance URL', + displayName: 'Instance URL', + description: 'The URL of this instance to use in the Content URI of each event.', + defaultValue: 'http://${hostname(true)}:8080/nifi', + required: true, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables defined at JVM level and system properties', + dependencies: [] + }, + 'Compress Events': { + name: 'Compress Events', + displayName: 'Compress Events', + description: 'Indicates whether or not to compress the data being sent.', + defaultValue: 'true', + allowableValues: [ + { + allowableValue: { + displayName: 'true', + value: 'true' + }, + canRead: true + }, + { + allowableValue: { + displayName: 'false', + value: 'false' + }, + canRead: true + } + ], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 'Communications Timeout': { + name: 'Communications Timeout', + displayName: 'Communications Timeout', + description: + 'Specifies how long to wait to a response from the destination before deciding that an error has occurred and canceling the transaction', + defaultValue: '30 secs', + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-transport-protocol': { + name: 's2s-transport-protocol', + displayName: 'Transport Protocol', + description: 'Specifies which transport protocol to use for Site-to-Site communication.', + defaultValue: 'RAW', + allowableValues: [ + { + allowableValue: { + displayName: 'RAW', + value: 'RAW' + }, + canRead: true + }, + { + allowableValue: { + displayName: 'HTTP', + value: 'HTTP' + }, + canRead: true + } + ], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-http-proxy-hostname': { + name: 's2s-http-proxy-hostname', + displayName: 'HTTP Proxy hostname', + description: + "Specify the proxy server's hostname to use. If not specified, HTTP traffics are sent directly to the target NiFi instance.", + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-http-proxy-port': { + name: 's2s-http-proxy-port', + displayName: 'HTTP Proxy port', + description: + "Specify the proxy server's port number, optional. If not specified, default port 80 will be used.", + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-http-proxy-username': { + name: 's2s-http-proxy-username', + displayName: 'HTTP Proxy username', + description: 'Specify an user name to connect to the proxy server, optional.', + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-http-proxy-password': { + name: 's2s-http-proxy-password', + displayName: 'HTTP Proxy password', + description: 'Specify an user password to connect to the proxy server, optional.', + required: false, + sensitive: true, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 'record-writer': { + name: 'record-writer', + displayName: 'Record Writer', + description: 'Specifies the Controller Service to use for writing out the records.', + allowableValues: [], + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + identifiesControllerService: 'org.apache.nifi.serialization.RecordSetWriterFactory', + identifiesControllerServiceBundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + }, + dependencies: [] + }, + 'include-null-values': { + name: 'include-null-values', + displayName: 'Include Null Values', + description: 'Indicate if null values should be included in records. Default will be false', + defaultValue: 'false', + allowableValues: [ + { + allowableValue: { + displayName: 'true', + value: 'true' + }, + canRead: true + }, + { + allowableValue: { + displayName: 'false', + value: 'false' + }, + canRead: true + } + ], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 's2s-metrics-hostname': { + name: 's2s-metrics-hostname', + displayName: 'Hostname', + description: 'The Hostname of this NiFi instance to be included in the metrics', + defaultValue: '${hostname(true)}', + required: true, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables defined at JVM level and system properties', + dependencies: [] + }, + 's2s-metrics-application-id': { + name: 's2s-metrics-application-id', + displayName: 'Application ID', + description: 'The Application ID to be included in the metrics', + defaultValue: 'nifi', + required: true, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables defined at JVM level and system properties', + dependencies: [] + }, + 's2s-metrics-format': { + name: 's2s-metrics-format', + displayName: 'Output Format', + description: + 'The output format that will be used for the metrics. If Record Format is selected, a Record Writer must be provided. If Ambari Format is selected, the Record Writer property should be empty.', + defaultValue: 'ambari-format', + allowableValues: [ + { + allowableValue: { + displayName: 'Ambari Format', + value: 'ambari-format', + description: + 'Metrics will be formatted according to the Ambari Metrics API. See Additional Details in Usage documentation.' + }, + canRead: true + }, + { + allowableValue: { + displayName: 'Record Format', + value: 'record-format', + description: + 'Metrics will be formatted using the Record Writer property of this reporting task. See Additional Details in Usage documentation to have the description of the default schema.' + }, + canRead: true + } + ], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + } + }, + validationErrors: [ + "'Input Port Name' is invalid because Input Port Name is required", + "'Destination URL' is invalid because Destination URL is required" + ], + validationStatus: 'INVALID', + activeThreadCount: 0, + extensionMissing: false + }, + operatePermissions: { + canRead: true, + canWrite: true + }, + status: { + runStatus: 'DISABLED', + validationStatus: 'INVALID', + activeThreadCount: 0 + } + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [EditReportingTask, BrowserAnimationsModule], + providers: [{ provide: MAT_DIALOG_DATA, useValue: data }] + }); + fixture = TestBed.createComponent(EditReportingTask); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.ts new file mode 100644 index 0000000000..75d6ec9a28 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component.ts @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Inject, Input, Output, signal } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatInputModule } from '@angular/material/input'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatButtonModule } from '@angular/material/button'; +import { AsyncPipe, NgForOf, NgIf } from '@angular/common'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatOptionModule } from '@angular/material/core'; +import { MatSelectModule } from '@angular/material/select'; +import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { Observable } from 'rxjs'; +import { Client } from '../../../../../service/client.service'; +import { + ControllerServiceReferencingComponent, + InlineServiceCreationRequest, + InlineServiceCreationResponse, + Parameter, + ParameterContextReferenceEntity, + Property, + PropertyTipInput, + SelectOption, + TextTipInput, + UpdateControllerServiceRequest, + UpdateReportingTaskRequest +} from '../../../../../state/shared'; +import { NiFiCommon } from '../../../../../service/nifi-common.service'; +import { PropertyTable } from '../../../../../ui/common/property-table/property-table.component'; +import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spinner.directive'; +import { EditReportingTaskDialogRequest, ReportingTaskEntity } from '../../../state/reporting-tasks'; +import { ControllerServiceApi } from '../../../../../ui/common/controller-service/controller-service-api/controller-service-api.component'; +import { NifiTooltipDirective } from '../../../../../ui/common/tooltips/nifi-tooltip.directive'; +import { TextTip } from '../../../../../ui/common/tooltips/text-tip/text-tip.component'; + +@Component({ + selector: 'edit-reporting-task', + standalone: true, + templateUrl: './edit-reporting-task.component.html', + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatInputModule, + MatCheckboxModule, + MatButtonModule, + NgIf, + MatTabsModule, + MatOptionModule, + MatSelectModule, + NgForOf, + PropertyTable, + ControllerServiceApi, + AsyncPipe, + NifiSpinnerDirective, + MatTooltipModule, + NifiTooltipDirective + ], + styleUrls: ['./edit-reporting-task.component.scss'] +}) +export class EditReportingTask { + @Input() createNewProperty!: (existingProperties: string[], allowsSensitive: boolean) => Observable; + @Input() createNewService!: (request: InlineServiceCreationRequest) => Observable; + @Input() goToService!: (serviceId: string) => void; + @Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void; + @Input() saving$!: Observable; + @Output() editReportingTask: EventEmitter = + new EventEmitter(); + + editReportingTaskForm: FormGroup; + schedulingStrategy: string; + cronDrivenSchedulingPeriod: string; + timerDrivenSchedulingPeriod: string; + + strategies: SelectOption[] = [ + { + text: 'Timer driven', + value: 'TIMER_DRIVEN', + description: 'Reporting task will be scheduled on an interval defined by the run schedule.' + }, + { + text: 'CRON driven', + value: 'CRON_DRIVEN', + description: + 'Reporting task will be scheduled to run on at specific times based on the specified CRON string.' + } + ]; + + constructor( + @Inject(MAT_DIALOG_DATA) public request: EditReportingTaskDialogRequest, + private formBuilder: FormBuilder, + private client: Client, + private nifiCommon: NiFiCommon + ) { + const serviceProperties: any = request.reportingTask.component.properties; + const properties: Property[] = Object.entries(serviceProperties).map((entry: any) => { + const [property, value] = entry; + return { + property, + value, + descriptor: request.reportingTask.component.descriptors[property] + }; + }); + + const defaultSchedulingPeriod: any = request.reportingTask.component.defaultSchedulingPeriod; + this.schedulingStrategy = request.reportingTask.component.schedulingStrategy; + let schedulingPeriod: string; + + if (this.schedulingStrategy === 'CRON_DRIVEN') { + this.cronDrivenSchedulingPeriod = request.reportingTask.component.schedulingPeriod; + this.timerDrivenSchedulingPeriod = defaultSchedulingPeriod['TIMER_DRIVEN']; + + schedulingPeriod = this.cronDrivenSchedulingPeriod; + } else { + this.cronDrivenSchedulingPeriod = defaultSchedulingPeriod['CRON_DRIVEN']; + this.timerDrivenSchedulingPeriod = request.reportingTask.component.schedulingPeriod; + + schedulingPeriod = this.timerDrivenSchedulingPeriod; + } + + // build the form + this.editReportingTaskForm = this.formBuilder.group({ + name: new FormControl(request.reportingTask.component.name, Validators.required), + state: new FormControl(request.reportingTask.component.state === 'STOPPED', Validators.required), + schedulingStrategy: new FormControl( + request.reportingTask.component.schedulingStrategy, + Validators.required + ), + schedulingPeriod: new FormControl(schedulingPeriod, Validators.required), + properties: new FormControl(properties), + comments: new FormControl(request.reportingTask.component.comments) + }); + } + + formatType(entity: ReportingTaskEntity): string { + return this.nifiCommon.formatType(entity.component); + } + + formatBundle(entity: ReportingTaskEntity): string { + return this.nifiCommon.formatBundle(entity.component.bundle); + } + + submitForm(postUpdateNavigation?: string[]) { + const payload: any = { + revision: this.client.getRevision(this.request.reportingTask), + component: { + id: this.request.reportingTask.id, + name: this.editReportingTaskForm.get('name')?.value, + comments: this.editReportingTaskForm.get('comments')?.value, + schedulingStrategy: this.editReportingTaskForm.get('schedulingStrategy')?.value, + schedulingPeriod: this.editReportingTaskForm.get('schedulingPeriod')?.value, + state: this.editReportingTaskForm.get('state')?.value ? 'STOPPED' : 'DISABLED' + } + }; + + const propertyControl: AbstractControl | null = this.editReportingTaskForm.get('properties'); + if (propertyControl && propertyControl.dirty) { + const properties: Property[] = propertyControl.value; + const values: { [key: string]: string | null } = {}; + properties.forEach((property) => (values[property.property] = property.value)); + payload.component.properties = values; + payload.component.sensitiveDynamicPropertyNames = properties + .filter((property) => property.descriptor.dynamic && property.descriptor.sensitive) + .map((property) => property.descriptor.name); + } + + this.editReportingTask.next({ + payload, + postUpdateNavigation + }); + } + + getPropertyTipData(option: SelectOption): TextTipInput { + return { + // @ts-ignore + text: option.description + }; + } + + schedulingStrategyChanged(value: string): void { + this.schedulingStrategy = value; + + if (value === 'CRON_DRIVEN') { + this.editReportingTaskForm.get('schedulingPeriod')?.setValue(this.cronDrivenSchedulingPeriod); + } else { + this.editReportingTaskForm.get('schedulingPeriod')?.setValue(this.timerDrivenSchedulingPeriod); + } + } + + schedulingPeriodChanged(): void { + if (this.schedulingStrategy === 'CRON_DRIVEN') { + this.cronDrivenSchedulingPeriod = this.editReportingTaskForm.get('schedulingPeriod')?.value; + } else { + this.timerDrivenSchedulingPeriod = this.editReportingTaskForm.get('schedulingPeriod')?.value; + } + } + + protected readonly TextTip = TextTip; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-task-table/reporting-task-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-task-table/reporting-task-table.component.html index 8f791bac2d..95879eed4c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-task-table/reporting-task-table.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-task-table/reporting-task-table.component.html @@ -104,7 +104,11 @@ *ngIf="canStop(item)" (click)="stopClicked(item)" title="Stop"> -
+
= new EventEmitter(); @Output() deleteReportingTask: EventEmitter = new EventEmitter(); @Output() startReportingTask: EventEmitter = new EventEmitter(); + @Output() configureReportingTask: EventEmitter = new EventEmitter(); @Output() stopReportingTask: EventEmitter = new EventEmitter(); protected readonly TextTip = TextTip; @@ -226,6 +227,11 @@ export class ReportingTaskTable implements AfterViewInit { this.deleteReportingTask.next(entity); } + configureClicked(entity: ReportingTaskEntity, event: MouseEvent): void { + event.stopPropagation(); + this.configureReportingTask.next(entity); + } + canViewState(entity: ReportingTaskEntity): boolean { return this.canRead(entity) && this.canWrite(entity) && entity.component.persistsState === true; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.component.html index 4f160f1030..7d64ca86b7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.component.html @@ -30,6 +30,7 @@ ) {} + constructor(private store: Store) { + this.store + .select(selectSingleEditedReportingTask) + .pipe( + filter((id: string) => id != null), + switchMap((id: string) => + this.store.select(selectTask(id)).pipe( + filter((entity) => entity != null), + take(1) + ) + ), + takeUntilDestroyed() + ) + .subscribe((entity) => { + if (entity) { + this.store.dispatch( + openConfigureReportingTaskDialog({ + request: { + id: entity.id, + reportingTask: entity + } + }) + ); + } + }); + } ngOnInit(): void { this.store.dispatch(loadReportingTasks()); @@ -69,7 +99,7 @@ export class ReportingTasks implements OnInit, OnDestroy { this.store.dispatch( selectReportingTask({ request: { - reportingTask: entity + id: entity.id } }) ); @@ -85,6 +115,14 @@ export class ReportingTasks implements OnInit, OnDestroy { ); } + configureReportingTask(entity: ReportingTaskEntity): void { + this.store.dispatch( + navigateToEditReportingTask({ + id: entity.id + }) + ); + } + startReportingTask(entity: ReportingTaskEntity): void { this.store.dispatch( startReportingTask({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.module.ts index 9513f8280c..10b3f32ade 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/reporting-tasks/reporting-tasks.module.ts @@ -23,10 +23,18 @@ import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive'; import { ReportingTaskTable } from './reporting-task-table/reporting-task-table.component'; +import { ControllerServiceTable } from '../../../../ui/common/controller-service/controller-service-table/controller-service-table.component'; @NgModule({ declarations: [ReportingTasks, ReportingTaskTable], exports: [ReportingTasks], - imports: [CommonModule, NgxSkeletonLoaderModule, MatSortModule, MatTableModule, NifiTooltipDirective] + imports: [ + CommonModule, + NgxSkeletonLoaderModule, + MatSortModule, + MatTableModule, + NifiTooltipDirective, + ControllerServiceTable + ] }) export class ReportingTasksModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts index 812ab63560..1b425ff4f9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts @@ -115,6 +115,11 @@ export interface UpdateControllerServiceRequest { postUpdateNavigation?: string[]; } +export interface UpdateReportingTaskRequest { + payload: any; + postUpdateNavigation?: string[]; +} + export interface SetEnableControllerServiceDialogRequest { id: string; controllerService: ControllerServiceEntity; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/enable-controller-service/enable-controller-service.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/enable-controller-service/enable-controller-service.component.html index f42bc5590d..e9b7b2be9e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/enable-controller-service/enable-controller-service.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/enable-controller-service/enable-controller-service.component.html @@ -39,8 +39,8 @@ nifiTooltip [tooltipComponentType]="TextTip" [tooltipInputData]="getSelectOptionTipData(option)" - [delayClose]="false" - >{{ option.text }} + [delayClose]="false"> + {{ option.text }}