mirror of
https://github.com/apache/nifi.git
synced 2025-02-07 18:48:51 +00:00
[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;
|
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.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;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,6 +32,8 @@ public class ParameterProvidersEntity extends Entity {
|
|||||||
|
|
||||||
private Set<ParameterProviderEntity> parameterProviders;
|
private Set<ParameterProviderEntity> parameterProviders;
|
||||||
|
|
||||||
|
private Date currentTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list of parameter providers that are being serialized
|
* @return list of parameter providers that are being serialized
|
||||||
*/
|
*/
|
||||||
@ -38,4 +45,18 @@ public class ParameterProvidersEntity extends Entity {
|
|||||||
this.parameterProviders = parameterProviders;
|
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 org.apache.nifi.web.api.entity.ParameterProvidersEntity;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -60,6 +61,7 @@ public class ParameterProvidersEndpointMerger extends AbstractSingleEntityEndpoi
|
|||||||
}
|
}
|
||||||
|
|
||||||
clientEntity.setParameterProviders(new HashSet<>(providerEntities.values()));
|
clientEntity.setParameterProviders(new HashSet<>(providerEntities.values()));
|
||||||
|
clientEntity.setCurrentTime(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -672,6 +672,7 @@ public class FlowResource extends ApplicationResource {
|
|||||||
// create the response entity
|
// create the response entity
|
||||||
final ParameterProvidersEntity entity = new ParameterProvidersEntity();
|
final ParameterProvidersEntity entity = new ParameterProvidersEntity();
|
||||||
entity.setParameterProviders(parameterProviders);
|
entity.setParameterProviders(parameterProviders);
|
||||||
|
entity.setCurrentTime(new Date());
|
||||||
|
|
||||||
// generate the response
|
// generate the response
|
||||||
return generateOkResponse(entity).build();
|
return generateOkResponse(entity).build();
|
||||||
|
@ -33,19 +33,6 @@ export class AccessPolicyService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
createAccessPolicy(resourceAction: ResourceAction): Observable<any> {
|
||||||
let resource: string = `/${resourceAction.resource}`;
|
let resource: string = `/${resourceAction.resource}`;
|
||||||
if (resourceAction.resourceIdentifier) {
|
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> {
|
deleteAccessPolicy(accessPolicy: AccessPolicyEntity): Observable<any> {
|
||||||
const revision: any = this.client.getRevision(accessPolicy);
|
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> {
|
getUsers(): Observable<any> {
|
||||||
|
@ -306,6 +306,7 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||||||
return 'icon-label';
|
return 'icon-label';
|
||||||
case 'remote-process-groups':
|
case 'remote-process-groups':
|
||||||
return 'icon-group-remote';
|
return 'icon-group-remote';
|
||||||
|
case 'parameter-providers':
|
||||||
case 'parameter-contexts':
|
case 'parameter-contexts':
|
||||||
return 'icon-drop';
|
return 'icon-drop';
|
||||||
}
|
}
|
||||||
@ -329,6 +330,8 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||||||
return 'Remote Process Group';
|
return 'Remote Process Group';
|
||||||
case 'parameter-contexts':
|
case 'parameter-contexts':
|
||||||
return 'Parameter Contexts';
|
return 'Parameter Contexts';
|
||||||
|
case 'parameter-providers':
|
||||||
|
return 'Parameter Provider';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Process Group';
|
return 'Process Group';
|
||||||
|
@ -42,11 +42,13 @@ export class CounterTable implements AfterViewInit {
|
|||||||
@Input() initialSortColumn: 'context' | 'name' | 'value' = 'context';
|
@Input() initialSortColumn: 'context' | 'name' | 'value' = 'context';
|
||||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||||
|
|
||||||
|
activeSort: Sort = {
|
||||||
|
active: this.initialSortColumn,
|
||||||
|
direction: this.initialSortDirection
|
||||||
|
};
|
||||||
|
|
||||||
@Input() set counters(counterEntities: CounterEntity[]) {
|
@Input() set counters(counterEntities: CounterEntity[]) {
|
||||||
this.dataSource.data = this.sortEntities(counterEntities, {
|
this.dataSource.data = this.sortEntities(counterEntities, this.activeSort);
|
||||||
active: this.initialSortColumn,
|
|
||||||
direction: this.initialSortDirection
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dataSource.filterPredicate = (data: CounterEntity, filter: string) => {
|
this.dataSource.filterPredicate = (data: CounterEntity, filter: string) => {
|
||||||
const { filterTerm, filterColumn } = JSON.parse(filter);
|
const { filterTerm, filterColumn } = JSON.parse(filter);
|
||||||
@ -128,6 +130,7 @@ export class CounterTable implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortData(sort: Sort) {
|
sortData(sort: Sort) {
|
||||||
|
this.activeSort = sort;
|
||||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,34 +16,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { EMPTY, Observable } from 'rxjs';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Client } from '../../../service/client.service';
|
import { Client } from '../../../service/client.service';
|
||||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||||
import { ControllerServiceEntity } from '../../../state/shared';
|
|
||||||
import {
|
import {
|
||||||
ConfigureControllerServiceRequest,
|
ControllerServiceCreator,
|
||||||
|
ControllerServiceEntity,
|
||||||
CreateControllerServiceRequest,
|
CreateControllerServiceRequest,
|
||||||
DeleteControllerServiceRequest
|
PropertyDescriptorRetriever
|
||||||
} from '../state/controller-services';
|
} from '../../../state/shared';
|
||||||
|
import { ConfigureControllerServiceRequest, DeleteControllerServiceRequest } from '../state/controller-services';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ControllerServiceService {
|
export class ControllerServiceService implements ControllerServiceCreator, PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -69,17 +57,20 @@ export class ControllerServiceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createControllerService(createControllerService: CreateControllerServiceRequest): Observable<any> {
|
createControllerService(createControllerService: CreateControllerServiceRequest): Observable<any> {
|
||||||
const processGroupId: string = createControllerService.processGroupId;
|
if (createControllerService.processGroupId) {
|
||||||
return this.httpClient.post(
|
const processGroupId: string = createControllerService.processGroupId;
|
||||||
`${ControllerServiceService.API}/process-groups/${processGroupId}/controller-services`,
|
return this.httpClient.post(
|
||||||
{
|
`${ControllerServiceService.API}/process-groups/${processGroupId}/controller-services`,
|
||||||
revision: createControllerService.revision,
|
{
|
||||||
component: {
|
revision: createControllerService.revision,
|
||||||
bundle: createControllerService.controllerServiceBundle,
|
component: {
|
||||||
type: createControllerService.controllerServiceType
|
bundle: createControllerService.controllerServiceBundle,
|
||||||
|
type: createControllerService.controllerServiceType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
}
|
||||||
|
return EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||||
@ -94,7 +85,7 @@ export class ControllerServiceService {
|
|||||||
|
|
||||||
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
||||||
return this.httpClient.put(
|
return this.httpClient.put(
|
||||||
this.stripProtocol(configureControllerService.uri),
|
this.nifiCommon.stripProtocol(configureControllerService.uri),
|
||||||
configureControllerService.payload
|
configureControllerService.payload
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -102,6 +93,6 @@ export class ControllerServiceService {
|
|||||||
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
||||||
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
||||||
const revision: any = this.client.getRevision(entity);
|
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,
|
UpdateComponentRequest,
|
||||||
UploadProcessGroupRequest
|
UploadProcessGroupRequest
|
||||||
} from '../state/flow';
|
} from '../state/flow';
|
||||||
import { ComponentType } from '../../../state/shared';
|
import { ComponentType, PropertyDescriptorRetriever } from '../../../state/shared';
|
||||||
import { Client } from '../../../service/client.service';
|
import { Client } from '../../../service/client.service';
|
||||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class FlowService {
|
export class FlowService implements PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
private static readonly API: string = '../nifi-api';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -53,19 +53,6 @@ export class FlowService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
getFlow(processGroupId = 'root'): Observable<any> {
|
||||||
// TODO - support uiOnly... this would mean that we need to load the entire resource prior to editing
|
// 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}`);
|
return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}`);
|
||||||
@ -212,13 +199,13 @@ export class FlowService {
|
|||||||
|
|
||||||
updateComponent(updateComponent: UpdateComponentRequest): Observable<any> {
|
updateComponent(updateComponent: UpdateComponentRequest): Observable<any> {
|
||||||
// return throwError('API Error');
|
// 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> {
|
deleteComponent(deleteComponent: DeleteComponentRequest): Observable<any> {
|
||||||
// return throwError('API Error');
|
// return throwError('API Error');
|
||||||
const revision: any = this.client.getRevision(deleteComponent.entity);
|
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> {
|
createSnippet(snippet: Snippet): Observable<any> {
|
||||||
@ -250,7 +237,7 @@ export class FlowService {
|
|||||||
disconnectedNodeAcknowledged: false,
|
disconnectedNodeAcknowledged: false,
|
||||||
state: 'RUN_ONCE'
|
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> {
|
startComponent(request: StartComponentRequest): Observable<any> {
|
||||||
@ -259,7 +246,7 @@ export class FlowService {
|
|||||||
disconnectedNodeAcknowledged: false,
|
disconnectedNodeAcknowledged: false,
|
||||||
state: request.type === ComponentType.RemoteProcessGroup ? 'TRANSMITTING' : 'RUNNING'
|
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> {
|
stopComponent(request: StopComponentRequest): Observable<any> {
|
||||||
@ -268,7 +255,7 @@ export class FlowService {
|
|||||||
disconnectedNodeAcknowledged: false,
|
disconnectedNodeAcknowledged: false,
|
||||||
state: 'STOPPED'
|
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> {
|
startProcessGroup(request: StartProcessGroupRequest): Observable<any> {
|
||||||
|
@ -30,19 +30,6 @@ export class ParameterService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
getParameterContext(id: string, includeInheritedParameters: boolean): Observable<any> {
|
||||||
return this.httpClient.get(`${ParameterService.API}/parameter-contexts/${id}`, {
|
return this.httpClient.get(`${ParameterService.API}/parameter-contexts/${id}`, {
|
||||||
params: {
|
params: {
|
||||||
@ -59,10 +46,10 @@ export class ParameterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pollParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
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> {
|
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
|
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> {
|
submitEmptyQueueRequest(emptyQueueRequest: SubmitEmptyQueueRequest): Observable<any> {
|
||||||
return this.httpClient.post(
|
return this.httpClient.post(
|
||||||
`${QueueService.API}/flowfile-queues/${emptyQueueRequest.connectionId}/drop-requests`,
|
`${QueueService.API}/flowfile-queues/${emptyQueueRequest.connectionId}/drop-requests`,
|
||||||
@ -58,10 +45,10 @@ export class QueueService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pollEmptyQueueRequest(dropRequest: DropRequest): Observable<any> {
|
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> {
|
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 {
|
import {
|
||||||
ConfigureControllerServiceRequest,
|
ConfigureControllerServiceRequest,
|
||||||
ConfigureControllerServiceSuccess,
|
ConfigureControllerServiceSuccess,
|
||||||
CreateControllerServiceRequest,
|
|
||||||
CreateControllerServiceSuccess,
|
CreateControllerServiceSuccess,
|
||||||
DeleteControllerServiceRequest,
|
DeleteControllerServiceRequest,
|
||||||
DeleteControllerServiceSuccess,
|
DeleteControllerServiceSuccess,
|
||||||
@ -28,6 +27,7 @@ import {
|
|||||||
SelectControllerServiceRequest
|
SelectControllerServiceRequest
|
||||||
} from './index';
|
} from './index';
|
||||||
import {
|
import {
|
||||||
|
CreateControllerServiceRequest,
|
||||||
DisableControllerServiceDialogRequest,
|
DisableControllerServiceDialogRequest,
|
||||||
EditControllerServiceDialogRequest,
|
EditControllerServiceDialogRequest,
|
||||||
SetEnableControllerServiceDialogRequest
|
SetEnableControllerServiceDialogRequest
|
||||||
|
@ -18,20 +18,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||||
import * as ControllerServicesActions from './controller-services.actions';
|
import * as ControllerServicesActions from './controller-services.actions';
|
||||||
import {
|
import { catchError, combineLatest, filter, from, map, NEVER, of, switchMap, take, takeUntil, tap } from 'rxjs';
|
||||||
catchError,
|
|
||||||
combineLatest,
|
|
||||||
filter,
|
|
||||||
from,
|
|
||||||
map,
|
|
||||||
NEVER,
|
|
||||||
Observable,
|
|
||||||
of,
|
|
||||||
switchMap,
|
|
||||||
take,
|
|
||||||
takeUntil,
|
|
||||||
tap
|
|
||||||
} from 'rxjs';
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { NiFiState } from '../../../../state';
|
import { NiFiState } from '../../../../state';
|
||||||
@ -45,17 +32,10 @@ import {
|
|||||||
ControllerServiceReferencingComponent,
|
ControllerServiceReferencingComponent,
|
||||||
EditParameterRequest,
|
EditParameterRequest,
|
||||||
EditParameterResponse,
|
EditParameterResponse,
|
||||||
InlineServiceCreationRequest,
|
|
||||||
InlineServiceCreationResponse,
|
|
||||||
NewPropertyDialogRequest,
|
|
||||||
NewPropertyDialogResponse,
|
|
||||||
Parameter,
|
Parameter,
|
||||||
ParameterEntity,
|
ParameterEntity,
|
||||||
Property,
|
|
||||||
PropertyDescriptor,
|
|
||||||
UpdateControllerServiceRequest
|
UpdateControllerServiceRequest
|
||||||
} from '../../../../state/shared';
|
} from '../../../../state/shared';
|
||||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||||
import { selectCurrentProcessGroupId, selectSaving } from './controller-services.selectors';
|
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 { ParameterService } from '../../service/parameter.service';
|
||||||
import { EnableControllerService } from '../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component';
|
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 { DisableControllerService } from '../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ControllerServicesEffects {
|
export class ControllerServicesEffects {
|
||||||
@ -80,7 +61,8 @@ export class ControllerServicesEffects {
|
|||||||
private parameterService: ParameterService,
|
private parameterService: ParameterService,
|
||||||
private extensionTypesService: ExtensionTypesService,
|
private extensionTypesService: ExtensionTypesService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadControllerServices$ = createEffect(() =>
|
loadControllerServices$ = createEffect(() =>
|
||||||
@ -225,36 +207,8 @@ export class ControllerServicesEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(request.id, this.controllerServiceService);
|
||||||
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
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goTo = (commands: string[], destination: string): void => {
|
const goTo = (commands: string[], destination: string): void => {
|
||||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||||
@ -393,85 +347,21 @@ export class ControllerServicesEffects {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
serviceRequest: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
request.id,
|
||||||
const descriptor: PropertyDescriptor = serviceRequest.descriptor;
|
this.controllerServiceService,
|
||||||
|
this.controllerServiceService,
|
||||||
// fetch all services that implement the requested service api
|
processGroupId,
|
||||||
return this.extensionTypesService
|
(createResponse) =>
|
||||||
.getImplementingControllerServiceTypes(
|
this.store.dispatch(
|
||||||
// @ts-ignore
|
ControllerServicesActions.inlineCreateControllerServiceSuccess({
|
||||||
descriptor.identifiesControllerService,
|
response: {
|
||||||
descriptor.identifiesControllerServiceBundle
|
controllerService: createResponse
|
||||||
)
|
}
|
||||||
.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.editControllerService
|
editDialogReference.componentInstance.editControllerService
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||||
|
@ -31,13 +31,6 @@ export interface LoadControllerServicesResponse {
|
|||||||
loadedTimestamp: string;
|
loadedTimestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateControllerServiceRequest {
|
|
||||||
processGroupId: string;
|
|
||||||
controllerServiceType: string;
|
|
||||||
controllerServiceBundle: Bundle;
|
|
||||||
revision: Revision;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreateControllerServiceSuccess {
|
export interface CreateControllerServiceSuccess {
|
||||||
controllerService: ControllerServiceEntity;
|
controllerService: ControllerServiceEntity;
|
||||||
}
|
}
|
||||||
|
@ -69,14 +69,8 @@ import {
|
|||||||
ComponentType,
|
ComponentType,
|
||||||
EditParameterRequest,
|
EditParameterRequest,
|
||||||
EditParameterResponse,
|
EditParameterResponse,
|
||||||
InlineServiceCreationRequest,
|
|
||||||
InlineServiceCreationResponse,
|
|
||||||
NewPropertyDialogRequest,
|
|
||||||
NewPropertyDialogResponse,
|
|
||||||
Parameter,
|
Parameter,
|
||||||
ParameterEntity,
|
ParameterEntity
|
||||||
Property,
|
|
||||||
PropertyDescriptor
|
|
||||||
} from '../../../../state/shared';
|
} from '../../../../state/shared';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Client } from '../../../../service/client.service';
|
import { Client } from '../../../../service/client.service';
|
||||||
@ -86,7 +80,6 @@ import { selectProcessorTypes } from '../../../../state/extension-types/extensio
|
|||||||
import { NiFiState } from '../../../../state';
|
import { NiFiState } from '../../../../state';
|
||||||
import { CreateProcessor } from '../../ui/canvas/items/processor/create-processor/create-processor.component';
|
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 { 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 { BirdseyeView } from '../../service/birdseye-view.service';
|
||||||
import { CreateProcessGroup } from '../../ui/canvas/items/process-group/create-process-group/create-process-group.component';
|
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';
|
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 { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component';
|
||||||
import { GroupComponents } from '../../ui/canvas/items/process-group/group-components/group-components.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 { 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 { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||||
import { ControllerServiceService } from '../../service/controller-service.service';
|
import { ControllerServiceService } from '../../service/controller-service.service';
|
||||||
import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component';
|
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 { EditParameterDialog } from '../../../../ui/common/edit-parameter-dialog/edit-parameter-dialog.component';
|
||||||
import { selectParameterSaving } from '../parameter/parameter.selectors';
|
import { selectParameterSaving } from '../parameter/parameter.selectors';
|
||||||
import { ParameterService } from '../../service/parameter.service';
|
import { ParameterService } from '../../service/parameter.service';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FlowEffects {
|
export class FlowEffects {
|
||||||
@ -117,7 +110,8 @@ export class FlowEffects {
|
|||||||
private birdseyeView: BirdseyeView,
|
private birdseyeView: BirdseyeView,
|
||||||
private connectionManager: ConnectionManager,
|
private connectionManager: ConnectionManager,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private dialog: MatDialog
|
private dialog: MatDialog,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
reloadFlow$ = createEffect(() =>
|
reloadFlow$ = createEffect(() =>
|
||||||
@ -852,36 +846,8 @@ export class FlowEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(processorId, this.flowService);
|
||||||
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
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goTo = (commands: string[], destination: string): void => {
|
const goTo = (commands: string[], destination: string): void => {
|
||||||
if (editDialogReference.componentInstance.editProcessorForm.dirty) {
|
if (editDialogReference.componentInstance.editProcessorForm.dirty) {
|
||||||
@ -1013,74 +979,13 @@ export class FlowEffects {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
serviceRequest: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
processorId,
|
||||||
const descriptor: PropertyDescriptor = serviceRequest.descriptor;
|
this.controllerServiceService,
|
||||||
|
this.flowService,
|
||||||
// fetch all services that implement the requested service api
|
processGroupId
|
||||||
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.editProcessor
|
editDialogReference.componentInstance.editProcessor
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||||
@ -2331,7 +2236,7 @@ export class FlowEffects {
|
|||||||
return from(this.flowService.getProcessGroup(request.id)).pipe(
|
return from(this.flowService.getProcessGroup(request.id)).pipe(
|
||||||
map((response) =>
|
map((response) =>
|
||||||
FlowActions.loadChildProcessGroupSuccess({
|
FlowActions.loadChildProcessGroupSuccess({
|
||||||
response: response.component
|
response
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||||
|
@ -326,10 +326,7 @@ export const flowReducer = createReducer(
|
|||||||
if (collection) {
|
if (collection) {
|
||||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||||
if (componentIndex > -1) {
|
if (componentIndex > -1) {
|
||||||
collection[componentIndex] = {
|
collection[componentIndex] = response.component;
|
||||||
...collection[componentIndex],
|
|
||||||
...response.component
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,10 +340,7 @@ export const flowReducer = createReducer(
|
|||||||
if (collection) {
|
if (collection) {
|
||||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||||
if (componentIndex > -1) {
|
if (componentIndex > -1) {
|
||||||
collection[componentIndex] = {
|
collection[componentIndex] = response.component;
|
||||||
...collection[componentIndex],
|
|
||||||
...response.component
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,10 +355,7 @@ export const flowReducer = createReducer(
|
|||||||
if (collection) {
|
if (collection) {
|
||||||
const componentIndex: number = collection.findIndex((f: any) => response.id === f.id);
|
const componentIndex: number = collection.findIndex((f: any) => response.id === f.id);
|
||||||
if (componentIndex > -1) {
|
if (componentIndex > -1) {
|
||||||
collection[componentIndex] = {
|
collection[componentIndex] = response;
|
||||||
...collection[componentIndex],
|
|
||||||
...response.component
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ import { provideMockStore } from '@ngrx/store/testing';
|
|||||||
import { initialState } from '../../state/controller-services/controller-services.reducer';
|
import { initialState } from '../../state/controller-services/controller-services.reducer';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { ControllerServicesModule } from './controller-services.module';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
|
||||||
describe('ControllerServices', () => {
|
describe('ControllerServices', () => {
|
||||||
let component: ControllerServices;
|
let component: ControllerServices;
|
||||||
@ -37,7 +39,7 @@ describe('ControllerServices', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ControllerServices],
|
declarations: [ControllerServices],
|
||||||
imports: [RouterTestingModule, MockNavigation],
|
imports: [RouterTestingModule, MockNavigation, ControllerServicesModule, HttpClientTestingModule],
|
||||||
providers: [
|
providers: [
|
||||||
provideMockStore({
|
provideMockStore({
|
||||||
initialState
|
initialState
|
||||||
|
@ -37,19 +37,6 @@ export class ParameterContextService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
getParameterContexts(): Observable<any> {
|
||||||
return this.httpClient.get(`${ParameterContextService.API}/flow/parameter-contexts`);
|
return this.httpClient.get(`${ParameterContextService.API}/flow/parameter-contexts`);
|
||||||
}
|
}
|
||||||
@ -77,11 +64,11 @@ export class ParameterContextService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pollParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable<any> {
|
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> {
|
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> {
|
deleteParameterContext(deleteParameterContext: DeleteParameterContextRequest): Observable<any> {
|
||||||
|
@ -28,7 +28,7 @@ import { RouterLink } from '@angular/router';
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [ParameterContextListing, ParameterContextTable],
|
declarations: [ParameterContextListing, ParameterContextTable],
|
||||||
exports: [ParameterContextListing],
|
exports: [ParameterContextListing, ParameterContextTable],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
NgxSkeletonLoaderModule,
|
NgxSkeletonLoaderModule,
|
||||||
|
@ -31,12 +31,13 @@ import { CurrentUser } from '../../../../../state/current-user';
|
|||||||
export class ParameterContextTable {
|
export class ParameterContextTable {
|
||||||
@Input() initialSortColumn: 'name' | 'provider' | 'description' = 'name';
|
@Input() initialSortColumn: 'name' | 'provider' | 'description' = 'name';
|
||||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||||
|
activeSort: Sort = {
|
||||||
|
active: this.initialSortColumn,
|
||||||
|
direction: this.initialSortDirection
|
||||||
|
};
|
||||||
|
|
||||||
@Input() set parameterContexts(parameterContextEntities: ParameterContextEntity[]) {
|
@Input() set parameterContexts(parameterContextEntities: ParameterContextEntity[]) {
|
||||||
this.dataSource.data = this.sortEntities(parameterContextEntities, {
|
this.dataSource.data = this.sortEntities(parameterContextEntities, this.activeSort);
|
||||||
active: this.initialSortColumn,
|
|
||||||
direction: this.initialSortDirection
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() selectedParameterContextId!: string;
|
@Input() selectedParameterContextId!: string;
|
||||||
@ -109,6 +110,7 @@ export class ParameterContextTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortData(sort: Sort) {
|
sortData(sort: Sort) {
|
||||||
|
this.activeSort = sort;
|
||||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||||
import { ProvenanceRequest } from '../state/provenance-event-listing';
|
import { ProvenanceRequest } from '../state/provenance-event-listing';
|
||||||
@ -31,19 +31,6 @@ export class ProvenanceService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
getSearchOptions(): Observable<any> {
|
||||||
return this.httpClient.get(`${ProvenanceService.API}/provenance/search-options`);
|
return this.httpClient.get(`${ProvenanceService.API}/provenance/search-options`);
|
||||||
}
|
}
|
||||||
|
@ -30,25 +30,12 @@ export class QueueService {
|
|||||||
private nifiCommon: NiFiCommon
|
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> {
|
getConnection(connectionId: string): Observable<any> {
|
||||||
return this.httpClient.get(`${QueueService.API}/connections/${connectionId}`);
|
return this.httpClient.get(`${QueueService.API}/connections/${connectionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFlowFile(flowfileSummary: FlowFileSummary): Observable<any> {
|
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> {
|
submitQueueListingRequest(queueListingRequest: SubmitQueueListingRequest): Observable<any> {
|
||||||
@ -59,15 +46,15 @@ export class QueueService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pollQueueListingRequest(listingRequest: ListingRequest): Observable<any> {
|
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> {
|
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 {
|
downloadContent(flowfileSummary: FlowFileSummary): void {
|
||||||
let dataUri: string = `${this.stripProtocol(flowfileSummary.uri)}/content`;
|
let dataUri: string = `${this.nifiCommon.stripProtocol(flowfileSummary.uri)}/content`;
|
||||||
|
|
||||||
const queryParameters: any = {};
|
const queryParameters: any = {};
|
||||||
|
|
||||||
@ -83,7 +70,7 @@ export class QueueService {
|
|||||||
|
|
||||||
viewContent(flowfileSummary: FlowFileSummary, contentViewerUrl: string): void {
|
viewContent(flowfileSummary: FlowFileSummary, contentViewerUrl: string): void {
|
||||||
// build the uri to the data
|
// 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 = {};
|
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 { RegistryClientsEffects } from '../state/registry-clients/registry-clients.effects';
|
||||||
import { FlowAnalysisRulesEffects } from '../state/flow-analysis-rules/flow-analysis-rules.effects';
|
import { FlowAnalysisRulesEffects } from '../state/flow-analysis-rules/flow-analysis-rules.effects';
|
||||||
import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
||||||
|
import { ParameterProvidersEffects } from '../state/parameter-providers/parameter-providers.effects';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [Settings],
|
declarations: [Settings],
|
||||||
@ -54,7 +55,8 @@ import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
|||||||
ManagementControllerServicesEffects,
|
ManagementControllerServicesEffects,
|
||||||
ReportingTasksEffects,
|
ReportingTasksEffects,
|
||||||
FlowAnalysisRulesEffects,
|
FlowAnalysisRulesEffects,
|
||||||
RegistryClientsEffects
|
RegistryClientsEffects,
|
||||||
|
ParameterProvidersEffects
|
||||||
),
|
),
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
Navigation
|
Navigation
|
||||||
|
@ -27,24 +27,12 @@ import {
|
|||||||
EnableFlowAnalysisRuleRequest,
|
EnableFlowAnalysisRuleRequest,
|
||||||
FlowAnalysisRuleEntity
|
FlowAnalysisRuleEntity
|
||||||
} from '../state/flow-analysis-rules';
|
} from '../state/flow-analysis-rules';
|
||||||
|
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class FlowAnalysisRuleService {
|
export class FlowAnalysisRuleService implements PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -68,7 +56,7 @@ export class FlowAnalysisRuleService {
|
|||||||
deleteFlowAnalysisRule(deleteFlowAnalysisRule: DeleteFlowAnalysisRuleRequest): Observable<any> {
|
deleteFlowAnalysisRule(deleteFlowAnalysisRule: DeleteFlowAnalysisRuleRequest): Observable<any> {
|
||||||
const entity: FlowAnalysisRuleEntity = deleteFlowAnalysisRule.flowAnalysisRule;
|
const entity: FlowAnalysisRuleEntity = deleteFlowAnalysisRule.flowAnalysisRule;
|
||||||
const revision: any = this.client.getRevision(entity);
|
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> {
|
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||||
@ -83,14 +71,14 @@ export class FlowAnalysisRuleService {
|
|||||||
|
|
||||||
updateFlowAnalysisRule(configureFlowAnalysisRule: ConfigureFlowAnalysisRuleRequest): Observable<any> {
|
updateFlowAnalysisRule(configureFlowAnalysisRule: ConfigureFlowAnalysisRuleRequest): Observable<any> {
|
||||||
return this.httpClient.put(
|
return this.httpClient.put(
|
||||||
this.stripProtocol(configureFlowAnalysisRule.uri),
|
this.nifiCommon.stripProtocol(configureFlowAnalysisRule.uri),
|
||||||
configureFlowAnalysisRule.payload
|
configureFlowAnalysisRule.payload
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnable(flowAnalysisRule: EnableFlowAnalysisRuleRequest, enabled: boolean): Observable<any> {
|
setEnable(flowAnalysisRule: EnableFlowAnalysisRuleRequest, enabled: boolean): Observable<any> {
|
||||||
const entity: FlowAnalysisRuleEntity = flowAnalysisRule.flowAnalysisRule;
|
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),
|
revision: this.client.getRevision(entity),
|
||||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||||
uiOnly: true
|
uiOnly: true
|
||||||
|
@ -16,34 +16,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import {
|
import {
|
||||||
ConfigureControllerServiceRequest,
|
ConfigureControllerServiceRequest,
|
||||||
CreateControllerServiceRequest,
|
|
||||||
DeleteControllerServiceRequest
|
DeleteControllerServiceRequest
|
||||||
} from '../state/management-controller-services';
|
} from '../state/management-controller-services';
|
||||||
import { Client } from '../../../service/client.service';
|
import { Client } from '../../../service/client.service';
|
||||||
import { NiFiCommon } from '../../../service/nifi-common.service';
|
import { NiFiCommon } from '../../../service/nifi-common.service';
|
||||||
import { ControllerServiceEntity } from '../../../state/shared';
|
import {
|
||||||
|
ControllerServiceCreator,
|
||||||
|
ControllerServiceEntity,
|
||||||
|
CreateControllerServiceRequest,
|
||||||
|
PropertyDescriptorRetriever
|
||||||
|
} from '../../../state/shared';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ManagementControllerServiceService {
|
export class ManagementControllerServiceService implements ControllerServiceCreator, PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -79,7 +70,7 @@ export class ManagementControllerServiceService {
|
|||||||
|
|
||||||
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
updateControllerService(configureControllerService: ConfigureControllerServiceRequest): Observable<any> {
|
||||||
return this.httpClient.put(
|
return this.httpClient.put(
|
||||||
this.stripProtocol(configureControllerService.uri),
|
this.nifiCommon.stripProtocol(configureControllerService.uri),
|
||||||
configureControllerService.payload
|
configureControllerService.payload
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -87,6 +78,6 @@ export class ManagementControllerServiceService {
|
|||||||
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable<any> {
|
||||||
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
const entity: ControllerServiceEntity = deleteControllerService.controllerService;
|
||||||
const revision: any = this.client.getRevision(entity);
|
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,
|
EditRegistryClientRequest,
|
||||||
RegistryClientEntity
|
RegistryClientEntity
|
||||||
} from '../state/registry-clients';
|
} from '../state/registry-clients';
|
||||||
|
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class RegistryClientService {
|
export class RegistryClientService implements PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -69,12 +57,12 @@ export class RegistryClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateRegistryClient(request: EditRegistryClientRequest): Observable<any> {
|
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> {
|
deleteRegistryClient(deleteRegistryClient: DeleteRegistryClientRequest): Observable<any> {
|
||||||
const entity: RegistryClientEntity = deleteRegistryClient.registryClient;
|
const entity: RegistryClientEntity = deleteRegistryClient.registryClient;
|
||||||
const revision: any = this.client.getRevision(entity);
|
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,
|
StartReportingTaskRequest,
|
||||||
StopReportingTaskRequest
|
StopReportingTaskRequest
|
||||||
} from '../state/reporting-tasks';
|
} from '../state/reporting-tasks';
|
||||||
|
import { PropertyDescriptorRetriever } from '../../../state/shared';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ReportingTaskService {
|
export class ReportingTaskService implements PropertyDescriptorRetriever {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -69,7 +57,7 @@ export class ReportingTaskService {
|
|||||||
deleteReportingTask(deleteReportingTask: DeleteReportingTaskRequest): Observable<any> {
|
deleteReportingTask(deleteReportingTask: DeleteReportingTaskRequest): Observable<any> {
|
||||||
const entity: ReportingTaskEntity = deleteReportingTask.reportingTask;
|
const entity: ReportingTaskEntity = deleteReportingTask.reportingTask;
|
||||||
const revision: any = this.client.getRevision(entity);
|
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> {
|
startReportingTask(startReportingTask: StartReportingTaskRequest): Observable<any> {
|
||||||
@ -79,7 +67,7 @@ export class ReportingTaskService {
|
|||||||
revision,
|
revision,
|
||||||
state: 'RUNNING'
|
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> {
|
stopReportingTask(stopReportingTask: StopReportingTaskRequest): Observable<any> {
|
||||||
@ -89,7 +77,7 @@ export class ReportingTaskService {
|
|||||||
revision,
|
revision,
|
||||||
state: 'STOPPED'
|
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> {
|
getPropertyDescriptor(id: string, propertyName: string, sensitive: boolean): Observable<any> {
|
||||||
@ -103,6 +91,9 @@ export class ReportingTaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateReportingTask(configureReportingTask: ConfigureReportingTaskRequest): Observable<any> {
|
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 { Injectable } from '@angular/core';
|
||||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||||
import * as FlowAnalysisRuleActions from './flow-analysis-rules.actions';
|
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 { MatDialog } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { NiFiState } from '../../../../state';
|
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 { CreateFlowAnalysisRule } from '../../ui/flow-analysis-rules/create-flow-analysis-rule/create-flow-analysis-rule.component';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { selectSaving } from '../management-controller-services/management-controller-services.selectors';
|
import { selectSaving } from '../management-controller-services/management-controller-services.selectors';
|
||||||
import {
|
import { UpdateControllerServiceRequest } from '../../../../state/shared';
|
||||||
InlineServiceCreationRequest,
|
|
||||||
InlineServiceCreationResponse,
|
|
||||||
NewPropertyDialogRequest,
|
|
||||||
NewPropertyDialogResponse,
|
|
||||||
Property,
|
|
||||||
PropertyDescriptor,
|
|
||||||
UpdateControllerServiceRequest
|
|
||||||
} from '../../../../state/shared';
|
|
||||||
import { EditFlowAnalysisRule } from '../../ui/flow-analysis-rules/edit-flow-analysis-rule/edit-flow-analysis-rule.component';
|
import { EditFlowAnalysisRule } from '../../ui/flow-analysis-rules/edit-flow-analysis-rule/edit-flow-analysis-rule.component';
|
||||||
import { CreateFlowAnalysisRuleSuccess } from './index';
|
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 { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FlowAnalysisRulesEffects {
|
export class FlowAnalysisRulesEffects {
|
||||||
@ -55,7 +46,8 @@ export class FlowAnalysisRulesEffects {
|
|||||||
private extensionTypesService: ExtensionTypesService,
|
private extensionTypesService: ExtensionTypesService,
|
||||||
private flowAnalysisRuleService: FlowAnalysisRuleService,
|
private flowAnalysisRuleService: FlowAnalysisRuleService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadFlowAnalysisRule$ = createEffect(() =>
|
loadFlowAnalysisRule$ = createEffect(() =>
|
||||||
@ -225,36 +217,8 @@ export class FlowAnalysisRulesEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(request.id, this.flowAnalysisRuleService);
|
||||||
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
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goTo = (commands: string[], destination: string): void => {
|
const goTo = (commands: string[], destination: string): void => {
|
||||||
if (editDialogReference.componentInstance.editFlowAnalysisRuleForm.dirty) {
|
if (editDialogReference.componentInstance.editFlowAnalysisRuleForm.dirty) {
|
||||||
@ -285,73 +249,12 @@ export class FlowAnalysisRulesEffects {
|
|||||||
goTo(commands, 'Controller Service');
|
goTo(commands, 'Controller Service');
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
request: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
request.id,
|
||||||
const descriptor: PropertyDescriptor = request.descriptor;
|
this.managementControllerServiceService,
|
||||||
|
this.flowAnalysisRuleService
|
||||||
// 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.editFlowAnalysisRule
|
editDialogReference.componentInstance.editFlowAnalysisRule
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||||
|
@ -29,6 +29,8 @@ import { registryClientsFeatureKey, RegistryClientsState } from './registry-clie
|
|||||||
import { registryClientsReducer } from './registry-clients/registry-clients.reducer';
|
import { registryClientsReducer } from './registry-clients/registry-clients.reducer';
|
||||||
import { flowAnalysisRulesFeatureKey, FlowAnalysisRulesState } from './flow-analysis-rules';
|
import { flowAnalysisRulesFeatureKey, FlowAnalysisRulesState } from './flow-analysis-rules';
|
||||||
import { flowAnalysisRulesReducer } from './flow-analysis-rules/flow-analysis-rules.reducer';
|
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';
|
export const settingsFeatureKey = 'settings';
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ export interface SettingsState {
|
|||||||
[reportingTasksFeatureKey]: ReportingTasksState;
|
[reportingTasksFeatureKey]: ReportingTasksState;
|
||||||
[flowAnalysisRulesFeatureKey]: FlowAnalysisRulesState;
|
[flowAnalysisRulesFeatureKey]: FlowAnalysisRulesState;
|
||||||
[registryClientsFeatureKey]: RegistryClientsState;
|
[registryClientsFeatureKey]: RegistryClientsState;
|
||||||
|
[parameterProvidersFeatureKey]: ParameterProvidersState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reducers(state: SettingsState | undefined, action: Action) {
|
export function reducers(state: SettingsState | undefined, action: Action) {
|
||||||
@ -46,7 +49,8 @@ export function reducers(state: SettingsState | undefined, action: Action) {
|
|||||||
[managementControllerServicesFeatureKey]: managementControllerServicesReducer,
|
[managementControllerServicesFeatureKey]: managementControllerServicesReducer,
|
||||||
[reportingTasksFeatureKey]: reportingTasksReducer,
|
[reportingTasksFeatureKey]: reportingTasksReducer,
|
||||||
[flowAnalysisRulesFeatureKey]: flowAnalysisRulesReducer,
|
[flowAnalysisRulesFeatureKey]: flowAnalysisRulesReducer,
|
||||||
[registryClientsFeatureKey]: registryClientsReducer
|
[registryClientsFeatureKey]: registryClientsReducer,
|
||||||
|
[parameterProvidersFeatureKey]: parameterProvidersReducer
|
||||||
})(state, action);
|
})(state, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,6 @@ export interface LoadManagementControllerServicesResponse {
|
|||||||
loadedTimestamp: string;
|
loadedTimestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateControllerServiceRequest {
|
|
||||||
controllerServiceType: string;
|
|
||||||
controllerServiceBundle: Bundle;
|
|
||||||
revision: Revision;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CreateControllerServiceSuccess {
|
export interface CreateControllerServiceSuccess {
|
||||||
controllerService: ControllerServiceEntity;
|
controllerService: ControllerServiceEntity;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import { createAction, props } from '@ngrx/store';
|
|||||||
import {
|
import {
|
||||||
ConfigureControllerServiceRequest,
|
ConfigureControllerServiceRequest,
|
||||||
ConfigureControllerServiceSuccess,
|
ConfigureControllerServiceSuccess,
|
||||||
CreateControllerServiceRequest,
|
|
||||||
CreateControllerServiceSuccess,
|
CreateControllerServiceSuccess,
|
||||||
DeleteControllerServiceRequest,
|
DeleteControllerServiceRequest,
|
||||||
DeleteControllerServiceSuccess,
|
DeleteControllerServiceSuccess,
|
||||||
@ -27,6 +26,7 @@ import {
|
|||||||
SelectControllerServiceRequest
|
SelectControllerServiceRequest
|
||||||
} from './index';
|
} from './index';
|
||||||
import {
|
import {
|
||||||
|
CreateControllerServiceRequest,
|
||||||
DisableControllerServiceDialogRequest,
|
DisableControllerServiceDialogRequest,
|
||||||
EditControllerServiceDialogRequest,
|
EditControllerServiceDialogRequest,
|
||||||
SetEnableControllerServiceDialogRequest
|
SetEnableControllerServiceDialogRequest
|
||||||
|
@ -33,18 +33,15 @@ import {
|
|||||||
ControllerServiceReferencingComponent,
|
ControllerServiceReferencingComponent,
|
||||||
InlineServiceCreationRequest,
|
InlineServiceCreationRequest,
|
||||||
InlineServiceCreationResponse,
|
InlineServiceCreationResponse,
|
||||||
NewPropertyDialogRequest,
|
|
||||||
NewPropertyDialogResponse,
|
|
||||||
Property,
|
|
||||||
PropertyDescriptor,
|
PropertyDescriptor,
|
||||||
UpdateControllerServiceRequest
|
UpdateControllerServiceRequest
|
||||||
} from '../../../../state/shared';
|
} from '../../../../state/shared';
|
||||||
import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component';
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
import { ExtensionTypesService } from '../../../../service/extension-types.service';
|
||||||
import { selectSaving } from './management-controller-services.selectors';
|
import { selectSaving } from './management-controller-services.selectors';
|
||||||
import { EnableControllerService } from '../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component';
|
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 { DisableControllerService } from '../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ManagementControllerServicesEffects {
|
export class ManagementControllerServicesEffects {
|
||||||
@ -55,7 +52,8 @@ export class ManagementControllerServicesEffects {
|
|||||||
private managementControllerServiceService: ManagementControllerServiceService,
|
private managementControllerServiceService: ManagementControllerServiceService,
|
||||||
private extensionTypesService: ExtensionTypesService,
|
private extensionTypesService: ExtensionTypesService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadManagementControllerServices$ = createEffect(() =>
|
loadManagementControllerServices$ = createEffect(() =>
|
||||||
@ -193,36 +191,11 @@ export class ManagementControllerServicesEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(
|
||||||
allowsSensitive: boolean
|
request.id,
|
||||||
): Observable<Property> => {
|
this.managementControllerServiceService
|
||||||
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
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const goTo = (commands: string[], destination: string): void => {
|
const goTo = (commands: string[], destination: string): void => {
|
||||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||||
@ -260,84 +233,21 @@ export class ManagementControllerServicesEffects {
|
|||||||
goTo(route, component.referenceType);
|
goTo(route, component.referenceType);
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
request: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
request.id,
|
||||||
const descriptor: PropertyDescriptor = request.descriptor;
|
this.managementControllerServiceService,
|
||||||
|
this.managementControllerServiceService,
|
||||||
// fetch all services that implement the requested service api
|
null,
|
||||||
return this.extensionTypesService
|
(createResponse) =>
|
||||||
.getImplementingControllerServiceTypes(
|
this.store.dispatch(
|
||||||
// @ts-ignore
|
ManagementControllerServicesActions.inlineCreateControllerServiceSuccess({
|
||||||
descriptor.identifiesControllerService,
|
response: {
|
||||||
descriptor.identifiesControllerServiceBundle
|
controllerService: createResponse
|
||||||
)
|
}
|
||||||
.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.editControllerService
|
editDialogReference.componentInstance.editControllerService
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.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 { Injectable } from '@angular/core';
|
||||||
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
|
||||||
import * as RegistryClientsActions from './registry-clients.actions';
|
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 { MatDialog } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { NiFiState } from '../../../../state';
|
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 { CreateRegistryClient } from '../../ui/registry-clients/create-registry-client/create-registry-client.component';
|
||||||
import { selectSaving } from './registry-clients.selectors';
|
import { selectSaving } from './registry-clients.selectors';
|
||||||
import { EditRegistryClient } from '../../ui/registry-clients/edit-registry-client/edit-registry-client.component';
|
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 { 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 { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
||||||
import { Client } from '../../../../service/client.service';
|
import { Client } from '../../../../service/client.service';
|
||||||
import { EditRegistryClientRequest } from './index';
|
import { EditRegistryClientRequest } from './index';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RegistryClientsEffects {
|
export class RegistryClientsEffects {
|
||||||
@ -54,7 +45,8 @@ export class RegistryClientsEffects {
|
|||||||
private extensionTypesService: ExtensionTypesService,
|
private extensionTypesService: ExtensionTypesService,
|
||||||
private managementControllerServiceService: ManagementControllerServiceService,
|
private managementControllerServiceService: ManagementControllerServiceService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadRegistryClients$ = createEffect(() =>
|
loadRegistryClients$ = createEffect(() =>
|
||||||
@ -181,40 +173,8 @@ export class RegistryClientsEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(registryClientId, this.registryClientService);
|
||||||
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.goToService = (serviceId: string) => {
|
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||||
@ -242,77 +202,12 @@ export class RegistryClientsEffects {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
request: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
registryClientId,
|
||||||
const descriptor: PropertyDescriptor = request.descriptor;
|
this.managementControllerServiceService,
|
||||||
|
this.registryClientService
|
||||||
// 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.editRegistryClient
|
editDialogReference.componentInstance.editRegistryClient
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.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 { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component';
|
||||||
import { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
import { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
||||||
import { Client } from '../../../../service/client.service';
|
import { Client } from '../../../../service/client.service';
|
||||||
|
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReportingTasksEffects {
|
export class ReportingTasksEffects {
|
||||||
@ -55,7 +56,8 @@ export class ReportingTasksEffects {
|
|||||||
private managementControllerServiceService: ManagementControllerServiceService,
|
private managementControllerServiceService: ManagementControllerServiceService,
|
||||||
private extensionTypesService: ExtensionTypesService,
|
private extensionTypesService: ExtensionTypesService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private propertyTableHelperService: PropertyTableHelperService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
loadReportingTasks$ = createEffect(() =>
|
loadReportingTasks$ = createEffect(() =>
|
||||||
@ -225,36 +227,8 @@ export class ReportingTasksEffects {
|
|||||||
|
|
||||||
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
editDialogReference.componentInstance.saving$ = this.store.select(selectSaving);
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewProperty = (
|
editDialogReference.componentInstance.createNewProperty =
|
||||||
existingProperties: string[],
|
this.propertyTableHelperService.createNewProperty(request.id, this.reportingTaskService);
|
||||||
allowsSensitive: boolean
|
|
||||||
): Observable<Property> => {
|
|
||||||
const dialogRequest: NewPropertyDialogRequest = { existingProperties, allowsSensitive };
|
|
||||||
const newPropertyDialogReference = this.dialog.open(NewPropertyDialog, {
|
|
||||||
data: dialogRequest,
|
|
||||||
panelClass: 'small-dialog'
|
|
||||||
});
|
|
||||||
|
|
||||||
return newPropertyDialogReference.componentInstance.newProperty.pipe(
|
|
||||||
take(1),
|
|
||||||
switchMap((dialogResponse: NewPropertyDialogResponse) => {
|
|
||||||
return this.reportingTaskService
|
|
||||||
.getPropertyDescriptor(request.id, dialogResponse.name, dialogResponse.sensitive)
|
|
||||||
.pipe(
|
|
||||||
take(1),
|
|
||||||
map((response) => {
|
|
||||||
newPropertyDialogReference.close();
|
|
||||||
|
|
||||||
return {
|
|
||||||
property: dialogResponse.name,
|
|
||||||
value: null,
|
|
||||||
descriptor: response.propertyDescriptor
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const goTo = (commands: string[], destination: string): void => {
|
const goTo = (commands: string[], destination: string): void => {
|
||||||
if (editDialogReference.componentInstance.editReportingTaskForm.dirty) {
|
if (editDialogReference.componentInstance.editReportingTaskForm.dirty) {
|
||||||
@ -285,73 +259,12 @@ export class ReportingTasksEffects {
|
|||||||
goTo(commands, 'Controller Service');
|
goTo(commands, 'Controller Service');
|
||||||
};
|
};
|
||||||
|
|
||||||
editDialogReference.componentInstance.createNewService = (
|
editDialogReference.componentInstance.createNewService =
|
||||||
request: InlineServiceCreationRequest
|
this.propertyTableHelperService.createNewService(
|
||||||
): Observable<InlineServiceCreationResponse> => {
|
request.id,
|
||||||
const descriptor: PropertyDescriptor = request.descriptor;
|
this.managementControllerServiceService,
|
||||||
|
this.reportingTaskService
|
||||||
// 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.editReportingTask
|
editDialogReference.componentInstance.editReportingTask
|
||||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
.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.
|
~ 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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { ParameterProviders } from './parameter-providers.component';
|
import { ParameterProviders } from './parameter-providers.component';
|
||||||
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { initialParameterProvidersState } from '../../state/parameter-providers/parameter-providers.reducer';
|
||||||
|
|
||||||
describe('ParameterProviders', () => {
|
describe('ParameterProviders', () => {
|
||||||
let component: ParameterProviders;
|
let component: ParameterProviders;
|
||||||
@ -25,7 +27,12 @@ describe('ParameterProviders', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ParameterProviders]
|
declarations: [ParameterProviders],
|
||||||
|
providers: [
|
||||||
|
provideMockStore({
|
||||||
|
initialState: initialParameterProvidersState
|
||||||
|
})
|
||||||
|
]
|
||||||
});
|
});
|
||||||
fixture = TestBed.createComponent(ParameterProviders);
|
fixture = TestBed.createComponent(ParameterProviders);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
@ -15,11 +15,105 @@
|
|||||||
* limitations under the License.
|
* 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({
|
@Component({
|
||||||
selector: 'parameter-providers',
|
selector: 'parameter-providers',
|
||||||
templateUrl: './parameter-providers.component.html',
|
templateUrl: './parameter-providers.component.html',
|
||||||
styleUrls: ['./parameter-providers.component.scss']
|
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 { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ParameterProviders } from './parameter-providers.component';
|
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({
|
@NgModule({
|
||||||
declarations: [ParameterProviders],
|
declarations: [ParameterProviders],
|
||||||
exports: [ParameterProviders],
|
exports: [ParameterProviders],
|
||||||
imports: [CommonModule]
|
imports: [CommonModule, NgxSkeletonLoaderModule, ParameterProvidersTable]
|
||||||
})
|
})
|
||||||
export class ParameterProvidersModule {}
|
export class ParameterProvidersModule {}
|
||||||
|
@ -35,12 +35,13 @@ import { CurrentUser } from '../../../../../state/current-user';
|
|||||||
export class ReportingTaskTable {
|
export class ReportingTaskTable {
|
||||||
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' = 'name';
|
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' = 'name';
|
||||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||||
|
activeSort: Sort = {
|
||||||
|
active: this.initialSortColumn,
|
||||||
|
direction: this.initialSortDirection
|
||||||
|
};
|
||||||
|
|
||||||
@Input() set reportingTasks(reportingTaskEntities: ReportingTaskEntity[]) {
|
@Input() set reportingTasks(reportingTaskEntities: ReportingTaskEntity[]) {
|
||||||
this.dataSource.data = this.sortEntities(reportingTaskEntities, {
|
this.dataSource.data = this.sortEntities(reportingTaskEntities, this.activeSort);
|
||||||
active: this.initialSortColumn,
|
|
||||||
direction: this.initialSortDirection
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() selectedReportingTaskId!: string;
|
@Input() selectedReportingTaskId!: string;
|
||||||
@ -258,6 +259,7 @@ export class ReportingTaskTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortData(sort: Sort) {
|
sortData(sort: Sort) {
|
||||||
|
this.activeSort = sort;
|
||||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,19 +32,6 @@ import {
|
|||||||
export class UsersService {
|
export class UsersService {
|
||||||
private static readonly API: string = '../nifi-api';
|
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(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private client: Client,
|
private client: Client,
|
||||||
@ -83,7 +70,7 @@ export class UsersService {
|
|||||||
...request.userPayload
|
...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> {
|
updateUserGroup(request: UpdateUserGroupRequest): Observable<any> {
|
||||||
@ -94,16 +81,16 @@ export class UsersService {
|
|||||||
...request.userGroupPayload
|
...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> {
|
deleteUser(user: UserEntity): Observable<any> {
|
||||||
const revision: any = this.client.getRevision(user);
|
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> {
|
deleteUserGroup(userGroup: UserGroupEntity): Observable<any> {
|
||||||
const revision: any = this.client.getRevision(userGroup);
|
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
|
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> {
|
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> {
|
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
|
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> {
|
getControllerService(id: string): Observable<any> {
|
||||||
return this.httpClient.get(`${ControllerServiceStateService.API}/controller-services/${id}`);
|
return this.httpClient.get(`${ControllerServiceStateService.API}/controller-services/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnable(controllerService: ControllerServiceEntity, enabled: boolean): Observable<any> {
|
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),
|
revision: this.client.getRevision(controllerService),
|
||||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||||
uiOnly: true
|
uiOnly: true
|
||||||
@ -69,7 +56,7 @@ export class ControllerServiceStateService {
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.httpClient.put(`${this.stripProtocol(controllerService.uri)}/references`, {
|
return this.httpClient.put(`${this.nifiCommon.stripProtocol(controllerService.uri)}/references`, {
|
||||||
id: controllerService.id,
|
id: controllerService.id,
|
||||||
state: enabled ? 'ENABLED' : 'DISABLED',
|
state: enabled ? 'ENABLED' : 'DISABLED',
|
||||||
referencingComponentRevisions: referencingComponentRevisions,
|
referencingComponentRevisions: referencingComponentRevisions,
|
||||||
@ -89,7 +76,7 @@ export class ControllerServiceStateService {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.httpClient.put(`${this.stripProtocol(controllerService.uri)}/references`, {
|
return this.httpClient.put(`${this.nifiCommon.stripProtocol(controllerService.uri)}/references`, {
|
||||||
id: controllerService.id,
|
id: controllerService.id,
|
||||||
state: running ? 'RUNNING' : 'STOPPED',
|
state: running ? 'RUNNING' : 'STOPPED',
|
||||||
referencingComponentRevisions: referencingComponentRevisions,
|
referencingComponentRevisions: referencingComponentRevisions,
|
||||||
|
@ -511,4 +511,17 @@ export class NiFiCommon {
|
|||||||
public getAllPolicyTypeListing(): SelectOption[] {
|
public getAllPolicyTypeListing(): SelectOption[] {
|
||||||
return this.policyTypeListing;
|
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
|
(state: ExtensionTypesState) => state.flowAnalysisRuleTypes
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectParameterProviderTypes = createSelector(
|
||||||
|
selectExtensionTypesState,
|
||||||
|
(state: ExtensionTypesState) => state.parameterProviderTypes
|
||||||
|
);
|
||||||
|
|
||||||
export const selectTypesToIdentifyComponentRestrictions = createSelector(
|
export const selectTypesToIdentifyComponentRestrictions = createSelector(
|
||||||
selectExtensionTypesState,
|
selectExtensionTypesState,
|
||||||
(state: ExtensionTypesState) => {
|
(state: ExtensionTypesState) => {
|
||||||
|
@ -112,7 +112,7 @@ export interface EditTenantResponse {
|
|||||||
userGroup?: any;
|
userGroup?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateControllerServiceRequest {
|
export interface CreateControllerServiceDialogRequest {
|
||||||
controllerServiceTypes: DocumentedType[];
|
controllerServiceTypes: DocumentedType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +306,7 @@ export interface ParameterContextReferenceEntity {
|
|||||||
permissions: Permissions;
|
permissions: Permissions;
|
||||||
id: string;
|
id: string;
|
||||||
component?: ParameterContextReference;
|
component?: ParameterContextReference;
|
||||||
|
bulletins?: BulletinEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParameterContextReference {
|
export interface ParameterContextReference {
|
||||||
@ -508,6 +509,10 @@ export interface PropertyDescriptor {
|
|||||||
identifiesControllerServiceBundle?: Bundle;
|
identifiesControllerServiceBundle?: Bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PropertyDescriptorEntity {
|
||||||
|
propertyDescriptor: PropertyDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Property {
|
export interface Property {
|
||||||
property: string;
|
property: string;
|
||||||
value: string | null;
|
value: string | null;
|
||||||
@ -522,3 +527,18 @@ export interface InlineServiceCreationResponse {
|
|||||||
value: string;
|
value: string;
|
||||||
descriptor: PropertyDescriptor;
|
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 {
|
export class ControllerServiceTable {
|
||||||
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' | 'scope' = 'name';
|
@Input() initialSortColumn: 'name' | 'type' | 'bundle' | 'state' | 'scope' = 'name';
|
||||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||||
|
activeSort: Sort = {
|
||||||
|
active: this.initialSortColumn,
|
||||||
|
direction: this.initialSortDirection
|
||||||
|
};
|
||||||
|
|
||||||
@Input() set controllerServices(controllerServiceEntities: ControllerServiceEntity[]) {
|
@Input() set controllerServices(controllerServiceEntities: ControllerServiceEntity[]) {
|
||||||
this.dataSource.data = this.sortEntities(controllerServiceEntities, {
|
this.dataSource.data = this.sortEntities(controllerServiceEntities, this.activeSort);
|
||||||
active: this.initialSortColumn,
|
|
||||||
direction: this.initialSortDirection
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() selectedServiceId!: string;
|
@Input() selectedServiceId!: string;
|
||||||
@ -277,6 +278,7 @@ export class ControllerServiceTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortData(sort: Sort) {
|
sortData(sort: Sort) {
|
||||||
|
this.activeSort = sort;
|
||||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { CreateControllerService } from './create-controller-service.component';
|
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 { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { initialState } from '../../../../state/extension-types/extension-types.reducer';
|
import { initialState } from '../../../../state/extension-types/extension-types.reducer';
|
||||||
@ -28,7 +28,7 @@ describe('CreateControllerService', () => {
|
|||||||
let component: CreateControllerService;
|
let component: CreateControllerService;
|
||||||
let fixture: ComponentFixture<CreateControllerService>;
|
let fixture: ComponentFixture<CreateControllerService>;
|
||||||
|
|
||||||
const data: CreateControllerServiceRequest = {
|
const data: CreateControllerServiceDialogRequest = {
|
||||||
controllerServiceTypes: [
|
controllerServiceTypes: [
|
||||||
{
|
{
|
||||||
type: 'org.apache.nifi.services.azure.storage.ADLSCredentialsControllerService',
|
type: 'org.apache.nifi.services.azure.storage.ADLSCredentialsControllerService',
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
import { Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
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 { ExtensionCreation } from '../../extension-creation/extension-creation.component';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
@ -35,7 +35,7 @@ export class CreateControllerService {
|
|||||||
|
|
||||||
controllerServiceTypes: DocumentedType[];
|
controllerServiceTypes: DocumentedType[];
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) private dialogRequest: CreateControllerServiceRequest) {
|
constructor(@Inject(MAT_DIALOG_DATA) private dialogRequest: CreateControllerServiceDialogRequest) {
|
||||||
this.controllerServiceTypes = dialogRequest.controllerServiceTypes;
|
this.controllerServiceTypes = dialogRequest.controllerServiceTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,16 +49,17 @@ export class ExtensionCreation {
|
|||||||
this.selectedType = documentedTypes[0];
|
this.selectedType = documentedTypes[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataSource.data = this.sortEntities(documentedTypes, {
|
this.dataSource.data = this.sortEntities(documentedTypes, this.activeSort);
|
||||||
active: this.initialSortColumn,
|
|
||||||
direction: this.initialSortDirection
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() componentType!: string;
|
@Input() componentType!: string;
|
||||||
@Input() saving!: boolean;
|
@Input() saving!: boolean;
|
||||||
@Input() initialSortColumn: 'type' | 'version' | 'tags' = 'type';
|
@Input() initialSortColumn: 'type' | 'version' | 'tags' = 'type';
|
||||||
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
@Input() initialSortDirection: 'asc' | 'desc' = 'asc';
|
||||||
|
activeSort: Sort = {
|
||||||
|
active: this.initialSortColumn,
|
||||||
|
direction: this.initialSortDirection
|
||||||
|
};
|
||||||
|
|
||||||
@Output() extensionTypeSelected: EventEmitter<DocumentedType> = new EventEmitter<DocumentedType>();
|
@Output() extensionTypeSelected: EventEmitter<DocumentedType> = new EventEmitter<DocumentedType>();
|
||||||
|
|
||||||
@ -151,6 +152,7 @@ export class ExtensionCreation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortData(sort: Sort) {
|
sortData(sort: Sort) {
|
||||||
|
this.activeSort = sort;
|
||||||
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
this.dataSource.data = this.sortEntities(this.dataSource.data, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user