mirror of
https://github.com/apache/nifi.git
synced 2025-02-07 10:38:33 +00:00
[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
This commit is contained in:
parent
afc367dbe5
commit
bbd8d7fd8d
@ -57,7 +57,13 @@ const routes: Routes = [
|
||||
children: [
|
||||
{
|
||||
path: ':id',
|
||||
component: ReportingTasks
|
||||
component: ReportingTasks,
|
||||
children: [
|
||||
{
|
||||
path: 'edit',
|
||||
component: ReportingTasks
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -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<any> {
|
||||
// return this.httpClient.put(`${ControllerServiceService.API}/controller/config`, controllerEntity);
|
||||
// }
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||
const params: any = {
|
||||
propertyName,
|
||||
sensitive
|
||||
};
|
||||
return this.httpClient.get(`${ReportingTaskService.API}/reporting-tasks/${id}/descriptors`, {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
updateReportingTask(configureReportingTask: ConfigureReportingTaskRequest): Observable<any> {
|
||||
return this.httpClient.put(this.stripProtocol(configureReportingTask.uri), configureReportingTask.payload);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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 }>()
|
||||
|
@ -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<NiFiState>,
|
||||
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<Property> => {
|
||||
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<InlineServiceCreationResponse> => {
|
||||
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 }
|
||||
|
@ -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
|
||||
})),
|
||||
|
@ -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));
|
||||
|
@ -0,0 +1,111 @@
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<h2 mat-dialog-title>Edit Reporting Task</h2>
|
||||
<form class="reporting-task-edit-form" [formGroup]="editReportingTaskForm">
|
||||
<mat-dialog-content>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Settings">
|
||||
<div class="tab-content py-4 flex gap-x-4">
|
||||
<div class="w-full">
|
||||
<div class="flex">
|
||||
<mat-form-field>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput formControlName="name" type="text" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox formControlName="state" class="pl-1"> Enabled </mat-checkbox>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Id</div>
|
||||
<div class="value">{{ request.reportingTask.id }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Type</div>
|
||||
<div class="value">{{ formatType(request.reportingTask) }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Bundle</div>
|
||||
<div class="value">{{ formatBundle(request.reportingTask) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col w-full">
|
||||
<div>
|
||||
<mat-form-field>
|
||||
<mat-label>Scheduling Strategy</mat-label>
|
||||
<mat-select
|
||||
formControlName="schedulingStrategy"
|
||||
(selectionChange)="schedulingStrategyChanged($event.value)">
|
||||
<mat-option
|
||||
*ngFor="let option of strategies"
|
||||
[value]="option.value"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
[tooltipInputData]="getPropertyTipData(option)"
|
||||
[delayClose]="false">
|
||||
{{ option.text }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field>
|
||||
<mat-label>Run Schedule</mat-label>
|
||||
<input
|
||||
matInput
|
||||
formControlName="schedulingPeriod"
|
||||
(change)="schedulingPeriodChanged()"
|
||||
type="text" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Properties">
|
||||
<div class="tab-content py-4">
|
||||
<property-table
|
||||
formControlName="properties"
|
||||
[createNewProperty]="createNewProperty"
|
||||
[createNewService]="createNewService"
|
||||
[goToService]="goToService"
|
||||
[supportsSensitiveDynamicProperties]="
|
||||
request.reportingTask.component.supportsSensitiveDynamicProperties
|
||||
">
|
||||
</property-table>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Comments">
|
||||
<div class="tab-content py-4">
|
||||
<mat-form-field>
|
||||
<mat-label>Comments</mat-label>
|
||||
<textarea matInput formControlName="comments" type="text" rows="5"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end" *ngIf="{ value: (saving$ | async)! } as saving">
|
||||
<button color="accent" mat-raised-button mat-dialog-close>Cancel</button>
|
||||
<button
|
||||
[disabled]="!editReportingTaskForm.dirty || editReportingTaskForm.invalid || saving.value"
|
||||
type="button"
|
||||
color="primary"
|
||||
(click)="submitForm()"
|
||||
mat-raised-button>
|
||||
<span *nifiSpinner="saving.value">Apply</span>
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
</form>
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<EditReportingTask>;
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
@ -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<Property>;
|
||||
@Input() createNewService!: (request: InlineServiceCreationRequest) => Observable<InlineServiceCreationResponse>;
|
||||
@Input() goToService!: (serviceId: string) => void;
|
||||
@Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void;
|
||||
@Input() saving$!: Observable<boolean>;
|
||||
@Output() editReportingTask: EventEmitter<UpdateReportingTaskRequest> =
|
||||
new EventEmitter<UpdateReportingTaskRequest>();
|
||||
|
||||
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;
|
||||
}
|
@ -104,7 +104,11 @@
|
||||
*ngIf="canStop(item)"
|
||||
(click)="stopClicked(item)"
|
||||
title="Stop"></div>
|
||||
<div class="pointer fa fa-pencil" *ngIf="canEdit(item)" title="Edit"></div>
|
||||
<div
|
||||
class="pointer fa fa-pencil"
|
||||
*ngIf="canEdit(item)"
|
||||
(click)="configureClicked(item, $event)"
|
||||
title="Edit"></div>
|
||||
<div
|
||||
class="pointer fa fa-play"
|
||||
*ngIf="canStart(item)"
|
||||
|
@ -52,6 +52,7 @@ export class ReportingTaskTable implements AfterViewInit {
|
||||
@Output() selectReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() deleteReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() startReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() configureReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() stopReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
<reporting-task-table
|
||||
[selectedReportingTaskId]="selectedReportingTaskId$ | async"
|
||||
[reportingTasks]="reportingTaskState.reportingTasks"
|
||||
(configureReportingTask)="configureReportingTask($event)"
|
||||
(selectReportingTask)="selectReportingTask($event)"
|
||||
(deleteReportingTask)="deleteReportingTask($event)"
|
||||
(stopReportingTask)="stopReportingTask($event)"
|
||||
|
@ -16,25 +16,30 @@
|
||||
*/
|
||||
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { ReportingTaskEntity, ReportingTasksState } from '../../state/reporting-tasks';
|
||||
import {
|
||||
selectReportingTaskIdFromRoute,
|
||||
selectReportingTasksState
|
||||
selectReportingTasksState,
|
||||
selectSingleEditedReportingTask,
|
||||
selectTask
|
||||
} from '../../state/reporting-tasks/reporting-tasks.selectors';
|
||||
import {
|
||||
loadReportingTasks,
|
||||
navigateToEditReportingTask,
|
||||
openConfigureReportingTaskDialog,
|
||||
openNewReportingTaskDialog,
|
||||
promptReportingTaskDeletion,
|
||||
resetReportingTasksState,
|
||||
selectReportingTask,
|
||||
startReportingTask,
|
||||
stopReportingTask
|
||||
stopReportingTask,
|
||||
selectReportingTask
|
||||
} from '../../state/reporting-tasks/reporting-tasks.actions';
|
||||
import { initialState } from '../../state/reporting-tasks/reporting-tasks.reducer';
|
||||
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
|
||||
import { NiFiState } from '../../../../state';
|
||||
import { state } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'reporting-tasks',
|
||||
@ -46,7 +51,32 @@ export class ReportingTasks implements OnInit, OnDestroy {
|
||||
selectedReportingTaskId$ = this.store.select(selectReportingTaskIdFromRoute);
|
||||
currentUser$ = this.store.select(selectCurrentUser);
|
||||
|
||||
constructor(private store: Store<NiFiState>) {}
|
||||
constructor(private store: Store<NiFiState>) {
|
||||
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({
|
||||
|
@ -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 {}
|
||||
|
@ -115,6 +115,11 @@ export interface UpdateControllerServiceRequest {
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateReportingTaskRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface SetEnableControllerServiceDialogRequest {
|
||||
id: string;
|
||||
controllerService: ControllerServiceEntity;
|
||||
|
@ -39,8 +39,8 @@
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
[tooltipInputData]="getSelectOptionTipData(option)"
|
||||
[delayClose]="false"
|
||||
>{{ option.text }}
|
||||
[delayClose]="false">
|
||||
{{ option.text }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
Loading…
x
Reference in New Issue
Block a user