mirror of https://github.com/apache/nifi.git
[NIFI-12622] - Parameter Providers - listing table (#8298)
* [NIFI-12622] - Parameter Providers - listing table * Add a new Parameter Provider * Delete parameter provider * refactor to reduce duplicate code when creating new properties * support editing parameter providers * refactored inline service creation into PropertyTableHelperService * added parameter provider linking to access policies. * fix bugs in flow reducer not setting state properly when starting/stopping components and run once. * address review feedback * refactored nifiCommon to provide stripProtocol method that was implemented in loads of places. replaced all occurrences to the nifiCommon implementation. This closes #8298
This commit is contained in:
parent
bce14f573b
commit
0e87032ef3
|
@ -16,7 +16,12 @@
|
|||
*/
|
||||
package org.apache.nifi.web.api.entity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import org.apache.nifi.web.api.dto.util.TimeAdapter;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +32,8 @@ public class ParameterProvidersEntity extends Entity {
|
|||
|
||||
private Set<ParameterProviderEntity> parameterProviders;
|
||||
|
||||
private Date currentTime;
|
||||
|
||||
/**
|
||||
* @return list of parameter providers that are being serialized
|
||||
*/
|
||||
|
@ -38,4 +45,18 @@ public class ParameterProvidersEntity extends Entity {
|
|||
this.parameterProviders = parameterProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current time on the server
|
||||
*/
|
||||
@XmlJavaTypeAdapter(TimeAdapter.class)
|
||||
@Schema(description = "The current time on the system.",
|
||||
type = "string"
|
||||
)
|
||||
public Date getCurrentTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
public void setCurrentTime(Date currentTime) {
|
||||
this.currentTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.nifi.web.api.entity.ParameterProviderEntity;
|
|||
import org.apache.nifi.web.api.entity.ParameterProvidersEntity;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
@ -60,6 +61,7 @@ public class ParameterProvidersEndpointMerger extends AbstractSingleEntityEndpoi
|
|||
}
|
||||
|
||||
clientEntity.setParameterProviders(new HashSet<>(providerEntities.values()));
|
||||
clientEntity.setCurrentTime(new Date());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -672,6 +672,7 @@ public class FlowResource extends ApplicationResource {
|
|||
// create the response entity
|
||||
final ParameterProvidersEntity entity = new ParameterProvidersEntity();
|
||||
entity.setParameterProviders(parameterProviders);
|
||||
entity.setCurrentTime(new Date());
|
||||
|
||||
// generate the response
|
||||
return generateOkResponse(entity).build();
|
||||
|
|
|
@ -33,19 +33,6 @@ export class AccessPolicyService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
createAccessPolicy(resourceAction: ResourceAction): Observable<any> {
|
||||
let resource: string = `/${resourceAction.resource}`;
|
||||
if (resourceAction.resourceIdentifier) {
|
||||
|
@ -92,12 +79,12 @@ export class AccessPolicyService {
|
|||
}
|
||||
};
|
||||
|
||||
return this.httpClient.put(this.stripProtocol(accessPolicy.uri), payload);
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(accessPolicy.uri), payload);
|
||||
}
|
||||
|
||||
deleteAccessPolicy(accessPolicy: AccessPolicyEntity): Observable<any> {
|
||||
const revision: any = this.client.getRevision(accessPolicy);
|
||||
return this.httpClient.delete(this.stripProtocol(accessPolicy.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(accessPolicy.uri), { params: revision });
|
||||
}
|
||||
|
||||
getUsers(): Observable<any> {
|
||||
|
|
|
@ -306,6 +306,7 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||
return 'icon-label';
|
||||
case 'remote-process-groups':
|
||||
return 'icon-group-remote';
|
||||
case 'parameter-providers':
|
||||
case 'parameter-contexts':
|
||||
return 'icon-drop';
|
||||
}
|
||||
|
@ -329,6 +330,8 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||
return 'Remote Process Group';
|
||||
case 'parameter-contexts':
|
||||
return 'Parameter Contexts';
|
||||
case 'parameter-providers':
|
||||
return 'Parameter Provider';
|
||||
}
|
||||
|
||||
return 'Process Group';
|
||||
|
|
|
@ -42,11 +42,13 @@ export class CounterTable implements AfterViewInit {
|
|||
@Input() initialSortColumn: 'context' | 'name' | 'value' = 'context';
|
||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
@Input() set counters(counterEntities: CounterEntity[]) {
|
||||
this.dataSource.data = this.sortEntities(counterEntities, {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
});
|
||||
this.dataSource.data = this.sortEntities(counterEntities, this.activeSort);
|
||||
|
||||
this.dataSource.filterPredicate = (data: CounterEntity, filter: string) => {
|
||||
const { filterTerm, filterColumn } = JSON.parse(filter);
|
||||
|
@ -128,6 +130,7 @@ export class CounterTable implements AfterViewInit {
|
|||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,34 +16,22 @@
|
|||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Client } from '../../../service/client.service';
|
||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||
import { ControllerServiceEntity } from '../../../state/shared';
|
||||
import {
|
||||
ConfigureControllerServiceRequest,
|
||||
ControllerServiceCreator,
|
||||
ControllerServiceEntity,
|
||||
CreateControllerServiceRequest,
|
||||
DeleteControllerServiceRequest
|
||||
} from '../state/controller-services';
|
||||
PropertyDescriptorRetriever
|
||||
} from '../../../state/shared';
|
||||
import { ConfigureControllerServiceRequest, DeleteControllerServiceRequest } from '../state/controller-services';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ControllerServiceService {
|
||||
export class ControllerServiceService implements ControllerServiceCreator, PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -69,17 +57,20 @@ export class ControllerServiceService {
|
|||
}
|
||||
|
||||
createControllerService(createControllerService: CreateControllerServiceRequest): Observable<any> {
|
||||
const processGroupId: string = createControllerService.processGroupId;
|
||||
return this.httpClient.post(
|
||||
`${ControllerServiceService.API}/process-groups/${processGroupId}/controller-services`,
|
||||
{
|
||||
revision: createControllerService.revision,
|
||||
component: {
|
||||
bundle: createControllerService.controllerServiceBundle,
|
||||
type: createControllerService.controllerServiceType
|
||||
if (createControllerService.processGroupId) {
|
||||
const processGroupId: string = createControllerService.processGroupId;
|
||||
return this.httpClient.post(
|
||||
`${ControllerServiceService.API}/process-groups/${processGroupId}/controller-services`,
|
||||
{
|
||||
revision: createControllerService.revision,
|
||||
component: {
|
||||
bundle: createControllerService.controllerServiceBundle,
|
||||
type: createControllerService.controllerServiceType
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||
|
@ -94,7 +85,7 @@ export class ControllerServiceService {
|
|||
|
||||
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
||||
return this.httpClient.put(
|
||||
this.stripProtocol(configureControllerService.uri),
|
||||
this.nifiCommon.stripProtocol(configureControllerService.uri),
|
||||
configureControllerService.payload
|
||||
);
|
||||
}
|
||||
|
@ -102,6 +93,6 @@ export class ControllerServiceService {
|
|||
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
||||
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
return this.httpClient.delete(this.stripProtocol(entity.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,12 +38,12 @@ import {
|
|||
UpdateComponentRequest,
|
||||
UploadProcessGroupRequest
|
||||
} from '../state/flow';
|
||||
import { ComponentType } from '../../../state/shared';
|
||||
import { ComponentType, PropertyDescriptorRetriever } from '../../../state/shared';
|
||||
import { Client } from '../../../service/client.service';
|
||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class FlowService {
|
||||
export class FlowService implements PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
constructor(
|
||||
|
@ -53,19 +53,6 @@ export class FlowService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getFlow(processGroupId = 'root'): Observable<any> {
|
||||
// TODO - support uiOnly... this would mean that we need to load the entire resource prior to editing
|
||||
return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}`);
|
||||
|
@ -212,13 +199,13 @@ export class FlowService {
|
|||
|
||||
updateComponent(updateComponent: UpdateComponentRequest): Observable<any> {
|
||||
// return throwError('API Error');
|
||||
return this.httpClient.put(this.stripProtocol(updateComponent.uri), updateComponent.payload);
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(updateComponent.uri), updateComponent.payload);
|
||||
}
|
||||
|
||||
deleteComponent(deleteComponent: DeleteComponentRequest): Observable<any> {
|
||||
// return throwError('API Error');
|
||||
const revision: any = this.client.getRevision(deleteComponent.entity);
|
||||
return this.httpClient.delete(this.stripProtocol(deleteComponent.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(deleteComponent.uri), { params: revision });
|
||||
}
|
||||
|
||||
createSnippet(snippet: Snippet): Observable<any> {
|
||||
|
@ -250,7 +237,7 @@ export class FlowService {
|
|||
disconnectedNodeAcknowledged: false,
|
||||
state: 'RUN_ONCE'
|
||||
};
|
||||
return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, startRequest);
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, startRequest);
|
||||
}
|
||||
|
||||
startComponent(request: StartComponentRequest): Observable<any> {
|
||||
|
@ -259,7 +246,7 @@ export class FlowService {
|
|||
disconnectedNodeAcknowledged: false,
|
||||
state: request.type === ComponentType.RemoteProcessGroup ? 'TRANSMITTING' : 'RUNNING'
|
||||
};
|
||||
return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, startRequest);
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, startRequest);
|
||||
}
|
||||
|
||||
stopComponent(request: StopComponentRequest): Observable<any> {
|
||||
|
@ -268,7 +255,7 @@ export class FlowService {
|
|||
disconnectedNodeAcknowledged: false,
|
||||
state: 'STOPPED'
|
||||
};
|
||||
return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, stopRequest);
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, stopRequest);
|
||||
}
|
||||
|
||||
startProcessGroup(request: StartProcessGroupRequest): Observable<any> {
|
||||
|
|
|
@ -30,19 +30,6 @@ export class ParameterService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getParameterContext(id: string, includeInheritedParameters: boolean): Observable<any> {
|
||||
return this.httpClient.get(`${ParameterService.API}/parameter-contexts/${id}`, {
|
||||
params: {
|
||||
|
@ -59,10 +46,10 @@ export class ParameterService {
|
|||
}
|
||||
|
||||
pollParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
||||
return this.httpClient.get(this.stripProtocol(updateRequest.uri));
|
||||
return this.httpClient.get(this.nifiCommon.stripProtocol(updateRequest.uri));
|
||||
}
|
||||
|
||||
deleteParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
||||
return this.httpClient.delete(this.stripProtocol(updateRequest.uri));
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(updateRequest.uri));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,19 +30,6 @@ export class QueueService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
submitEmptyQueueRequest(emptyQueueRequest: SubmitEmptyQueueRequest): Observable<any> {
|
||||
return this.httpClient.post(
|
||||
`${QueueService.API}/flowfile-queues/${emptyQueueRequest.connectionId}/drop-requests`,
|
||||
|
@ -58,10 +45,10 @@ export class QueueService {
|
|||
}
|
||||
|
||||
pollEmptyQueueRequest(dropRequest: DropRequest): Observable<any> {
|
||||
return this.httpClient.get(this.stripProtocol(dropRequest.uri));
|
||||
return this.httpClient.get(this.nifiCommon.stripProtocol(dropRequest.uri));
|
||||
}
|
||||
|
||||
deleteEmptyQueueRequest(dropRequest: DropRequest): Observable<any> {
|
||||
return this.httpClient.delete(this.stripProtocol(dropRequest.uri));
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(dropRequest.uri));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { createAction, props } from '@ngrx/store';
|
|||
import {
|
||||
ConfigureControllerServiceRequest,
|
||||
ConfigureControllerServiceSuccess,
|
||||
CreateControllerServiceRequest,
|
||||
CreateControllerServiceSuccess,
|
||||
DeleteControllerServiceRequest,
|
||||
DeleteControllerServiceSuccess,
|
||||
|
@ -28,6 +27,7 @@ import {
|
|||
SelectControllerServiceRequest
|
||||
} from './index';
|
||||
import {
|
||||
CreateControllerServiceRequest,
|
||||
DisableControllerServiceDialogRequest,
|
||||
EditControllerServiceDialogRequest,
|
||||
SetEnableControllerServiceDialogRequest
|
||||
|
|
|
@ -18,20 +18,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as ControllerServicesActions from './controller-services.actions';
|
||||
import {
|
||||
catchError,
|
||||
combineLatest,
|
||||
filter,
|
||||
from,
|
||||
map,
|
||||
NEVER,
|
||||
Observable,
|
||||
of,
|
||||
switchMap,
|
||||
take,
|
||||
takeUntil,
|
||||
tap
|
||||
} from 'rxjs';
|
||||
import { catchError, combineLatest, filter, from, map, NEVER, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NiFiState } from '../../../../state';
|
||||
|
@ -45,17 +32,10 @@ import {
|
|||
ControllerServiceReferencingComponent,
|
||||
EditParameterRequest,
|
||||
EditParameterResponse,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
NewPropertyDialogRequest,
|
||||
NewPropertyDialogResponse,
|
||||
Parameter,
|
||||
ParameterEntity,
|
||||
Property,
|
||||
PropertyDescriptor,
|
||||
UpdateControllerServiceRequest
|
||||
} from '../../../../state/shared';
|
||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||
import { selectCurrentProcessGroupId, selectSaving } from './controller-services.selectors';
|
||||
|
@ -68,6 +48,7 @@ import * as ParameterActions from '../parameter/parameter.actions';
|
|||
import { ParameterService } from '../../service/parameter.service';
|
||||
import { EnableControllerService } from '../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component';
|
||||
import { DisableControllerService } from '../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class ControllerServicesEffects {
|
||||
|
@ -80,7 +61,8 @@ export class ControllerServicesEffects {
|
|||
private parameterService: ParameterService,
|
||||
private extensionTypesService: ExtensionTypesService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
loadControllerServices$ = createEffect(() =>
|
||||
|
@ -225,36 +207,8 @@ export class ControllerServicesEffects {
|
|||
|
||||
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.controllerServiceService
|
||||
.getPropertyDescriptor(request.id, dialogResponse.name, dialogResponse.sensitive)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(request.id, this.controllerServiceService);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||
|
@ -393,85 +347,21 @@ export class ControllerServicesEffects {
|
|||
});
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewService = (
|
||||
serviceRequest: InlineServiceCreationRequest
|
||||
): Observable<InlineServiceCreationResponse> => {
|
||||
const descriptor: PropertyDescriptor = serviceRequest.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.controllerServiceService
|
||||
.createControllerService({
|
||||
revision: {
|
||||
clientId: this.client.getClientId(),
|
||||
version: 0
|
||||
},
|
||||
processGroupId,
|
||||
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(
|
||||
ControllerServicesActions.inlineCreateControllerServiceSuccess(
|
||||
{
|
||||
response: {
|
||||
controllerService: createResponse
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// fetch an updated property descriptor
|
||||
return this.controllerServiceService
|
||||
.getPropertyDescriptor(serviceId, 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.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
request.id,
|
||||
this.controllerServiceService,
|
||||
this.controllerServiceService,
|
||||
processGroupId,
|
||||
(createResponse) =>
|
||||
this.store.dispatch(
|
||||
ControllerServicesActions.inlineCreateControllerServiceSuccess({
|
||||
response: {
|
||||
controllerService: createResponse
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editControllerService
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
|
|
@ -31,13 +31,6 @@ export interface LoadControllerServicesResponse {
|
|||
loadedTimestamp: string;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceRequest {
|
||||
processGroupId: string;
|
||||
controllerServiceType: string;
|
||||
controllerServiceBundle: Bundle;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceSuccess {
|
||||
controllerService: ControllerServiceEntity;
|
||||
}
|
||||
|
|
|
@ -69,14 +69,8 @@ import {
|
|||
ComponentType,
|
||||
EditParameterRequest,
|
||||
EditParameterResponse,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
NewPropertyDialogRequest,
|
||||
NewPropertyDialogResponse,
|
||||
Parameter,
|
||||
ParameterEntity,
|
||||
Property,
|
||||
PropertyDescriptor
|
||||
ParameterEntity
|
||||
} from '../../../../state/shared';
|
||||
import { Router } from '@angular/router';
|
||||
import { Client } from '../../../../service/client.service';
|
||||
|
@ -86,7 +80,6 @@ import { selectProcessorTypes } from '../../../../state/extension-types/extensio
|
|||
import { NiFiState } from '../../../../state';
|
||||
import { CreateProcessor } from '../../ui/canvas/items/processor/create-processor/create-processor.component';
|
||||
import { EditProcessor } from '../../ui/canvas/items/processor/edit-processor/edit-processor.component';
|
||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
import { BirdseyeView } from '../../service/birdseye-view.service';
|
||||
import { CreateProcessGroup } from '../../ui/canvas/items/process-group/create-process-group/create-process-group.component';
|
||||
import { CreateConnection } from '../../ui/canvas/items/connection/create-connection/create-connection.component';
|
||||
|
@ -94,13 +87,13 @@ import { EditConnectionComponent } from '../../ui/canvas/items/connection/edit-c
|
|||
import { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component';
|
||||
import { GroupComponents } from '../../ui/canvas/items/process-group/group-components/group-components.component';
|
||||
import { EditProcessGroup } from '../../ui/canvas/items/process-group/edit-process-group/edit-process-group.component';
|
||||
import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component';
|
||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||
import { ControllerServiceService } from '../../service/controller-service.service';
|
||||
import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component';
|
||||
import { EditParameterDialog } from '../../../../ui/common/edit-parameter-dialog/edit-parameter-dialog.component';
|
||||
import { selectParameterSaving } from '../parameter/parameter.selectors';
|
||||
import { ParameterService } from '../../service/parameter.service';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class FlowEffects {
|
||||
|
@ -117,7 +110,8 @@ export class FlowEffects {
|
|||
private birdseyeView: BirdseyeView,
|
||||
private connectionManager: ConnectionManager,
|
||||
private router: Router,
|
||||
private dialog: MatDialog
|
||||
private dialog: MatDialog,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
reloadFlow$ = createEffect(() =>
|
||||
|
@ -852,36 +846,8 @@ export class FlowEffects {
|
|||
|
||||
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.flowService
|
||||
.getPropertyDescriptor(processorId, dialogResponse.name, dialogResponse.sensitive)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(processorId, this.flowService);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editProcessorForm.dirty) {
|
||||
|
@ -1013,74 +979,13 @@ export class FlowEffects {
|
|||
});
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewService = (
|
||||
serviceRequest: InlineServiceCreationRequest
|
||||
): Observable<InlineServiceCreationResponse> => {
|
||||
const descriptor: PropertyDescriptor = serviceRequest.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.controllerServiceService
|
||||
.createControllerService({
|
||||
revision: {
|
||||
clientId: this.client.getClientId(),
|
||||
version: 0
|
||||
},
|
||||
processGroupId,
|
||||
controllerServiceType: controllerServiceType.type,
|
||||
controllerServiceBundle: controllerServiceType.bundle
|
||||
})
|
||||
.pipe(
|
||||
take(1),
|
||||
switchMap((createReponse) => {
|
||||
// fetch an updated property descriptor
|
||||
return this.flowService
|
||||
.getPropertyDescriptor(processorId, descriptor.name, false)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((descriptorResponse) => {
|
||||
createServiceDialogReference.close();
|
||||
|
||||
return {
|
||||
value: createReponse.id,
|
||||
descriptor:
|
||||
descriptorResponse.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((error) => {
|
||||
// TODO - show error
|
||||
return NEVER;
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
processorId,
|
||||
this.controllerServiceService,
|
||||
this.flowService,
|
||||
processGroupId
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editProcessor
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
@ -2331,7 +2236,7 @@ export class FlowEffects {
|
|||
return from(this.flowService.getProcessGroup(request.id)).pipe(
|
||||
map((response) =>
|
||||
FlowActions.loadChildProcessGroupSuccess({
|
||||
response: response.component
|
||||
response
|
||||
})
|
||||
),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
|
|
|
@ -326,10 +326,7 @@ export const flowReducer = createReducer(
|
|||
if (collection) {
|
||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||
if (componentIndex > -1) {
|
||||
collection[componentIndex] = {
|
||||
...collection[componentIndex],
|
||||
...response.component
|
||||
};
|
||||
collection[componentIndex] = response.component;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,10 +340,7 @@ export const flowReducer = createReducer(
|
|||
if (collection) {
|
||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||
if (componentIndex > -1) {
|
||||
collection[componentIndex] = {
|
||||
...collection[componentIndex],
|
||||
...response.component
|
||||
};
|
||||
collection[componentIndex] = response.component;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,10 +355,7 @@ export const flowReducer = createReducer(
|
|||
if (collection) {
|
||||
const componentIndex: number = collection.findIndex((f: any) => response.id === f.id);
|
||||
if (componentIndex > -1) {
|
||||
collection[componentIndex] = {
|
||||
...collection[componentIndex],
|
||||
...response.component
|
||||
};
|
||||
collection[componentIndex] = response;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import { provideMockStore } from '@ngrx/store/testing';
|
|||
import { initialState } from '../../state/controller-services/controller-services.reducer';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Component } from '@angular/core';
|
||||
import { ControllerServicesModule } from './controller-services.module';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
|
||||
describe('ControllerServices', () => {
|
||||
let component: ControllerServices;
|
||||
|
@ -37,7 +39,7 @@ describe('ControllerServices', () => {
|
|||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ControllerServices],
|
||||
imports: [RouterTestingModule, MockNavigation],
|
||||
imports: [RouterTestingModule, MockNavigation, ControllerServicesModule, HttpClientTestingModule],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState
|
||||
|
|
|
@ -37,19 +37,6 @@ export class ParameterContextService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getParameterContexts(): Observable<any> {
|
||||
return this.httpClient.get(`${ParameterContextService.API}/flow/parameter-contexts`);
|
||||
}
|
||||
|
@ -77,11 +64,11 @@ export class ParameterContextService {
|
|||
}
|
||||
|
||||
pollParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
||||
return this.httpClient.get(this.stripProtocol(updateRequest.uri));
|
||||
return this.httpClient.get(this.nifiCommon.stripProtocol(updateRequest.uri));
|
||||
}
|
||||
|
||||
deleteParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
||||
return this.httpClient.delete(this.stripProtocol(updateRequest.uri));
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(updateRequest.uri));
|
||||
}
|
||||
|
||||
deleteParameterContext(deleteParameterContext: DeleteParameterContextRequest): Observable<any> {
|
||||
|
|
|
@ -28,7 +28,7 @@ import { RouterLink } from '@angular/router';
|
|||
|
||||
@NgModule({
|
||||
declarations: [ParameterContextListing, ParameterContextTable],
|
||||
exports: [ParameterContextListing],
|
||||
exports: [ParameterContextListing, ParameterContextTable],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NgxSkeletonLoaderModule,
|
||||
|
|
|
@ -31,12 +31,13 @@ import { CurrentUser } from '../../../../../state/current-user';
|
|||
export class ParameterContextTable {
|
||||
@Input() initialSortColumn: 'name' | 'provider' | 'description' = 'name';
|
||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
@Input() set parameterContexts(parameterContextEntities: ParameterContextEntity[]) {
|
||||
this.dataSource.data = this.sortEntities(parameterContextEntities, {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
});
|
||||
this.dataSource.data = this.sortEntities(parameterContextEntities, this.activeSort);
|
||||
}
|
||||
|
||||
@Input() selectedParameterContextId!: string;
|
||||
|
@ -109,6 +110,7 @@ export class ParameterContextTable {
|
|||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||
import { ProvenanceRequest } from '../state/provenance-event-listing';
|
||||
|
@ -31,19 +31,6 @@ export class ProvenanceService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getSearchOptions(): Observable<any> {
|
||||
return this.httpClient.get(`${ProvenanceService.API}/provenance/search-options`);
|
||||
}
|
||||
|
|
|
@ -30,25 +30,12 @@ export class QueueService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getConnection(connectionId: string): Observable<any> {
|
||||
return this.httpClient.get(`${QueueService.API}/connections/${connectionId}`);
|
||||
}
|
||||
|
||||
getFlowFile(flowfileSummary: FlowFileSummary): Observable<any> {
|
||||
return this.httpClient.get(this.stripProtocol(flowfileSummary.uri));
|
||||
return this.httpClient.get(this.nifiCommon.stripProtocol(flowfileSummary.uri));
|
||||
}
|
||||
|
||||
submitQueueListingRequest(queueListingRequest: SubmitQueueListingRequest): Observable<any> {
|
||||
|
@ -59,15 +46,15 @@ export class QueueService {
|
|||
}
|
||||
|
||||
pollQueueListingRequest(listingRequest: ListingRequest): Observable<any> {
|
||||
return this.httpClient.get(this.stripProtocol(listingRequest.uri));
|
||||
return this.httpClient.get(this.nifiCommon.stripProtocol(listingRequest.uri));
|
||||
}
|
||||
|
||||
deleteQueueListingRequest(listingRequest: ListingRequest): Observable<any> {
|
||||
return this.httpClient.delete(this.stripProtocol(listingRequest.uri));
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(listingRequest.uri));
|
||||
}
|
||||
|
||||
downloadContent(flowfileSummary: FlowFileSummary): void {
|
||||
let dataUri: string = `${this.stripProtocol(flowfileSummary.uri)}/content`;
|
||||
let dataUri: string = `${this.nifiCommon.stripProtocol(flowfileSummary.uri)}/content`;
|
||||
|
||||
const queryParameters: any = {};
|
||||
|
||||
|
@ -83,7 +70,7 @@ export class QueueService {
|
|||
|
||||
viewContent(flowfileSummary: FlowFileSummary, contentViewerUrl: string): void {
|
||||
// build the uri to the data
|
||||
let dataUri: string = `${this.stripProtocol(flowfileSummary.uri)}/content`;
|
||||
let dataUri: string = `${this.nifiCommon.stripProtocol(flowfileSummary.uri)}/content`;
|
||||
|
||||
const dataUriParameters: any = {};
|
||||
|
||||
|
|
|
@ -99,7 +99,26 @@ const routes: Routes = [
|
|||
}
|
||||
]
|
||||
},
|
||||
{ path: 'parameter-providers', component: ParameterProviders }
|
||||
{
|
||||
path: 'parameter-providers',
|
||||
component: ParameterProviders,
|
||||
children: [
|
||||
{
|
||||
path: ':id',
|
||||
component: ParameterProviders,
|
||||
children: [
|
||||
{
|
||||
path: 'edit',
|
||||
component: ParameterProviders
|
||||
},
|
||||
{
|
||||
path: 'fetch',
|
||||
component: ParameterProviders
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
|
|
@ -35,6 +35,7 @@ import { ReportingTasksEffects } from '../state/reporting-tasks/reporting-tasks.
|
|||
import { RegistryClientsEffects } from '../state/registry-clients/registry-clients.effects';
|
||||
import { FlowAnalysisRulesEffects } from '../state/flow-analysis-rules/flow-analysis-rules.effects';
|
||||
import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
||||
import { ParameterProvidersEffects } from '../state/parameter-providers/parameter-providers.effects';
|
||||
|
||||
@NgModule({
|
||||
declarations: [Settings],
|
||||
|
@ -54,7 +55,8 @@ import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
|||
ManagementControllerServicesEffects,
|
||||
ReportingTasksEffects,
|
||||
FlowAnalysisRulesEffects,
|
||||
RegistryClientsEffects
|
||||
RegistryClientsEffects,
|
||||
ParameterProvidersEffects
|
||||
),
|
||||
MatTabsModule,
|
||||
Navigation
|
||||
|
|
|
@ -27,24 +27,12 @@ import {
|
|||
EnableFlowAnalysisRuleRequest,
|
||||
FlowAnalysisRuleEntity
|
||||
} from '../state/flow-analysis-rules';
|
||||
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class FlowAnalysisRuleService {
|
||||
export class FlowAnalysisRuleService implements PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -68,7 +56,7 @@ export class FlowAnalysisRuleService {
|
|||
deleteFlowAnalysisRule(deleteFlowAnalysisRule: DeleteFlowAnalysisRuleRequest): Observable<any> {
|
||||
const entity: FlowAnalysisRuleEntity = deleteFlowAnalysisRule.flowAnalysisRule;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
return this.httpClient.delete(this.stripProtocol(entity.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||
|
@ -83,14 +71,14 @@ export class FlowAnalysisRuleService {
|
|||
|
||||
updateFlowAnalysisRule(configureFlowAnalysisRule: ConfigureFlowAnalysisRuleRequest): Observable<any> {
|
||||
return this.httpClient.put(
|
||||
this.stripProtocol(configureFlowAnalysisRule.uri),
|
||||
this.nifiCommon.stripProtocol(configureFlowAnalysisRule.uri),
|
||||
configureFlowAnalysisRule.payload
|
||||
);
|
||||
}
|
||||
|
||||
setEnable(flowAnalysisRule: EnableFlowAnalysisRuleRequest, enabled: boolean): Observable<any> {
|
||||
const entity: FlowAnalysisRuleEntity = flowAnalysisRule.flowAnalysisRule;
|
||||
return this.httpClient.put(`${this.stripProtocol(entity.uri)}/run-status`, {
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(entity.uri)}/run-status`, {
|
||||
revision: this.client.getRevision(entity),
|
||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||
uiOnly: true
|
||||
|
|
|
@ -16,34 +16,25 @@
|
|||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import {
|
||||
ConfigureControllerServiceRequest,
|
||||
CreateControllerServiceRequest,
|
||||
DeleteControllerServiceRequest
|
||||
} from '../state/management-controller-services';
|
||||
import { Client } from '../../../service/client.service';
|
||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||
import { ControllerServiceEntity } from '../../../state/shared';
|
||||
import {
|
||||
ControllerServiceCreator,
|
||||
ControllerServiceEntity,
|
||||
CreateControllerServiceRequest,
|
||||
PropertyDescriptorRetriever
|
||||
} from '../../../state/shared';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ManagementControllerServiceService {
|
||||
export class ManagementControllerServiceService implements ControllerServiceCreator, PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -79,7 +70,7 @@ export class ManagementControllerServiceService {
|
|||
|
||||
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
||||
return this.httpClient.put(
|
||||
this.stripProtocol(configureControllerService.uri),
|
||||
this.nifiCommon.stripProtocol(configureControllerService.uri),
|
||||
configureControllerService.payload
|
||||
);
|
||||
}
|
||||
|
@ -87,6 +78,6 @@ export class ManagementControllerServiceService {
|
|||
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
||||
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
return this.httpClient.delete(this.stripProtocol(entity.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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 { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Client } from '../../../service/client.service';
|
||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
ConfigureParameterProviderRequest,
|
||||
CreateParameterProviderRequest,
|
||||
DeleteParameterProviderRequest,
|
||||
ParameterProviderEntity
|
||||
} from '../state/parameter-providers';
|
||||
import { PropertyDescriptorRetriever, Revision } from '../../../state/shared';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ParameterProviderService implements PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
getParameterProviders(): Observable<any> {
|
||||
return this.httpClient.get(`${ParameterProviderService.API}/flow/parameter-providers`);
|
||||
}
|
||||
|
||||
createParameterProvider(request: CreateParameterProviderRequest) {
|
||||
return this.httpClient.post(`${ParameterProviderService.API}/controller/parameter-providers`, {
|
||||
revision: request.revision,
|
||||
component: {
|
||||
bundle: request.parameterProviderBundle,
|
||||
type: request.parameterProviderType
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteParameterProvider(request: DeleteParameterProviderRequest) {
|
||||
const entity: ParameterProviderEntity = request.parameterProvider;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
const params: any = {
|
||||
...revision,
|
||||
disconnectedNodeAcknowledged: false
|
||||
};
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||
const params: any = {
|
||||
propertyName,
|
||||
sensitive
|
||||
};
|
||||
return this.httpClient.get(`${ParameterProviderService.API}/parameter-providers/${id}/descriptors`, {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
updateParameterProvider(configureRequest: ConfigureParameterProviderRequest): Observable<any> {
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(configureRequest.uri), configureRequest.payload);
|
||||
}
|
||||
}
|
|
@ -26,24 +26,12 @@ import {
|
|||
EditRegistryClientRequest,
|
||||
RegistryClientEntity
|
||||
} from '../state/registry-clients';
|
||||
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class RegistryClientService {
|
||||
export class RegistryClientService implements PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -69,12 +57,12 @@ export class RegistryClientService {
|
|||
}
|
||||
|
||||
updateRegistryClient(request: EditRegistryClientRequest): Observable<any> {
|
||||
return this.httpClient.put(this.stripProtocol(request.uri), request.payload);
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(request.uri), request.payload);
|
||||
}
|
||||
|
||||
deleteRegistryClient(deleteRegistryClient: DeleteRegistryClientRequest): Observable<any> {
|
||||
const entity: RegistryClientEntity = deleteRegistryClient.registryClient;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
return this.httpClient.delete(this.stripProtocol(entity.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,24 +28,12 @@ import {
|
|||
StartReportingTaskRequest,
|
||||
StopReportingTaskRequest
|
||||
} from '../state/reporting-tasks';
|
||||
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ReportingTaskService {
|
||||
export class ReportingTaskService implements PropertyDescriptorRetriever {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -69,7 +57,7 @@ export class ReportingTaskService {
|
|||
deleteReportingTask(deleteReportingTask: DeleteReportingTaskRequest): Observable<any> {
|
||||
const entity: ReportingTaskEntity = deleteReportingTask.reportingTask;
|
||||
const revision: any = this.client.getRevision(entity);
|
||||
return this.httpClient.delete(this.stripProtocol(entity.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(entity.uri), { params: revision });
|
||||
}
|
||||
|
||||
startReportingTask(startReportingTask: StartReportingTaskRequest): Observable<any> {
|
||||
|
@ -79,7 +67,7 @@ export class ReportingTaskService {
|
|||
revision,
|
||||
state: 'RUNNING'
|
||||
};
|
||||
return this.httpClient.put(`${this.stripProtocol(entity.uri)}/run-status`, payload);
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(entity.uri)}/run-status`, payload);
|
||||
}
|
||||
|
||||
stopReportingTask(stopReportingTask: StopReportingTaskRequest): Observable<any> {
|
||||
|
@ -89,7 +77,7 @@ export class ReportingTaskService {
|
|||
revision,
|
||||
state: 'STOPPED'
|
||||
};
|
||||
return this.httpClient.put(`${this.stripProtocol(entity.uri)}/run-status`, payload);
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(entity.uri)}/run-status`, payload);
|
||||
}
|
||||
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||
|
@ -103,6 +91,9 @@ export class ReportingTaskService {
|
|||
}
|
||||
|
||||
updateReportingTask(configureReportingTask: ConfigureReportingTaskRequest): Observable<any> {
|
||||
return this.httpClient.put(this.stripProtocol(configureReportingTask.uri), configureReportingTask.payload);
|
||||
return this.httpClient.put(
|
||||
this.nifiCommon.stripProtocol(configureReportingTask.uri),
|
||||
configureReportingTask.payload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as FlowAnalysisRuleActions from './flow-analysis-rules.actions';
|
||||
import { catchError, from, map, NEVER, Observable, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { catchError, from, map, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NiFiState } from '../../../../state';
|
||||
|
@ -30,20 +30,11 @@ import { ManagementControllerServiceService } from '../../service/management-con
|
|||
import { CreateFlowAnalysisRule } from '../../ui/flow-analysis-rules/create-flow-analysis-rule/create-flow-analysis-rule.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 { UpdateControllerServiceRequest } from '../../../../state/shared';
|
||||
import { EditFlowAnalysisRule } from '../../ui/flow-analysis-rules/edit-flow-analysis-rule/edit-flow-analysis-rule.component';
|
||||
import { CreateFlowAnalysisRuleSuccess } from './index';
|
||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component';
|
||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class FlowAnalysisRulesEffects {
|
||||
|
@ -55,7 +46,8 @@ export class FlowAnalysisRulesEffects {
|
|||
private extensionTypesService: ExtensionTypesService,
|
||||
private flowAnalysisRuleService: FlowAnalysisRuleService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
loadFlowAnalysisRule$ = createEffect(() =>
|
||||
|
@ -225,36 +217,8 @@ export class FlowAnalysisRulesEffects {
|
|||
|
||||
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.flowAnalysisRuleService
|
||||
.getPropertyDescriptor(request.id, dialogResponse.name, dialogResponse.sensitive)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(request.id, this.flowAnalysisRuleService);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editFlowAnalysisRuleForm.dirty) {
|
||||
|
@ -285,73 +249,12 @@ export class FlowAnalysisRulesEffects {
|
|||
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) => {
|
||||
// fetch an updated property descriptor
|
||||
return this.flowAnalysisRuleService
|
||||
.getPropertyDescriptor(ruleId, 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.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
request.id,
|
||||
this.managementControllerServiceService,
|
||||
this.flowAnalysisRuleService
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editFlowAnalysisRule
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
|
|
@ -29,6 +29,8 @@ import { registryClientsFeatureKey, RegistryClientsState } from './registry-clie
|
|||
import { registryClientsReducer } from './registry-clients/registry-clients.reducer';
|
||||
import { flowAnalysisRulesFeatureKey, FlowAnalysisRulesState } from './flow-analysis-rules';
|
||||
import { flowAnalysisRulesReducer } from './flow-analysis-rules/flow-analysis-rules.reducer';
|
||||
import { parameterProvidersFeatureKey, ParameterProvidersState } from './parameter-providers';
|
||||
import { parameterProvidersReducer } from './parameter-providers/parameter-providers.reducer';
|
||||
|
||||
export const settingsFeatureKey = 'settings';
|
||||
|
||||
|
@ -38,6 +40,7 @@ export interface SettingsState {
|
|||
[reportingTasksFeatureKey]: ReportingTasksState;
|
||||
[flowAnalysisRulesFeatureKey]: FlowAnalysisRulesState;
|
||||
[registryClientsFeatureKey]: RegistryClientsState;
|
||||
[parameterProvidersFeatureKey]: ParameterProvidersState;
|
||||
}
|
||||
|
||||
export function reducers(state: SettingsState | undefined, action: Action) {
|
||||
|
@ -46,7 +49,8 @@ export function reducers(state: SettingsState | undefined, action: Action) {
|
|||
[managementControllerServicesFeatureKey]: managementControllerServicesReducer,
|
||||
[reportingTasksFeatureKey]: reportingTasksReducer,
|
||||
[flowAnalysisRulesFeatureKey]: flowAnalysisRulesReducer,
|
||||
[registryClientsFeatureKey]: registryClientsReducer
|
||||
[registryClientsFeatureKey]: registryClientsReducer,
|
||||
[parameterProvidersFeatureKey]: parameterProvidersReducer
|
||||
})(state, action);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,6 @@ export interface LoadManagementControllerServicesResponse {
|
|||
loadedTimestamp: string;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceRequest {
|
||||
controllerServiceType: string;
|
||||
controllerServiceBundle: Bundle;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceSuccess {
|
||||
controllerService: ControllerServiceEntity;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { createAction, props } from '@ngrx/store';
|
|||
import {
|
||||
ConfigureControllerServiceRequest,
|
||||
ConfigureControllerServiceSuccess,
|
||||
CreateControllerServiceRequest,
|
||||
CreateControllerServiceSuccess,
|
||||
DeleteControllerServiceRequest,
|
||||
DeleteControllerServiceSuccess,
|
||||
|
@ -27,6 +26,7 @@ import {
|
|||
SelectControllerServiceRequest
|
||||
} from './index';
|
||||
import {
|
||||
CreateControllerServiceRequest,
|
||||
DisableControllerServiceDialogRequest,
|
||||
EditControllerServiceDialogRequest,
|
||||
SetEnableControllerServiceDialogRequest
|
||||
|
|
|
@ -33,18 +33,15 @@ import {
|
|||
ControllerServiceReferencingComponent,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
NewPropertyDialogRequest,
|
||||
NewPropertyDialogResponse,
|
||||
Property,
|
||||
PropertyDescriptor,
|
||||
UpdateControllerServiceRequest
|
||||
} from '../../../../state/shared';
|
||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||
import { selectSaving } from './management-controller-services.selectors';
|
||||
import { EnableControllerService } from '../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component';
|
||||
import { DisableControllerService } from '../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class ManagementControllerServicesEffects {
|
||||
|
@ -55,7 +52,8 @@ export class ManagementControllerServicesEffects {
|
|||
private managementControllerServiceService: ManagementControllerServiceService,
|
||||
private extensionTypesService: ExtensionTypesService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
loadManagementControllerServices$ = createEffect(() =>
|
||||
|
@ -193,36 +191,11 @@ export class ManagementControllerServicesEffects {
|
|||
|
||||
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.managementControllerServiceService
|
||||
.getPropertyDescriptor(request.id, dialogResponse.name, dialogResponse.sensitive)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(
|
||||
request.id,
|
||||
this.managementControllerServiceService
|
||||
);
|
||||
};
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||
|
@ -260,84 +233,21 @@ export class ManagementControllerServicesEffects {
|
|||
goTo(route, component.referenceType);
|
||||
};
|
||||
|
||||
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.managementControllerServiceService
|
||||
.getPropertyDescriptor(serviceId, 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.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
request.id,
|
||||
this.managementControllerServiceService,
|
||||
this.managementControllerServiceService,
|
||||
null,
|
||||
(createResponse) =>
|
||||
this.store.dispatch(
|
||||
ManagementControllerServicesActions.inlineCreateControllerServiceSuccess({
|
||||
response: {
|
||||
controllerService: createResponse
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editControllerService
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 {
|
||||
Bundle,
|
||||
DocumentedType,
|
||||
ParameterContextReferenceEntity,
|
||||
Permissions,
|
||||
PropertyDescriptor,
|
||||
Revision
|
||||
} from '../../../../state/shared';
|
||||
|
||||
export const parameterProvidersFeatureKey = 'parameterProviders';
|
||||
|
||||
export interface ParameterProvider {
|
||||
bundle: Bundle;
|
||||
comments: string;
|
||||
deprecated: boolean;
|
||||
descriptors: { [key: string]: PropertyDescriptor };
|
||||
extensionMissing: boolean;
|
||||
id: string;
|
||||
multipleVersionsAvailable: boolean;
|
||||
name: string;
|
||||
parameterGroupConfigurations: any[];
|
||||
persistsState: boolean;
|
||||
properties: { [key: string]: string };
|
||||
referencingParameterContexts: ParameterContextReferenceEntity[];
|
||||
restricted: boolean;
|
||||
type: string;
|
||||
validationStatus: string;
|
||||
validationErrors?: string[];
|
||||
}
|
||||
|
||||
export interface ParameterProviderEntity {
|
||||
id: string;
|
||||
bulletins: [];
|
||||
component: ParameterProvider;
|
||||
permissions: Permissions;
|
||||
revision: Revision;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface ParameterProvidersState {
|
||||
parameterProviders: ParameterProviderEntity[];
|
||||
saving: boolean;
|
||||
loadedTimestamp: string;
|
||||
error: string | null;
|
||||
status: 'pending' | 'loading' | 'error' | 'success';
|
||||
}
|
||||
|
||||
export interface LoadParameterProvidersResponse {
|
||||
parameterProviders: ParameterProviderEntity[];
|
||||
loadedTimestamp: string;
|
||||
}
|
||||
|
||||
export interface SelectParameterProviderRequest {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface CreateParameterProviderDialogRequest {
|
||||
parameterProviderTypes: DocumentedType[];
|
||||
}
|
||||
|
||||
export interface CreateParameterProviderRequest {
|
||||
parameterProviderType: string;
|
||||
parameterProviderBundle: Bundle;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface CreateParameterProviderSuccessResponse {
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
}
|
||||
|
||||
export interface DeleteParameterProviderRequest {
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
}
|
||||
|
||||
export interface DeleteParameterProviderSuccess {
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
}
|
||||
|
||||
export interface EditParameterProviderRequest {
|
||||
id: string;
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
}
|
||||
|
||||
export interface ConfigureParameterProviderRequest {
|
||||
id: string;
|
||||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureParameterProviderSuccess {
|
||||
id: string;
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateParameterProviderRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 { createAction, props } from '@ngrx/store';
|
||||
import {
|
||||
ConfigureParameterProviderRequest,
|
||||
ConfigureParameterProviderSuccess,
|
||||
CreateParameterProviderRequest,
|
||||
CreateParameterProviderSuccessResponse,
|
||||
DeleteParameterProviderRequest,
|
||||
DeleteParameterProviderSuccess,
|
||||
EditParameterProviderRequest,
|
||||
LoadParameterProvidersResponse,
|
||||
SelectParameterProviderRequest
|
||||
} from './index';
|
||||
|
||||
const PARAMETER_PROVIDERS_PREFIX: string = '[Parameter Providers]';
|
||||
|
||||
export const resetParameterProvidersState = createAction(`${PARAMETER_PROVIDERS_PREFIX} Reset Parameter Providers`);
|
||||
|
||||
export const loadParameterProviders = createAction(`${PARAMETER_PROVIDERS_PREFIX} Load Parameter Providers`);
|
||||
|
||||
export const loadParameterProvidersSuccess = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Load Parameter Providers Success`,
|
||||
props<{ response: LoadParameterProvidersResponse }>()
|
||||
);
|
||||
|
||||
export const parameterProvidersApiError = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Load Parameter Providers Error`,
|
||||
props<{ error: string }>()
|
||||
);
|
||||
|
||||
export const selectParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Select Parameter Provider`,
|
||||
props<{ request: SelectParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const openNewParameterProviderDialog = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Open New Parameter Provider Dialog`
|
||||
);
|
||||
|
||||
export const createParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Create Parameter Provider`,
|
||||
props<{ request: CreateParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const createParameterProviderSuccess = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Create Parameter Provider Success`,
|
||||
props<{ response: CreateParameterProviderSuccessResponse }>()
|
||||
);
|
||||
|
||||
export const promptParameterProviderDeletion = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Prompt Parameter Provider Deletion`,
|
||||
props<{ request: DeleteParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const deleteParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Delete Parameter Provider`,
|
||||
props<{ request: DeleteParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const deleteParameterProviderSuccess = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Delete Parameter Provider Success`,
|
||||
props<{ response: DeleteParameterProviderSuccess }>()
|
||||
);
|
||||
|
||||
export const navigateToEditParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Navigate To Edit Parameter Provider`,
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const openConfigureParameterProviderDialog = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Open Configure Parameter Provider Dialog`,
|
||||
props<{ request: EditParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const configureParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Configure Parameter Provider`,
|
||||
props<{ request: ConfigureParameterProviderRequest }>()
|
||||
);
|
||||
|
||||
export const configureParameterProviderSuccess = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Configure Parameter Provider Success`,
|
||||
props<{ response: ConfigureParameterProviderSuccess }>()
|
||||
);
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* 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 { Injectable } from '@angular/core';
|
||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NiFiState } from '../../../../state';
|
||||
import { Client } from '../../../../service/client.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Router } from '@angular/router';
|
||||
import { ParameterProviderService } from '../../service/parameter-provider.service';
|
||||
import * as ParameterProviderActions from './parameter-providers.actions';
|
||||
import { loadParameterProviders, selectParameterProvider } from './parameter-providers.actions';
|
||||
import { catchError, from, map, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { selectSaving } from './parameter-providers.selectors';
|
||||
import { selectParameterProviderTypes } from '../../../../state/extension-types/extension-types.selectors';
|
||||
import { CreateParameterProvider } from '../../ui/parameter-providers/create-parameter-provider/create-parameter-provider.component';
|
||||
import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component';
|
||||
import { EditParameterProvider } from '../../ui/parameter-providers/edit-parameter-provider/edit-parameter-provider.component';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
import { UpdateParameterProviderRequest } from './index';
|
||||
import { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
||||
|
||||
@Injectable()
|
||||
export class ParameterProvidersEffects {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private store: Store<NiFiState>,
|
||||
private client: Client,
|
||||
private dialog: MatDialog,
|
||||
private router: Router,
|
||||
private parameterProviderService: ParameterProviderService,
|
||||
private propertyTableHelperService: PropertyTableHelperService,
|
||||
private managementControllerServiceService: ManagementControllerServiceService
|
||||
) {}
|
||||
|
||||
loadParameterProviders$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(loadParameterProviders),
|
||||
switchMap(() =>
|
||||
from(this.parameterProviderService.getParameterProviders()).pipe(
|
||||
map((response) =>
|
||||
ParameterProviderActions.loadParameterProvidersSuccess({
|
||||
response: {
|
||||
parameterProviders: response.parameterProviders,
|
||||
loadedTimestamp: response.currentTime
|
||||
}
|
||||
})
|
||||
),
|
||||
catchError((error) =>
|
||||
of(ParameterProviderActions.parameterProvidersApiError({ error: error.error }))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
selectParameterProvider$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(selectParameterProvider),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/settings', 'parameter-providers', request.id]);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
openNewParameterProviderDialog$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.openNewParameterProviderDialog),
|
||||
concatLatestFrom(() => this.store.select(selectParameterProviderTypes)),
|
||||
tap(([action, parameterProviderTypes]) => {
|
||||
const dialogReference = this.dialog.open(CreateParameterProvider, {
|
||||
data: {
|
||||
parameterProviderTypes
|
||||
},
|
||||
panelClass: 'medium-dialog'
|
||||
});
|
||||
|
||||
dialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||
|
||||
dialogReference.componentInstance.createParameterProvider
|
||||
.pipe(take(1))
|
||||
.subscribe((parameterProviderType) => {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.createParameterProvider({
|
||||
request: {
|
||||
parameterProviderType: parameterProviderType.type,
|
||||
parameterProviderBundle: parameterProviderType.bundle,
|
||||
revision: {
|
||||
clientId: this.client.getClientId(),
|
||||
version: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
createParameterProvider$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.createParameterProvider),
|
||||
map((action) => action.request),
|
||||
switchMap((request) =>
|
||||
from(this.parameterProviderService.createParameterProvider(request)).pipe(
|
||||
map((response: any) =>
|
||||
ParameterProviderActions.createParameterProviderSuccess({
|
||||
response: {
|
||||
parameterProvider: response
|
||||
}
|
||||
})
|
||||
),
|
||||
catchError((error) =>
|
||||
of(ParameterProviderActions.parameterProvidersApiError({ error: error.error }))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
createParameterProviderSuccess$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.createParameterProviderSuccess),
|
||||
map((action) => action.response),
|
||||
tap(() => {
|
||||
this.dialog.closeAll();
|
||||
}),
|
||||
switchMap((response) =>
|
||||
of(
|
||||
ParameterProviderActions.selectParameterProvider({
|
||||
request: {
|
||||
id: response.parameterProvider.id
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
promptParameterProviderDeletion$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.promptParameterProviderDeletion),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
const dialogReference = this.dialog.open(YesNoDialog, {
|
||||
data: {
|
||||
title: 'Delete Parameter Provider',
|
||||
message: `Delete parameter provider ${request.parameterProvider.component.name}?`
|
||||
},
|
||||
panelClass: 'small-dialog'
|
||||
});
|
||||
|
||||
dialogReference.componentInstance.yes.pipe(take(1)).subscribe(() =>
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.deleteParameterProvider({
|
||||
request
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
deleteParameterProvider = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.deleteParameterProvider),
|
||||
map((action) => action.request),
|
||||
switchMap((request) =>
|
||||
from(this.parameterProviderService.deleteParameterProvider(request)).pipe(
|
||||
map((response: any) =>
|
||||
ParameterProviderActions.deleteParameterProviderSuccess({
|
||||
response: {
|
||||
parameterProvider: response
|
||||
}
|
||||
})
|
||||
),
|
||||
catchError((error) =>
|
||||
of(
|
||||
ParameterProviderActions.parameterProvidersApiError({
|
||||
error: error.error
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
navigateToEditParameterProvider$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.navigateToEditParameterProvider),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
this.router.navigate(['settings', 'parameter-providers', id, 'edit']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
openConfigureParameterProviderDialog$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.openConfigureParameterProviderDialog),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
const id = request.id;
|
||||
const editDialogReference = this.dialog.open(EditParameterProvider, {
|
||||
data: {
|
||||
parameterProvider: request.parameterProvider
|
||||
},
|
||||
id,
|
||||
panelClass: 'large-dialog'
|
||||
});
|
||||
|
||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||
|
||||
const goTo = (commands: string[], destination: string) => {
|
||||
// confirm navigating away while changes are unsaved
|
||||
if (editDialogReference.componentInstance.editParameterProviderForm.dirty) {
|
||||
const promptSaveDialogRef = this.dialog.open(YesNoDialog, {
|
||||
data: {
|
||||
title: 'Parameter Provider Configuration',
|
||||
message: `Save changes before going to this ${destination}`
|
||||
},
|
||||
panelClass: 'small-dialog'
|
||||
});
|
||||
|
||||
promptSaveDialogRef.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
});
|
||||
|
||||
promptSaveDialogRef.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.close('ROUTED');
|
||||
this.router.navigate(commands);
|
||||
});
|
||||
} else {
|
||||
editDialogReference.close('ROUTED');
|
||||
this.router.navigate(commands);
|
||||
}
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToReferencingParameterContext = (id: string) => {
|
||||
const commands: string[] = ['parameter-contexts', id];
|
||||
goTo(commands, 'Parameter Context');
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
goTo(commands, 'Controller Service');
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(request.id, this.parameterProviderService);
|
||||
|
||||
editDialogReference.componentInstance.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
request.id,
|
||||
this.managementControllerServiceService,
|
||||
this.parameterProviderService
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editParameterProvider
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
.subscribe((updateRequest: UpdateParameterProviderRequest) => {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.configureParameterProvider({
|
||||
request: {
|
||||
id: request.parameterProvider.id,
|
||||
uri: request.parameterProvider.uri,
|
||||
payload: updateRequest.payload,
|
||||
postUpdateNavigation: updateRequest.postUpdateNavigation
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
editDialogReference.afterClosed().subscribe((response) => {
|
||||
if (response !== 'ROUTED') {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.selectParameterProvider({
|
||||
request: {
|
||||
id
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
configureParameterProvider$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.configureParameterProvider),
|
||||
map((action) => action.request),
|
||||
switchMap((request) =>
|
||||
from(this.parameterProviderService.updateParameterProvider(request)).pipe(
|
||||
map((response) =>
|
||||
ParameterProviderActions.configureParameterProviderSuccess({
|
||||
response: {
|
||||
id: request.id,
|
||||
parameterProvider: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
}
|
||||
})
|
||||
),
|
||||
catchError((error) =>
|
||||
of(
|
||||
ParameterProviderActions.parameterProvidersApiError({
|
||||
error: error.error
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
configureParameterProviderSuccess$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.configureParameterProviderSuccess),
|
||||
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 }
|
||||
);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 { ParameterProvidersState } from './index';
|
||||
import { createReducer, on } from '@ngrx/store';
|
||||
import {
|
||||
configureParameterProvider,
|
||||
configureParameterProviderSuccess,
|
||||
createParameterProvider,
|
||||
createParameterProviderSuccess,
|
||||
deleteParameterProvider,
|
||||
deleteParameterProviderSuccess,
|
||||
loadParameterProviders,
|
||||
loadParameterProvidersSuccess,
|
||||
parameterProvidersApiError,
|
||||
resetParameterProvidersState
|
||||
} from './parameter-providers.actions';
|
||||
import { produce } from 'immer';
|
||||
|
||||
export const initialParameterProvidersState: ParameterProvidersState = {
|
||||
parameterProviders: [],
|
||||
saving: false,
|
||||
loadedTimestamp: '',
|
||||
error: null,
|
||||
status: 'pending'
|
||||
};
|
||||
|
||||
export const parameterProvidersReducer = createReducer(
|
||||
initialParameterProvidersState,
|
||||
|
||||
on(resetParameterProvidersState, (state: ParameterProvidersState) => ({
|
||||
...initialParameterProvidersState
|
||||
})),
|
||||
|
||||
on(loadParameterProviders, (state: ParameterProvidersState) => ({
|
||||
...state,
|
||||
status: 'loading' as const
|
||||
})),
|
||||
|
||||
on(loadParameterProvidersSuccess, (state: ParameterProvidersState, { response }) => ({
|
||||
...state,
|
||||
parameterProviders: response.parameterProviders,
|
||||
loadedTimestamp: response.loadedTimestamp,
|
||||
error: null,
|
||||
status: 'success' as const
|
||||
})),
|
||||
|
||||
on(parameterProvidersApiError, (state: ParameterProvidersState, { error }) => ({
|
||||
...state,
|
||||
saving: false,
|
||||
error,
|
||||
status: 'error' as const
|
||||
})),
|
||||
|
||||
on(createParameterProvider, configureParameterProvider, deleteParameterProvider, (state, { request }) => ({
|
||||
...state,
|
||||
saving: true
|
||||
})),
|
||||
|
||||
on(createParameterProviderSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
draftState.parameterProviders.push(response.parameterProvider);
|
||||
draftState.saving = false;
|
||||
});
|
||||
}),
|
||||
|
||||
on(deleteParameterProviderSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
const idx = draftState.parameterProviders.findIndex(
|
||||
(provider) => provider.id === response.parameterProvider.id
|
||||
);
|
||||
if (idx > -1) {
|
||||
draftState.parameterProviders.splice(idx, 1);
|
||||
}
|
||||
draftState.saving = false;
|
||||
});
|
||||
}),
|
||||
|
||||
on(configureParameterProviderSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
const idx = draftState.parameterProviders.findIndex(
|
||||
(provider) => provider.id === response.parameterProvider.id
|
||||
);
|
||||
|
||||
if (idx > -1) {
|
||||
draftState.parameterProviders[idx] = response.parameterProvider;
|
||||
}
|
||||
|
||||
draftState.saving = false;
|
||||
});
|
||||
})
|
||||
);
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 { createSelector } from '@ngrx/store';
|
||||
import { selectSettingsState, SettingsState } from '../index';
|
||||
import { ParameterProviderEntity, parameterProvidersFeatureKey, ParameterProvidersState } from './index';
|
||||
import { selectCurrentRoute } from '../../../../state/router/router.selectors';
|
||||
|
||||
export const selectParameterProvidersState = createSelector(
|
||||
selectSettingsState,
|
||||
(state: SettingsState) => state[parameterProvidersFeatureKey]
|
||||
);
|
||||
|
||||
export const selectSaving = createSelector(
|
||||
selectParameterProvidersState,
|
||||
(state: ParameterProvidersState) => state.saving
|
||||
);
|
||||
|
||||
export const selectParameterProviderIdFromRoute = createSelector(selectCurrentRoute, (route) => {
|
||||
if (route) {
|
||||
// always select the parameter provider from the route
|
||||
return route.params.id;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
export const selectSingleEditedParameterProvider = createSelector(selectCurrentRoute, (route) => {
|
||||
if (route?.routeConfig?.path == 'edit') {
|
||||
return route.params.id;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
export const selectParameterProviders = createSelector(
|
||||
selectParameterProvidersState,
|
||||
(state: ParameterProvidersState) => state.parameterProviders
|
||||
);
|
||||
|
||||
export const selectParameterProvider = (id: string) =>
|
||||
createSelector(selectParameterProviders, (entities: ParameterProviderEntity[]) =>
|
||||
entities.find((entity) => id == entity.id)
|
||||
);
|
|
@ -18,7 +18,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as RegistryClientsActions from './registry-clients.actions';
|
||||
import { catchError, from, map, NEVER, Observable, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { catchError, from, map, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NiFiState } from '../../../../state';
|
||||
|
@ -29,20 +29,11 @@ import { RegistryClientService } from '../../service/registry-client.service';
|
|||
import { CreateRegistryClient } from '../../ui/registry-clients/create-registry-client/create-registry-client.component';
|
||||
import { selectSaving } from './registry-clients.selectors';
|
||||
import { EditRegistryClient } from '../../ui/registry-clients/edit-registry-client/edit-registry-client.component';
|
||||
import {
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
NewPropertyDialogRequest,
|
||||
NewPropertyDialogResponse,
|
||||
Property,
|
||||
PropertyDescriptor
|
||||
} from '../../../../state/shared';
|
||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
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 { Client } from '../../../../service/client.service';
|
||||
import { EditRegistryClientRequest } from './index';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class RegistryClientsEffects {
|
||||
|
@ -54,7 +45,8 @@ export class RegistryClientsEffects {
|
|||
private extensionTypesService: ExtensionTypesService,
|
||||
private managementControllerServiceService: ManagementControllerServiceService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
loadRegistryClients$ = createEffect(() =>
|
||||
|
@ -181,40 +173,8 @@ export class RegistryClientsEffects {
|
|||
|
||||
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.registryClientService
|
||||
.getPropertyDescriptor(
|
||||
registryClientId,
|
||||
dialogResponse.name,
|
||||
dialogResponse.sensitive
|
||||
)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(registryClientId, this.registryClientService);
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
|
@ -242,77 +202,12 @@ export class RegistryClientsEffects {
|
|||
}
|
||||
};
|
||||
|
||||
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((createReponse) => {
|
||||
// fetch an updated property descriptor
|
||||
return this.registryClientService
|
||||
.getPropertyDescriptor(
|
||||
registryClientId,
|
||||
descriptor.name,
|
||||
false
|
||||
)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((descriptorResponse) => {
|
||||
createServiceDialogReference.close();
|
||||
|
||||
return {
|
||||
value: createReponse.id,
|
||||
descriptor:
|
||||
descriptorResponse.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((error) => {
|
||||
// TODO - show error
|
||||
return NEVER;
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
registryClientId,
|
||||
this.managementControllerServiceService,
|
||||
this.registryClientService
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editRegistryClient
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
|
|
@ -44,6 +44,7 @@ import { ExtensionTypesService } from '../../../../service/extension-types.servi
|
|||
import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component';
|
||||
import { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
||||
import { Client } from '../../../../service/client.service';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
|
||||
@Injectable()
|
||||
export class ReportingTasksEffects {
|
||||
|
@ -55,7 +56,8 @@ export class ReportingTasksEffects {
|
|||
private managementControllerServiceService: ManagementControllerServiceService,
|
||||
private extensionTypesService: ExtensionTypesService,
|
||||
private dialog: MatDialog,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private propertyTableHelperService: PropertyTableHelperService
|
||||
) {}
|
||||
|
||||
loadReportingTasks$ = createEffect(() =>
|
||||
|
@ -225,36 +227,8 @@ export class ReportingTasksEffects {
|
|||
|
||||
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
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
this.propertyTableHelperService.createNewProperty(request.id, this.reportingTaskService);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editReportingTaskForm.dirty) {
|
||||
|
@ -285,73 +259,12 @@ export class ReportingTasksEffects {
|
|||
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) => {
|
||||
// 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.createNewService =
|
||||
this.propertyTableHelperService.createNewService(
|
||||
request.id,
|
||||
this.managementControllerServiceService,
|
||||
this.reportingTaskService
|
||||
);
|
||||
|
||||
editDialogReference.componentInstance.editReportingTask
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<extension-creation
|
||||
[componentType]="'Parameter Provider'"
|
||||
[documentedTypes]="parameterProviderTypes"
|
||||
[saving]="(saving$ | async)!"
|
||||
(extensionTypeSelected)="parameterProviderTypeSelected($event)"></extension-creation>
|
|
@ -0,0 +1,16 @@
|
|||
/*!
|
||||
* 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.
|
||||
*/
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 { CreateParameterProvider } from './create-parameter-provider.component';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialParameterProvidersState } from '../../../state/parameter-providers/parameter-providers.reducer';
|
||||
import {
|
||||
CreateParameterProviderDialogRequest,
|
||||
CreateParameterProviderRequest
|
||||
} from '../../../state/parameter-providers';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('CreateParameterProvider', () => {
|
||||
let component: CreateParameterProvider;
|
||||
let fixture: ComponentFixture<CreateParameterProvider>;
|
||||
const data: CreateParameterProviderDialogRequest = {
|
||||
parameterProviderTypes: [
|
||||
{
|
||||
type: 'org.apache.nifi.parameter.aws.AwsSecretsManagerParameterProvider',
|
||||
bundle: {
|
||||
group: 'org.apache.nifi',
|
||||
artifact: 'nifi-aws-nar',
|
||||
version: '2.0.0-SNAPSHOT'
|
||||
},
|
||||
description:
|
||||
'Fetches parameters from AWS SecretsManager. Each secret becomes a Parameter group, which can map to a Parameter Context, with key/value pairs in the secret mapping to Parameters in the group.',
|
||||
restricted: false,
|
||||
tags: ['secretsmanager', 'manager', 'aws', 'secrets']
|
||||
},
|
||||
{
|
||||
type: 'org.apache.nifi.parameter.azure.AzureKeyVaultSecretsParameterProvider',
|
||||
bundle: {
|
||||
group: 'org.apache.nifi',
|
||||
artifact: 'nifi-azure-nar',
|
||||
version: '2.0.0-SNAPSHOT'
|
||||
},
|
||||
description:
|
||||
"Fetches parameters from Azure Key Vault Secrets. Each secret becomes a Parameter, which map to a Parameter Group byadding a secret tag named 'group-name'.",
|
||||
restricted: false,
|
||||
tags: ['keyvault', 'secrets', 'key', 'vault', 'azure']
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CreateParameterProvider, NoopAnimationsModule],
|
||||
providers: [
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: data
|
||||
},
|
||||
provideMockStore({ initialState: initialParameterProvidersState })
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(CreateParameterProvider);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DocumentedType } from '../../../../../state/shared';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { CreateParameterProviderDialogRequest } from '../../../state/parameter-providers';
|
||||
import { ExtensionCreation } from '../../../../../ui/common/extension-creation/extension-creation.component';
|
||||
|
||||
@Component({
|
||||
selector: 'create-parameter-provider',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ExtensionCreation],
|
||||
templateUrl: './create-parameter-provider.component.html',
|
||||
styleUrls: ['./create-parameter-provider.component.scss']
|
||||
})
|
||||
export class CreateParameterProvider {
|
||||
@Input() saving$!: Observable<boolean>;
|
||||
@Output() createParameterProvider: EventEmitter<DocumentedType> = new EventEmitter<DocumentedType>();
|
||||
|
||||
parameterProviderTypes: DocumentedType[];
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) private dialogRequest: CreateParameterProviderDialogRequest) {
|
||||
this.parameterProviderTypes = dialogRequest.parameterProviderTypes;
|
||||
}
|
||||
|
||||
parameterProviderTypeSelected(parameterProviderType: DocumentedType) {
|
||||
this.createParameterProvider.next(parameterProviderType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<!--
|
||||
~ 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 Parameter Provider</h2>
|
||||
<form class="parameter-provider-edit-form" [formGroup]="editParameterProviderForm">
|
||||
<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>
|
||||
<mat-form-field>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput formControlName="name" type="text" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Id</div>
|
||||
<div class="value">{{ request.parameterProvider.id }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Type</div>
|
||||
<div class="value">{{ formatType(request.parameterProvider) }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Bundle</div>
|
||||
<div class="value">{{ formatBundle(request.parameterProvider) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col w-full">
|
||||
<div>Referencing Components</div>
|
||||
<div>
|
||||
<parameter-provider-references
|
||||
[parameterProviderReferences]="
|
||||
request.parameterProvider.component.referencingParameterContexts
|
||||
"
|
||||
(goToParameterContext)="
|
||||
navigateToParameterContext($event)
|
||||
"></parameter-provider-references>
|
||||
</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"></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]="!editParameterProviderForm.dirty || editParameterProviderForm.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,36 @@
|
|||
/*!
|
||||
* 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;
|
||||
|
||||
.parameter-provider-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%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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 { EditParameterProvider } from './edit-parameter-provider.component';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { EditParameterProviderRequest } from '../../../state/parameter-providers';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('EditParameterProvider', () => {
|
||||
let component: EditParameterProvider;
|
||||
let fixture: ComponentFixture<EditParameterProvider>;
|
||||
const data: EditParameterProviderRequest = {
|
||||
id: 'id',
|
||||
parameterProvider: {
|
||||
revision: {
|
||||
clientId: '36ba1cc1-018d-1000-bc2c-787bc552d63d',
|
||||
version: 6
|
||||
},
|
||||
id: '369487d7-018d-1000-817a-1d8d9a8f4a91',
|
||||
uri: 'https://localhost:8443/nifi-api/parameter-providers/369487d7-018d-1000-817a-1d8d9a8f4a91',
|
||||
permissions: {
|
||||
canRead: true,
|
||||
canWrite: true
|
||||
},
|
||||
bulletins: [],
|
||||
component: {
|
||||
id: '369487d7-018d-1000-817a-1d8d9a8f4a91',
|
||||
name: 'Group 1 - FileParameterProvider',
|
||||
type: 'org.apache.nifi.parameter.FileParameterProvider',
|
||||
bundle: {
|
||||
group: 'org.apache.nifi',
|
||||
artifact: 'nifi-standard-nar',
|
||||
version: '2.0.0-SNAPSHOT'
|
||||
},
|
||||
comments: '',
|
||||
persistsState: false,
|
||||
restricted: true,
|
||||
deprecated: false,
|
||||
multipleVersionsAvailable: false,
|
||||
properties: {
|
||||
'parameter-group-directories': '/Users/rfellows/tmp/parameterProviders/group1',
|
||||
'parameter-value-byte-limit': '256 B',
|
||||
'parameter-value-encoding': 'plaintext'
|
||||
},
|
||||
descriptors: {
|
||||
'parameter-group-directories': {
|
||||
name: 'parameter-group-directories',
|
||||
displayName: 'Parameter Group Directories',
|
||||
description:
|
||||
'A comma-separated list of directory absolute paths that will map to named parameter groups. Each directory that contains files will map to a parameter group, named after the innermost directory in the path. Files inside the directory will map to parameter names, whose values are the content of each respective file.',
|
||||
required: true,
|
||||
sensitive: false,
|
||||
dynamic: false,
|
||||
supportsEl: false,
|
||||
expressionLanguageScope: 'Not Supported',
|
||||
dependencies: []
|
||||
},
|
||||
'parameter-value-byte-limit': {
|
||||
name: 'parameter-value-byte-limit',
|
||||
displayName: 'Parameter Value Byte Limit',
|
||||
description:
|
||||
'The maximum byte size of a parameter value. Since parameter values are pulled from the contents of files, this is a safeguard that can prevent memory issues if large files are included.',
|
||||
defaultValue: '256 B',
|
||||
required: true,
|
||||
sensitive: false,
|
||||
dynamic: false,
|
||||
supportsEl: false,
|
||||
expressionLanguageScope: 'Not Supported',
|
||||
dependencies: []
|
||||
},
|
||||
'parameter-value-encoding': {
|
||||
name: 'parameter-value-encoding',
|
||||
displayName: 'Parameter Value Encoding',
|
||||
description: 'Indicates how parameter values are encoded inside Parameter files.',
|
||||
defaultValue: 'base64',
|
||||
allowableValues: [
|
||||
{
|
||||
allowableValue: {
|
||||
displayName: 'Base64',
|
||||
value: 'base64',
|
||||
description:
|
||||
'File content is Base64-encoded, and will be decoded before providing the value as a Parameter.'
|
||||
},
|
||||
canRead: true
|
||||
},
|
||||
{
|
||||
allowableValue: {
|
||||
displayName: 'Plain text',
|
||||
value: 'plaintext',
|
||||
description:
|
||||
'File content is not encoded, and will be provided directly as a Parameter value.'
|
||||
},
|
||||
canRead: true
|
||||
}
|
||||
],
|
||||
required: true,
|
||||
sensitive: false,
|
||||
dynamic: false,
|
||||
supportsEl: false,
|
||||
expressionLanguageScope: 'Not Supported',
|
||||
dependencies: []
|
||||
}
|
||||
},
|
||||
parameterGroupConfigurations: [
|
||||
{
|
||||
groupName: 'group1',
|
||||
parameterContextName: 'group1',
|
||||
parameterSensitivities: {
|
||||
bytes: 'NON_SENSITIVE',
|
||||
password: 'SENSITIVE',
|
||||
username: 'NON_SENSITIVE'
|
||||
},
|
||||
synchronized: true
|
||||
}
|
||||
],
|
||||
referencingParameterContexts: [
|
||||
{
|
||||
id: '3716e18d-018d-1000-f203-4f6d571d572e',
|
||||
permissions: {
|
||||
canRead: true,
|
||||
canWrite: true
|
||||
},
|
||||
bulletins: [],
|
||||
component: {
|
||||
id: '3716e18d-018d-1000-f203-4f6d571d572e',
|
||||
name: 'group1'
|
||||
}
|
||||
}
|
||||
],
|
||||
validationStatus: 'VALID',
|
||||
extensionMissing: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [EditParameterProvider, NoopAnimationsModule],
|
||||
providers: [
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: data
|
||||
}
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(EditParameterProvider);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spinner.directive';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
ControllerServiceReferencingComponent,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
ParameterContextReferenceEntity,
|
||||
Property
|
||||
} from '../../../../../state/shared';
|
||||
import {
|
||||
EditParameterProviderRequest,
|
||||
ParameterProviderEntity,
|
||||
UpdateParameterProviderRequest
|
||||
} from '../../../state/parameter-providers';
|
||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Client } from '../../../../../service/client.service';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { ControllerServiceReferences } from '../../../../../ui/common/controller-service/controller-service-references/controller-service-references.component';
|
||||
import { ParameterProviderReferences } from '../parameter-context-references/parameter-provider-references.component';
|
||||
import { PropertyTable } from '../../../../../ui/common/property-table/property-table.component';
|
||||
|
||||
@Component({
|
||||
selector: 'edit-parameter-provider',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatDialogModule,
|
||||
MatTabsModule,
|
||||
MatButtonModule,
|
||||
NifiSpinnerDirective,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
ControllerServiceReferences,
|
||||
ParameterProviderReferences,
|
||||
PropertyTable
|
||||
],
|
||||
templateUrl: './edit-parameter-provider.component.html',
|
||||
styleUrls: ['./edit-parameter-provider.component.scss']
|
||||
})
|
||||
export class EditParameterProvider {
|
||||
@Input() createNewProperty!: (existingProperties: string[], allowsSensitive: boolean) => Observable<Property>;
|
||||
@Input() createNewService!: (request: InlineServiceCreationRequest) => Observable<InlineServiceCreationResponse>;
|
||||
@Input() goToService!: (serviceId: string) => void;
|
||||
@Input() goToReferencingParameterContext!: (parameterContextId: string) => void;
|
||||
@Input() saving$!: Observable<boolean>;
|
||||
|
||||
@Output() editParameterProvider: EventEmitter<UpdateParameterProviderRequest> =
|
||||
new EventEmitter<UpdateParameterProviderRequest>();
|
||||
|
||||
editParameterProviderForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public request: EditParameterProviderRequest,
|
||||
private formBuilder: FormBuilder,
|
||||
private client: Client,
|
||||
private nifiCommon: NiFiCommon
|
||||
) {
|
||||
const providerProperties = request.parameterProvider.component.properties;
|
||||
const properties: Property[] = Object.entries(providerProperties).map((entry: any) => {
|
||||
const [property, value] = entry;
|
||||
return {
|
||||
property,
|
||||
value,
|
||||
descriptor: request.parameterProvider.component.descriptors[property]
|
||||
};
|
||||
});
|
||||
|
||||
// build the form
|
||||
this.editParameterProviderForm = this.formBuilder.group({
|
||||
name: new FormControl(request.parameterProvider.component.name, Validators.required),
|
||||
properties: new FormControl(properties),
|
||||
comments: new FormControl(request.parameterProvider.component.comments)
|
||||
});
|
||||
}
|
||||
|
||||
formatType(entity: ParameterProviderEntity): string {
|
||||
return this.nifiCommon.formatType(entity.component);
|
||||
}
|
||||
|
||||
formatBundle(entity: ParameterProviderEntity): string {
|
||||
return this.nifiCommon.formatBundle(entity.component.bundle);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.parameterProvider),
|
||||
component: {
|
||||
id: this.request.parameterProvider.id,
|
||||
name: this.editParameterProviderForm.get('name')?.value,
|
||||
comments: this.editParameterProviderForm.get('comments')?.value
|
||||
}
|
||||
};
|
||||
|
||||
const propertyControl: AbstractControl | null = this.editParameterProviderForm.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.editParameterProvider.next({
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
});
|
||||
}
|
||||
|
||||
navigateToParameterContext(parameterContextReference: ParameterContextReferenceEntity) {
|
||||
if (parameterContextReference.component?.id) {
|
||||
this.goToReferencingParameterContext(parameterContextReference.component?.id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 { ParameterProviderReferences } from './parameter-provider-references.component';
|
||||
|
||||
describe('ParameterProviderReferences', () => {
|
||||
let component: ParameterProviderReferences;
|
||||
let fixture: ComponentFixture<ParameterProviderReferences>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ParameterProviderReferences]
|
||||
});
|
||||
fixture = TestBed.createComponent(ParameterProviderReferences);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ParameterContextReferenceEntity } from '../../../../../state/shared';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'parameter-provider-references',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterLink],
|
||||
templateUrl: './parameter-providers-references.component.html',
|
||||
styleUrls: ['./parameter-providers-references.component.scss']
|
||||
})
|
||||
export class ParameterProviderReferences {
|
||||
@Input() parameterProviderReferences!: ParameterContextReferenceEntity[];
|
||||
@Output() goToParameterContext: EventEmitter<ParameterContextReferenceEntity> =
|
||||
new EventEmitter<ParameterContextReferenceEntity>();
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
getUnauthorized(references: ParameterContextReferenceEntity[]) {
|
||||
return references.filter((p) => !p.permissions.canRead);
|
||||
}
|
||||
|
||||
getAuthorized(references: ParameterContextReferenceEntity[]) {
|
||||
return references.filter((p) => p.permissions.canRead);
|
||||
}
|
||||
|
||||
goToParameterContextClicked(event: MouseEvent, parameterContextReference: ParameterContextReferenceEntity) {
|
||||
event.stopPropagation();
|
||||
this.goToParameterContext.next(parameterContextReference);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<div class="parameter-provider-references">
|
||||
<div
|
||||
*ngIf="!parameterProviderReferences || parameterProviderReferences?.length === 0; else hasReferences"
|
||||
class="value">
|
||||
No referencing components
|
||||
</div>
|
||||
|
||||
<ng-template #hasReferences>
|
||||
<ul>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
parameterContexts;
|
||||
context: {
|
||||
$implicit: getAuthorized(parameterProviderReferences),
|
||||
label: 'Parameter Contexts'
|
||||
}
|
||||
"></ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
unauthorized;
|
||||
context: {
|
||||
$implicit: getUnauthorized(parameterProviderReferences),
|
||||
label: 'Unauthorized'
|
||||
}
|
||||
"></ng-container>
|
||||
</ul>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #parameterContexts let-references let-label="label">
|
||||
<ng-container *ngIf="references.length > 0">
|
||||
<li>
|
||||
<h4>
|
||||
<span class="value">{{ label }}</span> ({{ references.length }})
|
||||
</h4>
|
||||
<div class="references">
|
||||
<div *ngFor="let reference of references" class="flex items-center gap-x-2">
|
||||
<a (click)="goToParameterContextClicked($event, reference)">{{ reference.component?.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #unauthorized let-references let-label="label">
|
||||
<ng-container *ngIf="references.length > 0">
|
||||
<li>
|
||||
<h4>
|
||||
<span class="value">{{ label }}</span> ({{ references.length }})
|
||||
</h4>
|
||||
<div class="references">
|
||||
<div *ngFor="let reference of references" class="flex items-center gap-x-2">
|
||||
<div class="unset">{{ reference.id }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
/*!
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.parameter-provider-references {
|
||||
ul.nested {
|
||||
padding-inline-start: 20px;
|
||||
}
|
||||
|
||||
.references {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<ng-container>
|
||||
<div class="parameter-providers-table h-full flex flex-col">
|
||||
<div class="flex-1 relative">
|
||||
<div class="listing-table overflow-y-auto border absolute inset-0">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
matSort
|
||||
matSortDisableClear
|
||||
(matSortChange)="sortData($event)"
|
||||
[matSortActive]="initialSortColumn"
|
||||
[matSortDirection]="initialSortDirection">
|
||||
<!-- More Details Column -->
|
||||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO: open details -->
|
||||
<div class="pointer fa fa-info-circle" title="View details"></div>
|
||||
|
||||
<!-- TODO: open documentation -->
|
||||
<div class="pointer fa fa-book" title="View Documentation"></div>
|
||||
|
||||
<!-- Validation Errors -->
|
||||
<div *ngIf="hasErrors(item)">
|
||||
<div
|
||||
class="pointer fa fa-warning has-errors"
|
||||
nifiTooltip
|
||||
[delayClose]="false"
|
||||
[tooltipComponentType]="ValidationErrorsTip"
|
||||
[tooltipInputData]="getValidationErrorsTipData(item)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Name</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatName(item)">
|
||||
<div [ngClass]="{ unset: !canRead(item) }">{{ formatName(item) }}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Type column -->
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Type</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatType(item)">
|
||||
{{ formatType(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Bundle column -->
|
||||
<ng-container matColumnDef="bundle">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>
|
||||
<div class="flex-1 overflow-ellipsis overflow-hidden whitespace-nowrap">Bundle</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let item" [title]="formatBundle(item)">
|
||||
{{ formatBundle(item) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div
|
||||
class="pointer fa fa-pencil"
|
||||
(click)="configureClicked(item, $event)"
|
||||
title="Edit"></div>
|
||||
<div
|
||||
class="pointer fa fa-arrow-circle-down"
|
||||
(click)="fetchClicked(item, $event)"
|
||||
title="Fetch Parameters"></div>
|
||||
<div
|
||||
class="pointer fa fa-trash"
|
||||
(click)="deleteClicked(item, $event)"
|
||||
title="Remove"></div>
|
||||
<div
|
||||
*ngIf="canManageAccessPolicies()"
|
||||
class="pointer fa fa-key"
|
||||
(click)="$event.stopPropagation()"
|
||||
[routerLink]="getPolicyLink(item)"
|
||||
title="Access Policies"></div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
<tr
|
||||
mat-row
|
||||
*matRowDef="let row; let even = even; columns: displayedColumns"
|
||||
[class.even]="even"
|
||||
(click)="selectParameterProvider.next(row)"
|
||||
[class.selected]="isSelected(row)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
|
@ -0,0 +1,22 @@
|
|||
/*!
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.parameter-providers-table {
|
||||
.listing-table {
|
||||
// overrides to the listing-table styles go here
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 { ParameterProvidersTable } from './parameter-providers-table.component';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('ParameterProvidersTable', () => {
|
||||
let component: ParameterProvidersTable;
|
||||
let fixture: ComponentFixture<ParameterProvidersTable>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ParameterProvidersTable, NoopAnimationsModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(ParameterProvidersTable);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* 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, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatSortModule, Sort, SortDirection } from '@angular/material/sort';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { ParameterProviderEntity } from '../../../state/parameter-providers';
|
||||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
import { CurrentUser } from '../../../../../state/current-user';
|
||||
import { FlowConfiguration } from '../../../../../state/flow-configuration';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { SummaryTableFilterModule } from '../../../../summary/ui/common/summary-table-filter/summary-table-filter.module';
|
||||
import { PortStatusSnapshotEntity } from '../../../../summary/state/summary-listing';
|
||||
import { ValidationErrorsTip } from '../../../../../ui/common/tooltips/validation-errors-tip/validation-errors-tip.component';
|
||||
import { NifiTooltipDirective } from '../../../../../ui/common/tooltips/nifi-tooltip.directive';
|
||||
import { ControllerServiceEntity, ValidationErrorsTipInput } from '../../../../../state/shared';
|
||||
import { RouterLink } from '@angular/router';
|
||||
|
||||
export type SupportedColumns = 'name' | 'type' | 'bundle';
|
||||
|
||||
@Component({
|
||||
selector: 'parameter-providers-table',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatTableModule,
|
||||
SummaryTableFilterModule,
|
||||
NifiTooltipDirective,
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './parameter-providers-table.component.html',
|
||||
styleUrls: ['./parameter-providers-table.component.scss', '../../../../../../assets/styles/listing-table.scss']
|
||||
})
|
||||
export class ParameterProvidersTable {
|
||||
@Input() initialSortColumn: SupportedColumns = 'name';
|
||||
@Input() initialSortDirection: SortDirection = 'asc';
|
||||
|
||||
displayedColumns: string[] = ['moreDetails', 'name', 'type', 'bundle', 'actions'];
|
||||
dataSource: MatTableDataSource<ParameterProviderEntity> = new MatTableDataSource<ParameterProviderEntity>();
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
constructor(private nifiCommon: NiFiCommon) {}
|
||||
|
||||
@Input() selectedParameterProviderId!: string;
|
||||
@Input() currentUser!: CurrentUser;
|
||||
@Input() flowConfiguration!: FlowConfiguration;
|
||||
|
||||
@Input() set parameterProviders(parameterProviders: ParameterProviderEntity[]) {
|
||||
if (parameterProviders) {
|
||||
this.dataSource.data = this.sortEntities(parameterProviders, this.activeSort);
|
||||
}
|
||||
}
|
||||
|
||||
@Output() selectParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() configureParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() deleteParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() fetchParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() manageAccessPolicies: EventEmitter<ParameterProviderEntity> = new EventEmitter<ParameterProviderEntity>();
|
||||
|
||||
protected readonly ValidationErrorsTip = ValidationErrorsTip;
|
||||
|
||||
canRead(entity: ParameterProviderEntity): boolean {
|
||||
return entity.permissions.canRead;
|
||||
}
|
||||
|
||||
canWrite(entity: ParameterProviderEntity): boolean {
|
||||
return entity.permissions.canWrite;
|
||||
}
|
||||
|
||||
canManageAccessPolicies(): boolean {
|
||||
return this.flowConfiguration.supportsManagedAuthorizer && this.currentUser.tenantsPermissions.canRead;
|
||||
}
|
||||
|
||||
isSelected(parameterProvider: ParameterProviderEntity): boolean {
|
||||
if (this.selectedParameterProviderId) {
|
||||
return parameterProvider.id === this.selectedParameterProviderId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
formatName(entity: ParameterProviderEntity): string {
|
||||
return this.canRead(entity) ? entity.component.name : entity.id;
|
||||
}
|
||||
|
||||
formatType(entity: ParameterProviderEntity): string {
|
||||
return this.canRead(entity) ? this.nifiCommon.formatType(entity.component) : '';
|
||||
}
|
||||
|
||||
formatBundle(entity: ParameterProviderEntity): string {
|
||||
return this.canRead(entity) ? this.nifiCommon.formatBundle(entity.component.bundle) : '';
|
||||
}
|
||||
|
||||
hasErrors(entity: ParameterProviderEntity): boolean {
|
||||
return this.canRead(entity) && !this.nifiCommon.isEmpty(entity.component.validationErrors);
|
||||
}
|
||||
|
||||
getValidationErrorsTipData(entity: ParameterProviderEntity): ValidationErrorsTipInput | null {
|
||||
return {
|
||||
isValidating: entity.component.validationStatus === 'VALIDATING',
|
||||
validationErrors: entity.component?.validationErrors || []
|
||||
};
|
||||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
private sortEntities(data: ParameterProviderEntity[], sort: Sort): ParameterProviderEntity[] {
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
return data.slice().sort((a, b) => {
|
||||
const isAsc: boolean = sort.direction === 'asc';
|
||||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(this.formatName(a), this.formatName(b));
|
||||
break;
|
||||
case 'type':
|
||||
retVal = this.nifiCommon.compareString(this.formatType(a), this.formatType(b));
|
||||
break;
|
||||
case 'bundle':
|
||||
retVal = this.nifiCommon.compareString(this.formatBundle(a), this.formatBundle(b));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return retVal * (isAsc ? 1 : -1);
|
||||
});
|
||||
}
|
||||
|
||||
configureClicked(entity: ParameterProviderEntity, event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.configureParameterProvider.next(entity);
|
||||
}
|
||||
|
||||
fetchClicked(entity: ParameterProviderEntity, event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.fetchParameterProvider.next(entity);
|
||||
}
|
||||
|
||||
deleteClicked(entity: ParameterProviderEntity, event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.deleteParameterProvider.next(entity);
|
||||
}
|
||||
|
||||
getPolicyLink(entity: ParameterProviderEntity): string[] {
|
||||
return ['/access-policies', 'read', 'component', 'parameter-providers', entity.id];
|
||||
}
|
||||
}
|
|
@ -15,4 +15,39 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<p>parameter-providers works!</p>
|
||||
<ng-container *ngIf="parameterProvidersState$ | async; let parameterProvidersState">
|
||||
<div *ngIf="isInitialLoading(parameterProvidersState); else loaded">
|
||||
<ngx-skeleton-loader count="3"></ngx-skeleton-loader>
|
||||
</div>
|
||||
<ng-template #loaded>
|
||||
<div class="flex flex-col h-full gap-y-2" *ngIf="currentUser$ | async; let currentUser">
|
||||
<div class="flex justify-end" *ngIf="currentUser.controllerPermissions.canWrite">
|
||||
<button
|
||||
class="nifi-button"
|
||||
(click)="openNewParameterProviderDialog()"
|
||||
title="Add a new parameter provider">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<parameter-providers-table
|
||||
[currentUser]="currentUser"
|
||||
[flowConfiguration]="(flowConfiguration$ | async)!"
|
||||
[parameterProviders]="parameterProvidersState.parameterProviders"
|
||||
[selectedParameterProviderId]="selectedParameterProviderId$ | async"
|
||||
(deleteParameterProvider)="deleteParameterProvider($event)"
|
||||
(configureParameterProvider)="openConfigureParameterProviderDialog($event)"
|
||||
(selectParameterProvider)="selectParameterProvider($event)"></parameter-providers-table>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
<button class="nifi-button" (click)="refreshParameterProvidersListing()">
|
||||
<i class="fa fa-refresh" [class.fa-spin]="parameterProvidersState.status === 'loading'"></i>
|
||||
</button>
|
||||
<div>Last updated:</div>
|
||||
<div class="refresh-timestamp">{{ parameterProvidersState.loadedTimestamp }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ParameterProviders } from './parameter-providers.component';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialParameterProvidersState } from '../../state/parameter-providers/parameter-providers.reducer';
|
||||
|
||||
describe('ParameterProviders', () => {
|
||||
let component: ParameterProviders;
|
||||
|
@ -25,7 +27,12 @@ describe('ParameterProviders', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ParameterProviders]
|
||||
declarations: [ParameterProviders],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState: initialParameterProvidersState
|
||||
})
|
||||
]
|
||||
});
|
||||
fixture = TestBed.createComponent(ParameterProviders);
|
||||
component = fixture.componentInstance;
|
||||
|
|
|
@ -15,11 +15,105 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NiFiState } from '../../../../state';
|
||||
import { ParameterProviderEntity, ParameterProvidersState } from '../../state/parameter-providers';
|
||||
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
|
||||
import {
|
||||
selectParameterProvider,
|
||||
selectParameterProviderIdFromRoute,
|
||||
selectParameterProvidersState,
|
||||
selectSingleEditedParameterProvider
|
||||
} from '../../state/parameter-providers/parameter-providers.selectors';
|
||||
import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors';
|
||||
import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions';
|
||||
import * as ParameterProviderActions from '../../state/parameter-providers/parameter-providers.actions';
|
||||
import { initialParameterProvidersState } from '../../state/parameter-providers/parameter-providers.reducer';
|
||||
import { filter, switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { isDefinedAndNotNull } from '../../../../state/shared';
|
||||
|
||||
@Component({
|
||||
selector: 'parameter-providers',
|
||||
templateUrl: './parameter-providers.component.html',
|
||||
styleUrls: ['./parameter-providers.component.scss']
|
||||
})
|
||||
export class ParameterProviders {}
|
||||
export class ParameterProviders implements OnInit, OnDestroy {
|
||||
currentUser$ = this.store.select(selectCurrentUser);
|
||||
parameterProvidersState$ = this.store.select(selectParameterProvidersState);
|
||||
selectedParameterProviderId$ = this.store.select(selectParameterProviderIdFromRoute);
|
||||
flowConfiguration$ = this.store.select(selectFlowConfiguration);
|
||||
|
||||
constructor(private store: Store<NiFiState>) {
|
||||
this.store
|
||||
.select(selectSingleEditedParameterProvider)
|
||||
.pipe(
|
||||
isDefinedAndNotNull(),
|
||||
switchMap((id: string) =>
|
||||
this.store.select(selectParameterProvider(id)).pipe(isDefinedAndNotNull(), take(1))
|
||||
),
|
||||
takeUntilDestroyed()
|
||||
)
|
||||
.subscribe((entity) => {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.openConfigureParameterProviderDialog({
|
||||
request: {
|
||||
id: entity.id,
|
||||
parameterProvider: entity
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.dispatch(loadFlowConfiguration());
|
||||
this.store.dispatch(ParameterProviderActions.loadParameterProviders());
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.store.dispatch(ParameterProviderActions.resetParameterProvidersState());
|
||||
}
|
||||
|
||||
isInitialLoading(state: ParameterProvidersState): boolean {
|
||||
// using the current timestamp to detect the initial load event
|
||||
return state.loadedTimestamp == initialParameterProvidersState.loadedTimestamp;
|
||||
}
|
||||
|
||||
refreshParameterProvidersListing(): void {
|
||||
this.store.dispatch(ParameterProviderActions.loadParameterProviders());
|
||||
}
|
||||
|
||||
openNewParameterProviderDialog() {
|
||||
this.store.dispatch(ParameterProviderActions.openNewParameterProviderDialog());
|
||||
}
|
||||
|
||||
openConfigureParameterProviderDialog(parameterProvider: ParameterProviderEntity) {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.navigateToEditParameterProvider({
|
||||
id: parameterProvider.component.id
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
selectParameterProvider(parameterProvider: ParameterProviderEntity) {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.selectParameterProvider({
|
||||
request: {
|
||||
id: parameterProvider.id
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteParameterProvider(parameterProvider: ParameterProviderEntity) {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.promptParameterProviderDeletion({
|
||||
request: {
|
||||
parameterProvider
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ParameterProviders } from './parameter-providers.component';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { ParameterContextListingModule } from '../../../parameter-contexts/ui/parameter-context-listing/parameter-context-listing.module';
|
||||
import { ParameterProvidersTable } from './parameter-providers-table/parameter-providers-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ParameterProviders],
|
||||
exports: [ParameterProviders],
|
||||
imports: [CommonModule]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule, ParameterProvidersTable]
|
||||
})
|
||||
export class ParameterProvidersModule {}
|
||||
|
|
|
@ -35,12 +35,13 @@ import { CurrentUser } from '../../../../../state/current-user';
|
|||
export class ReportingTaskTable {
|
||||
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' = 'name';
|
||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
@Input() set reportingTasks(reportingTaskEntities: ReportingTaskEntity[]) {
|
||||
this.dataSource.data = this.sortEntities(reportingTaskEntities, {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
});
|
||||
this.dataSource.data = this.sortEntities(reportingTaskEntities, this.activeSort);
|
||||
}
|
||||
|
||||
@Input() selectedReportingTaskId!: string;
|
||||
|
@ -258,6 +259,7 @@ export class ReportingTaskTable {
|
|||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,19 +32,6 @@ import {
|
|||
export class UsersService {
|
||||
private static readonly API: string = '../nifi-api';
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
private client: Client,
|
||||
|
@ -83,7 +70,7 @@ export class UsersService {
|
|||
...request.userPayload
|
||||
}
|
||||
};
|
||||
return this.httpClient.put(this.stripProtocol(request.uri), payload);
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(request.uri), payload);
|
||||
}
|
||||
|
||||
updateUserGroup(request: UpdateUserGroupRequest): Observable<any> {
|
||||
|
@ -94,16 +81,16 @@ export class UsersService {
|
|||
...request.userGroupPayload
|
||||
}
|
||||
};
|
||||
return this.httpClient.put(this.stripProtocol(request.uri), payload);
|
||||
return this.httpClient.put(this.nifiCommon.stripProtocol(request.uri), payload);
|
||||
}
|
||||
|
||||
deleteUser(user: UserEntity): Observable<any> {
|
||||
const revision: any = this.client.getRevision(user);
|
||||
return this.httpClient.delete(this.stripProtocol(user.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(user.uri), { params: revision });
|
||||
}
|
||||
|
||||
deleteUserGroup(userGroup: UserGroupEntity): Observable<any> {
|
||||
const revision: any = this.client.getRevision(userGroup);
|
||||
return this.httpClient.delete(this.stripProtocol(userGroup.uri), { params: revision });
|
||||
return this.httpClient.delete(this.nifiCommon.stripProtocol(userGroup.uri), { params: revision });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,24 +28,11 @@ export class ComponentStateService {
|
|||
private nifiCommon: NiFiCommon
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getComponentState(request: LoadComponentStateRequest): Observable<any> {
|
||||
return this.httpClient.get(`${this.stripProtocol(request.componentUri)}/state`);
|
||||
return this.httpClient.get(`${this.nifiCommon.stripProtocol(request.componentUri)}/state`);
|
||||
}
|
||||
|
||||
clearComponentState(request: ClearComponentStateRequest): Observable<any> {
|
||||
return this.httpClient.post(`${this.stripProtocol(request.componentUri)}/state/clear-requests`, {});
|
||||
return this.httpClient.post(`${this.nifiCommon.stripProtocol(request.componentUri)}/state/clear-requests`, {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,25 +36,12 @@ export class ControllerServiceStateService {
|
|||
private client: Client
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
private stripProtocol(url: string): string {
|
||||
return this.nifiCommon.substringAfterFirst(url, ':');
|
||||
}
|
||||
|
||||
getControllerService(id: string): Observable<any> {
|
||||
return this.httpClient.get(`${ControllerServiceStateService.API}/controller-services/${id}`);
|
||||
}
|
||||
|
||||
setEnable(controllerService: ControllerServiceEntity, enabled: boolean): Observable<any> {
|
||||
return this.httpClient.put(`${this.stripProtocol(controllerService.uri)}/run-status`, {
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(controllerService.uri)}/run-status`, {
|
||||
revision: this.client.getRevision(controllerService),
|
||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||
uiOnly: true
|
||||
|
@ -69,7 +56,7 @@ export class ControllerServiceStateService {
|
|||
true
|
||||
);
|
||||
|
||||
return this.httpClient.put(`${this.stripProtocol(controllerService.uri)}/references`, {
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(controllerService.uri)}/references`, {
|
||||
id: controllerService.id,
|
||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||
referencingComponentRevisions: referencingComponentRevisions,
|
||||
|
@ -89,7 +76,7 @@ export class ControllerServiceStateService {
|
|||
false
|
||||
);
|
||||
|
||||
return this.httpClient.put(`${this.stripProtocol(controllerService.uri)}/references`, {
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(controllerService.uri)}/references`, {
|
||||
id: controllerService.id,
|
||||
state: running ? 'RUNNING' : 'STOPPED',
|
||||
referencingComponentRevisions: referencingComponentRevisions,
|
||||
|
|
|
@ -511,4 +511,17 @@ export class NiFiCommon {
|
|||
public getAllPolicyTypeListing(): SelectOption[] {
|
||||
return this.policyTypeListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling
|
||||
* does not work on absolute URLs, so we need to strip off the proto for the request header to be added.
|
||||
*
|
||||
* https://stackoverflow.com/a/59586462
|
||||
*
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
public stripProtocol(url: string): string {
|
||||
return this.substringAfterFirst(url, ':');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { catchError, map, NEVER, Observable, switchMap, take } from 'rxjs';
|
||||
import {
|
||||
ControllerServiceCreator,
|
||||
ControllerServiceEntity,
|
||||
CreateControllerServiceRequest,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
NewPropertyDialogRequest,
|
||||
NewPropertyDialogResponse,
|
||||
Property,
|
||||
PropertyDescriptor,
|
||||
PropertyDescriptorRetriever
|
||||
} from '../state/shared';
|
||||
import { NewPropertyDialog } from '../ui/common/new-property-dialog/new-property-dialog.component';
|
||||
import { CreateControllerService } from '../ui/common/controller-service/create-controller-service/create-controller-service.component';
|
||||
import { ManagementControllerServiceService } from '../pages/settings/service/management-controller-service.service';
|
||||
import { ExtensionTypesService } from './extension-types.service';
|
||||
import { Client } from './client.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PropertyTableHelperService {
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private extensionTypesService: ExtensionTypesService,
|
||||
private client: Client
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns a function that can be used to pass into a PropertyTable to support creating a new property
|
||||
* @param id id of the component to create the property for
|
||||
* @param propertyDescriptorService the service to call to get property descriptors
|
||||
*/
|
||||
createNewProperty(
|
||||
id: string,
|
||||
propertyDescriptorService: PropertyDescriptorRetriever
|
||||
): (existingProperties: string[], allowsSensitive: boolean) => Observable<Property> {
|
||||
return (existingProperties: string[], allowsSensitive: boolean) => {
|
||||
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 propertyDescriptorService
|
||||
.getPropertyDescriptor(id, dialogResponse.name, dialogResponse.sensitive)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((response) => {
|
||||
newPropertyDialogReference.close();
|
||||
|
||||
return {
|
||||
property: dialogResponse.name,
|
||||
value: null,
|
||||
descriptor: response.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that can be used to pass into a PropertyTable to create a controller service, inline.
|
||||
*
|
||||
* @param id id of the component where the inline-create controller service was initiated
|
||||
* @param controllerServiceCreator service to use to create the controller service and lookup property descriptors
|
||||
* @param propertyDescriptorService the service to call to get property descriptors
|
||||
* @param afterServiceCreated OPTIONAL - callback function to possibly dispatch an action after the controller service has been created
|
||||
* @param processGroupId OPTIONAL - process group id to create the
|
||||
*/
|
||||
createNewService(
|
||||
id: string,
|
||||
controllerServiceCreator: ControllerServiceCreator,
|
||||
propertyDescriptorService: PropertyDescriptorRetriever,
|
||||
processGroupId?: string | null,
|
||||
afterServiceCreated?: (createdResponse: ControllerServiceEntity) => void
|
||||
): (request: InlineServiceCreationRequest) => Observable<InlineServiceCreationResponse> {
|
||||
return (request: InlineServiceCreationRequest) => {
|
||||
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
|
||||
const payload: CreateControllerServiceRequest = {
|
||||
revision: {
|
||||
clientId: this.client.getClientId(),
|
||||
version: 0
|
||||
},
|
||||
controllerServiceType: controllerServiceType.type,
|
||||
controllerServiceBundle: controllerServiceType.bundle
|
||||
};
|
||||
|
||||
if (processGroupId) {
|
||||
payload.processGroupId = processGroupId;
|
||||
}
|
||||
|
||||
return controllerServiceCreator.createControllerService(payload).pipe(
|
||||
take(1),
|
||||
switchMap((createResponse) => {
|
||||
// if provided, call the callback function
|
||||
if (afterServiceCreated) {
|
||||
afterServiceCreated(createResponse);
|
||||
}
|
||||
|
||||
// fetch an updated property descriptor
|
||||
return propertyDescriptorService
|
||||
.getPropertyDescriptor(id, descriptor.name, false)
|
||||
.pipe(
|
||||
take(1),
|
||||
map((descriptorResponse) => {
|
||||
createServiceDialogReference.close();
|
||||
|
||||
return {
|
||||
value: createResponse.id,
|
||||
descriptor: descriptorResponse.propertyDescriptor
|
||||
};
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((error) => {
|
||||
// TODO - show error
|
||||
return NEVER;
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -51,6 +51,11 @@ export const selectFlowAnalysisRuleTypes = createSelector(
|
|||
(state: ExtensionTypesState) => state.flowAnalysisRuleTypes
|
||||
);
|
||||
|
||||
export const selectParameterProviderTypes = createSelector(
|
||||
selectExtensionTypesState,
|
||||
(state: ExtensionTypesState) => state.parameterProviderTypes
|
||||
);
|
||||
|
||||
export const selectTypesToIdentifyComponentRestrictions = createSelector(
|
||||
selectExtensionTypesState,
|
||||
(state: ExtensionTypesState) => {
|
||||
|
|
|
@ -112,7 +112,7 @@ export interface EditTenantResponse {
|
|||
userGroup?: any;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceRequest {
|
||||
export interface CreateControllerServiceDialogRequest {
|
||||
controllerServiceTypes: DocumentedType[];
|
||||
}
|
||||
|
||||
|
@ -306,6 +306,7 @@ export interface ParameterContextReferenceEntity {
|
|||
permissions: Permissions;
|
||||
id: string;
|
||||
component?: ParameterContextReference;
|
||||
bulletins?: BulletinEntity[];
|
||||
}
|
||||
|
||||
export interface ParameterContextReference {
|
||||
|
@ -508,6 +509,10 @@ export interface PropertyDescriptor {
|
|||
identifiesControllerServiceBundle?: Bundle;
|
||||
}
|
||||
|
||||
export interface PropertyDescriptorEntity {
|
||||
propertyDescriptor: PropertyDescriptor;
|
||||
}
|
||||
|
||||
export interface Property {
|
||||
property: string;
|
||||
value: string | null;
|
||||
|
@ -522,3 +527,18 @@ export interface InlineServiceCreationResponse {
|
|||
value: string;
|
||||
descriptor: PropertyDescriptor;
|
||||
}
|
||||
|
||||
export interface PropertyDescriptorRetriever {
|
||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<PropertyDescriptorEntity>;
|
||||
}
|
||||
|
||||
export interface CreateControllerServiceRequest {
|
||||
processGroupId?: string;
|
||||
controllerServiceType: string;
|
||||
controllerServiceBundle: Bundle;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface ControllerServiceCreator {
|
||||
createControllerService(createControllerService: CreateControllerServiceRequest): Observable<any>;
|
||||
}
|
||||
|
|
|
@ -55,12 +55,13 @@ import { CurrentUser } from '../../../../state/current-user';
|
|||
export class ControllerServiceTable {
|
||||
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' | 'scope' = 'name';
|
||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
@Input() set controllerServices(controllerServiceEntities: ControllerServiceEntity[]) {
|
||||
this.dataSource.data = this.sortEntities(controllerServiceEntities, {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
});
|
||||
this.dataSource.data = this.sortEntities(controllerServiceEntities, this.activeSort);
|
||||
}
|
||||
|
||||
@Input() selectedServiceId!: string;
|
||||
|
@ -277,6 +278,7 @@ export class ControllerServiceTable {
|
|||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateControllerService } from './create-controller-service.component';
|
||||
import { CreateControllerServiceRequest, DocumentedType } from '../../../../state/shared';
|
||||
import { CreateControllerServiceDialogRequest, DocumentedType } from '../../../../state/shared';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialState } from '../../../../state/extension-types/extension-types.reducer';
|
||||
|
@ -28,7 +28,7 @@ describe('CreateControllerService', () => {
|
|||
let component: CreateControllerService;
|
||||
let fixture: ComponentFixture<CreateControllerService>;
|
||||
|
||||
const data: CreateControllerServiceRequest = {
|
||||
const data: CreateControllerServiceDialogRequest = {
|
||||
controllerServiceTypes: [
|
||||
{
|
||||
type: 'org.apache.nifi.services.azure.storage.ADLSCredentialsControllerService',
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { CreateControllerServiceRequest, DocumentedType } from '../../../../state/shared';
|
||||
import { CreateControllerServiceDialogRequest, DocumentedType } from '../../../../state/shared';
|
||||
import { ExtensionCreation } from '../../extension-creation/extension-creation.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
|
@ -35,7 +35,7 @@ export class CreateControllerService {
|
|||
|
||||
controllerServiceTypes: DocumentedType[];
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) private dialogRequest: CreateControllerServiceRequest) {
|
||||
constructor(@Inject(MAT_DIALOG_DATA) private dialogRequest: CreateControllerServiceDialogRequest) {
|
||||
this.controllerServiceTypes = dialogRequest.controllerServiceTypes;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,16 +49,17 @@ export class ExtensionCreation {
|
|||
this.selectedType = documentedTypes[0];
|
||||
}
|
||||
|
||||
this.dataSource.data = this.sortEntities(documentedTypes, {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
});
|
||||
this.dataSource.data = this.sortEntities(documentedTypes, this.activeSort);
|
||||
}
|
||||
|
||||
@Input() componentType!: string;
|
||||
@Input() saving!: boolean;
|
||||
@Input() initialSortColumn: 'type' | 'version' | 'tags' = 'type';
|
||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||
activeSort: Sort = {
|
||||
active: this.initialSortColumn,
|
||||
direction: this.initialSortDirection
|
||||
};
|
||||
|
||||
@Output() extensionTypeSelected: EventEmitter<DocumentedType> = new EventEmitter<DocumentedType>();
|
||||
|
||||
|
@ -151,6 +152,7 @@ export class ExtensionCreation {
|
|||
}
|
||||
|
||||
sortData(sort: Sort) {
|
||||
this.activeSort = sort;
|
||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue