mirror of https://github.com/apache/nifi.git
NIFI-13078: Adding support to Enable and Disable through the context menu and operation control (#8680)
* NIFI-13078: - Adding support to Enable and Disable through the context menu and operation control. * NIFI-13078: - Addressing review feedback. This closes #8680
This commit is contained in:
parent
cde820673c
commit
562eece6e3
|
@ -58,13 +58,19 @@ import {
|
|||
copy,
|
||||
paste,
|
||||
terminateThreads,
|
||||
navigateToParameterContext
|
||||
navigateToParameterContext,
|
||||
enableCurrentProcessGroup,
|
||||
enableComponents,
|
||||
disableCurrentProcessGroup,
|
||||
disableComponents
|
||||
} from '../state/flow/flow.actions';
|
||||
import { ComponentType } from '../../../state/shared';
|
||||
import {
|
||||
ConfirmStopVersionControlRequest,
|
||||
CopyComponentRequest,
|
||||
DeleteComponentRequest,
|
||||
DisableComponentRequest,
|
||||
EnableComponentRequest,
|
||||
MoveComponentRequest,
|
||||
OpenChangeVersionDialogRequest,
|
||||
OpenLocalChangesDialogRequest,
|
||||
|
@ -573,8 +579,9 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
// are runnable or can start transmitting. However, if all the startable components are RGPs, we will defer
|
||||
// to the Enable Transmission menu option and not show the start option.
|
||||
const allRpgs =
|
||||
!startable.empty() &&
|
||||
startable.filter((d: any) => d.type === ComponentType.RemoteProcessGroup).size() ===
|
||||
startable.size();
|
||||
startable.size();
|
||||
|
||||
return this.canvasUtils.areAnyRunnable(selection) && !allRpgs;
|
||||
},
|
||||
|
@ -613,8 +620,9 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
// are runnable or can stop transmitting. However, if all the stoppable components are RGPs, we will defer
|
||||
// to the Disable Transmission menu option and not show the start option.
|
||||
const allRpgs =
|
||||
!stoppable.empty() &&
|
||||
stoppable.filter((d: any) => d.type === ComponentType.RemoteProcessGroup).size() ===
|
||||
stoppable.size();
|
||||
stoppable.size();
|
||||
|
||||
return this.canvasUtils.areAnyStoppable(selection) && !allRpgs;
|
||||
},
|
||||
|
@ -685,25 +693,65 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
}
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
// TODO - canEnable
|
||||
return false;
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.canEnable(selection);
|
||||
},
|
||||
clazz: 'fa fa-flash',
|
||||
text: 'Enable',
|
||||
action: () => {
|
||||
// TODO - enable
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
if (selection.empty()) {
|
||||
// attempting to enable the current process group
|
||||
this.store.dispatch(enableCurrentProcessGroup());
|
||||
} else {
|
||||
const components: EnableComponentRequest[] = [];
|
||||
const enableable = this.canvasUtils.filterEnable(selection);
|
||||
enableable.each((d: any) => {
|
||||
components.push({
|
||||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
enableComponents({
|
||||
request: {
|
||||
components
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
// TODO - canDisable
|
||||
return false;
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.canDisable(selection);
|
||||
},
|
||||
clazz: 'icon icon-enable-false',
|
||||
text: 'Disable',
|
||||
action: () => {
|
||||
// TODO - disable
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
if (selection.empty()) {
|
||||
// attempting to disable the current process group
|
||||
this.store.dispatch(disableCurrentProcessGroup());
|
||||
} else {
|
||||
const components: DisableComponentRequest[] = [];
|
||||
const disableable = this.canvasUtils.filterDisable(selection);
|
||||
disableable.each((d: any) => {
|
||||
components.push({
|
||||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
disableComponents({
|
||||
request: {
|
||||
components
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1440,6 +1440,89 @@ export class CanvasUtils {
|
|||
return '#ffffff';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the specified selection for any components that supports enable.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
*/
|
||||
public filterEnable(selection: d3.Selection<any, any, any, any>): d3.Selection<any, any, any, any> {
|
||||
return selection.filter((d, i, nodes) => {
|
||||
const selected = d3.select(nodes[i]);
|
||||
|
||||
// enable always allowed for PGs since they will invoke the /flow endpoint for enabling all applicable components (based on permissions)
|
||||
if (this.isProcessGroup(selected)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not a PG, verify permissions to modify
|
||||
if (!this.canOperate(selected)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure it's a processor, input port, or output port and supports modification and is disabled (can enable)
|
||||
return (
|
||||
(this.isProcessor(selected) || this.isInputPort(selected) || this.isOutputPort(selected)) &&
|
||||
this.supportsModification(selected) &&
|
||||
d.status.aggregateSnapshot.runStatus === 'Disabled'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified selection contains any components that supports enable.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
*/
|
||||
public canEnable(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
if (selection.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.filterEnable(selection).size() === selection.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the specified selection for any components that supports disable.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
*/
|
||||
public filterDisable(selection: d3.Selection<any, any, any, any>): d3.Selection<any, any, any, any> {
|
||||
return selection.filter((d, i, nodes) => {
|
||||
const selected = d3.select(nodes[i]);
|
||||
|
||||
// disable always allowed for PGs since they will invoke the /flow endpoint for disabling all applicable components (based on permissions)
|
||||
if (this.isProcessGroup(selected)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not a PG, verify permissions to modify
|
||||
if (!this.canOperate(selected)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure it's a processor, input port, or output port and supports modification and is stopped (can disable)
|
||||
return (
|
||||
(this.isProcessor(selected) || this.isInputPort(selected) || this.isOutputPort(selected)) &&
|
||||
this.supportsModification(selected) &&
|
||||
(d.status.aggregateSnapshot.runStatus === 'Stopped' ||
|
||||
d.status.aggregateSnapshot.runStatus === 'Invalid')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified selection contains any components that supports disable.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
*/
|
||||
public canDisable(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
if (selection.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.filterDisable(selection).size() === selection.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the components in the specified selection are runnable.
|
||||
*
|
||||
|
|
|
@ -27,7 +27,11 @@ import {
|
|||
CreateProcessorRequest,
|
||||
CreateRemoteProcessGroupRequest,
|
||||
DeleteComponentRequest,
|
||||
DisableComponentRequest,
|
||||
DisableProcessGroupRequest,
|
||||
DownloadFlowRequest,
|
||||
EnableComponentRequest,
|
||||
EnableProcessGroupRequest,
|
||||
FlowComparisonEntity,
|
||||
FlowUpdateRequestEntity,
|
||||
GoToRemoteProcessGroupRequest,
|
||||
|
@ -270,6 +274,24 @@ export class FlowService implements PropertyDescriptorRetriever {
|
|||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, startRequest);
|
||||
}
|
||||
|
||||
enableComponent(request: EnableComponentRequest): Observable<any> {
|
||||
const enableRequest: ComponentRunStatusRequest = {
|
||||
revision: request.revision,
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
state: 'STOPPED'
|
||||
};
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, enableRequest);
|
||||
}
|
||||
|
||||
disableComponent(request: DisableComponentRequest): Observable<any> {
|
||||
const disableRequest: ComponentRunStatusRequest = {
|
||||
revision: request.revision,
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
state: 'DISABLED'
|
||||
};
|
||||
return this.httpClient.put(`${this.nifiCommon.stripProtocol(request.uri)}/run-status`, disableRequest);
|
||||
}
|
||||
|
||||
startComponent(request: StartComponentRequest): Observable<any> {
|
||||
const startRequest: ComponentRunStatusRequest = {
|
||||
revision: request.revision,
|
||||
|
@ -292,6 +314,24 @@ export class FlowService implements PropertyDescriptorRetriever {
|
|||
return this.httpClient.delete(`${this.nifiCommon.stripProtocol(request.uri)}/threads`);
|
||||
}
|
||||
|
||||
enableProcessGroup(request: EnableProcessGroupRequest): Observable<any> {
|
||||
const enableRequest: ProcessGroupRunStatusRequest = {
|
||||
id: request.id,
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
state: 'ENABLED'
|
||||
};
|
||||
return this.httpClient.put(`${FlowService.API}/flow/process-groups/${request.id}`, enableRequest);
|
||||
}
|
||||
|
||||
disableProcessGroup(request: DisableProcessGroupRequest): Observable<any> {
|
||||
const disableComponent: ProcessGroupRunStatusRequest = {
|
||||
id: request.id,
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
state: 'DISABLED'
|
||||
};
|
||||
return this.httpClient.put(`${FlowService.API}/flow/process-groups/${request.id}`, disableComponent);
|
||||
}
|
||||
|
||||
startProcessGroup(request: StartProcessGroupRequest): Observable<any> {
|
||||
const startRequest: ProcessGroupRunStatusRequest = {
|
||||
id: request.id,
|
||||
|
|
|
@ -34,10 +34,20 @@ import {
|
|||
CreateRemoteProcessGroupRequest,
|
||||
DeleteComponentRequest,
|
||||
DeleteComponentResponse,
|
||||
DisableComponentRequest,
|
||||
DisableComponentResponse,
|
||||
DisableComponentsRequest,
|
||||
DisableProcessGroupRequest,
|
||||
DisableProcessGroupResponse,
|
||||
DownloadFlowRequest,
|
||||
EditComponentDialogRequest,
|
||||
EditConnectionDialogRequest,
|
||||
EditCurrentProcessGroupRequest,
|
||||
EnableComponentRequest,
|
||||
EnableComponentResponse,
|
||||
EnableComponentsRequest,
|
||||
EnableProcessGroupRequest,
|
||||
EnableProcessGroupResponse,
|
||||
EnterProcessGroupRequest,
|
||||
FlowUpdateRequestEntity,
|
||||
GoToRemoteProcessGroupRequest,
|
||||
|
@ -588,6 +598,50 @@ export const replayLastProvenanceEvent = createAction(
|
|||
props<{ request: ReplayLastProvenanceEventRequest }>()
|
||||
);
|
||||
|
||||
export const enableComponent = createAction(
|
||||
`${CANVAS_PREFIX} Enable Component`,
|
||||
props<{ request: EnableComponentRequest | EnableProcessGroupRequest }>()
|
||||
);
|
||||
|
||||
export const enableComponents = createAction(
|
||||
`${CANVAS_PREFIX} Enable Components`,
|
||||
props<{ request: EnableComponentsRequest }>()
|
||||
);
|
||||
|
||||
export const enableComponentSuccess = createAction(
|
||||
`${CANVAS_PREFIX} Enable Component Success`,
|
||||
props<{ response: EnableComponentResponse }>()
|
||||
);
|
||||
|
||||
export const enableProcessGroupSuccess = createAction(
|
||||
`${CANVAS_PREFIX} Enable Process Group Success`,
|
||||
props<{ response: EnableProcessGroupResponse }>()
|
||||
);
|
||||
|
||||
export const enableCurrentProcessGroup = createAction(`${CANVAS_PREFIX} Enable Current Process Group`);
|
||||
|
||||
export const disableComponent = createAction(
|
||||
`${CANVAS_PREFIX} Disable Component`,
|
||||
props<{ request: DisableComponentRequest | DisableProcessGroupRequest }>()
|
||||
);
|
||||
|
||||
export const disableComponents = createAction(
|
||||
`${CANVAS_PREFIX} Disable Components`,
|
||||
props<{ request: DisableComponentsRequest }>()
|
||||
);
|
||||
|
||||
export const disableComponentSuccess = createAction(
|
||||
`${CANVAS_PREFIX} Disable Component Success`,
|
||||
props<{ response: DisableComponentResponse }>()
|
||||
);
|
||||
|
||||
export const disableProcessGroupSuccess = createAction(
|
||||
`${CANVAS_PREFIX} Disable Process Group Success`,
|
||||
props<{ response: DisableProcessGroupResponse }>()
|
||||
);
|
||||
|
||||
export const disableCurrentProcessGroup = createAction(`${CANVAS_PREFIX} Disable Current Process Group`);
|
||||
|
||||
export const runOnce = createAction(`${CANVAS_PREFIX} Run Once`, props<{ request: RunOnceRequest }>());
|
||||
|
||||
export const runOnceSuccess = createAction(`${CANVAS_PREFIX} Run Once Success`, props<{ response: RunOnceResponse }>());
|
||||
|
|
|
@ -2436,6 +2436,240 @@ export class FlowEffects {
|
|||
{ dispatch: false }
|
||||
);
|
||||
|
||||
enableCurrentProcessGroup$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.enableCurrentProcessGroup),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
switchMap(([, pgId]) => {
|
||||
return of(
|
||||
FlowActions.enableComponent({
|
||||
request: {
|
||||
id: pgId,
|
||||
type: ComponentType.ProcessGroup
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
enableComponents$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.enableComponents),
|
||||
map((action) => action.request),
|
||||
mergeMap((request) => [
|
||||
...request.components.map((component) => {
|
||||
return FlowActions.enableComponent({
|
||||
request: component
|
||||
});
|
||||
})
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
enableComponent$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.enableComponent),
|
||||
map((action) => action.request),
|
||||
mergeMap((request) => {
|
||||
switch (request.type) {
|
||||
case ComponentType.InputPort:
|
||||
case ComponentType.OutputPort:
|
||||
case ComponentType.Processor:
|
||||
if ('uri' in request && 'revision' in request) {
|
||||
return from(this.flowService.enableComponent(request)).pipe(
|
||||
map((response) => {
|
||||
return FlowActions.enableComponentSuccess({
|
||||
response: {
|
||||
type: request.type,
|
||||
component: response
|
||||
}
|
||||
});
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
}
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({
|
||||
error: `Enabling ${request.type} requires both uri and revision properties`
|
||||
})
|
||||
);
|
||||
case ComponentType.ProcessGroup:
|
||||
return from(this.flowService.enableProcessGroup(request)).pipe(
|
||||
map((enablePgResponse) => {
|
||||
return FlowActions.enableProcessGroupSuccess({
|
||||
response: {
|
||||
type: request.type,
|
||||
component: enablePgResponse
|
||||
}
|
||||
});
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
default:
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({ error: `${request.type} does not support enabling` })
|
||||
);
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* If the component enabled was the current process group, reload the flow
|
||||
*/
|
||||
enableCurrentProcessGroupSuccess$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.enableProcessGroupSuccess),
|
||||
map((action) => action.response),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
filter(([response, currentPg]) => response.component.id === currentPg),
|
||||
switchMap(() => of(FlowActions.reloadFlow()))
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* If a ProcessGroup was enabled, it should be reloaded as the response from the start operation doesn't contain all the displayed info
|
||||
*/
|
||||
enableProcessGroupSuccess$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.enableProcessGroupSuccess),
|
||||
map((action) => action.response),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
filter(([response, currentPg]) => response.component.id !== currentPg),
|
||||
switchMap(([response]) =>
|
||||
of(
|
||||
FlowActions.loadChildProcessGroup({
|
||||
request: {
|
||||
id: response.component.id
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
disableCurrentProcessGroup$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.disableCurrentProcessGroup),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
switchMap(([, pgId]) => {
|
||||
return of(
|
||||
FlowActions.disableComponent({
|
||||
request: {
|
||||
id: pgId,
|
||||
type: ComponentType.ProcessGroup
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
disableComponents$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.disableComponents),
|
||||
map((action) => action.request),
|
||||
mergeMap((request) => [
|
||||
...request.components.map((component) => {
|
||||
return FlowActions.disableComponent({
|
||||
request: component
|
||||
});
|
||||
})
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
disableComponent$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.disableComponent),
|
||||
map((action) => action.request),
|
||||
mergeMap((request) => {
|
||||
switch (request.type) {
|
||||
case ComponentType.InputPort:
|
||||
case ComponentType.OutputPort:
|
||||
case ComponentType.Processor:
|
||||
if ('uri' in request && 'revision' in request) {
|
||||
return from(this.flowService.disableComponent(request)).pipe(
|
||||
map((response) => {
|
||||
return FlowActions.disableComponentSuccess({
|
||||
response: {
|
||||
type: request.type,
|
||||
component: response
|
||||
}
|
||||
});
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
}
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({
|
||||
error: `Disabling ${request.type} requires both uri and revision properties`
|
||||
})
|
||||
);
|
||||
case ComponentType.ProcessGroup:
|
||||
return from(this.flowService.disableProcessGroup(request)).pipe(
|
||||
map((enablePgResponse) => {
|
||||
return FlowActions.disableProcessGroupSuccess({
|
||||
response: {
|
||||
type: request.type,
|
||||
component: enablePgResponse
|
||||
}
|
||||
});
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
default:
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({ error: `${request.type} does not support disabling` })
|
||||
);
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* If the component disabled was the current process group, reload the flow
|
||||
*/
|
||||
disableCurrentProcessGroupSuccess$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.disableProcessGroupSuccess),
|
||||
map((action) => action.response),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
filter(([response, currentPg]) => response.component.id === currentPg),
|
||||
switchMap(() => of(FlowActions.reloadFlow()))
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* If a ProcessGroup was disabled, it should be reloaded as the response from the start operation doesn't contain all the displayed info
|
||||
*/
|
||||
disableProcessGroupSuccess$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.disableProcessGroupSuccess),
|
||||
map((action) => action.response),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
filter(([response, currentPg]) => response.component.id !== currentPg),
|
||||
switchMap(([response]) =>
|
||||
of(
|
||||
FlowActions.loadChildProcessGroup({
|
||||
request: {
|
||||
id: response.component.id
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
startCurrentProcessGroup$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.startCurrentProcessGroup),
|
||||
|
@ -2449,8 +2683,7 @@ export class FlowEffects {
|
|||
}
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -2488,11 +2721,13 @@ export class FlowEffects {
|
|||
}
|
||||
});
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
}
|
||||
return of(
|
||||
FlowActions.flowApiError({
|
||||
FlowActions.flowSnackbarError({
|
||||
error: `Starting ${request.type} requires both uri and revision properties`
|
||||
})
|
||||
);
|
||||
|
@ -2509,13 +2744,16 @@ export class FlowEffects {
|
|||
}
|
||||
});
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
default:
|
||||
return of(FlowActions.flowApiError({ error: `${request.type} does not support starting` }));
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({ error: `${request.type} does not support starting` })
|
||||
);
|
||||
}
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -2604,11 +2842,13 @@ export class FlowEffects {
|
|||
}
|
||||
});
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
}
|
||||
return of(
|
||||
FlowActions.flowApiError({
|
||||
FlowActions.flowSnackbarError({
|
||||
error: `Stopping ${request.type} requires both uri and revision properties`
|
||||
})
|
||||
);
|
||||
|
@ -2625,13 +2865,16 @@ export class FlowEffects {
|
|||
}
|
||||
});
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
default:
|
||||
return of(FlowActions.flowApiError({ error: `${request.type} does not support stopping` }));
|
||||
return of(
|
||||
FlowActions.flowSnackbarError({ error: `${request.type} does not support stopping` })
|
||||
);
|
||||
}
|
||||
}),
|
||||
catchError((error) => of(FlowActions.flowApiError({ error: error.error })))
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -2739,6 +2982,7 @@ export class FlowEffects {
|
|||
//////////////////////////////////
|
||||
// Start version control effects
|
||||
//////////////////////////////////
|
||||
|
||||
openSaveVersionDialogRequest$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.openSaveVersionDialogRequest),
|
||||
|
|
|
@ -30,6 +30,12 @@ import {
|
|||
createProcessGroup,
|
||||
createProcessor,
|
||||
deleteComponentsSuccess,
|
||||
disableComponent,
|
||||
disableComponentSuccess,
|
||||
disableProcessGroupSuccess,
|
||||
enableComponent,
|
||||
enableComponentSuccess,
|
||||
enableProcessGroupSuccess,
|
||||
flowApiError,
|
||||
flowVersionBannerError,
|
||||
groupComponents,
|
||||
|
@ -61,8 +67,11 @@ import {
|
|||
setTransitionRequired,
|
||||
startComponent,
|
||||
startComponentSuccess,
|
||||
startProcessGroupSuccess,
|
||||
startRemoteProcessGroupPolling,
|
||||
stopComponent,
|
||||
stopComponentSuccess,
|
||||
stopProcessGroupSuccess,
|
||||
stopRemoteProcessGroupPolling,
|
||||
stopVersionControl,
|
||||
stopVersionControlSuccess,
|
||||
|
@ -275,10 +284,30 @@ export const flowReducer = createReducer(
|
|||
dragging: false,
|
||||
saving: false
|
||||
})),
|
||||
on(updateComponent, updateProcessor, updateConnection, startComponent, runOnce, (state) => ({
|
||||
...state,
|
||||
saving: true
|
||||
})),
|
||||
on(
|
||||
updateComponent,
|
||||
updateProcessor,
|
||||
updateConnection,
|
||||
enableComponent,
|
||||
disableComponent,
|
||||
startComponent,
|
||||
stopComponent,
|
||||
runOnce,
|
||||
(state) => ({
|
||||
...state,
|
||||
saving: true
|
||||
})
|
||||
),
|
||||
on(
|
||||
enableProcessGroupSuccess,
|
||||
disableProcessGroupSuccess,
|
||||
startProcessGroupSuccess,
|
||||
stopProcessGroupSuccess,
|
||||
(state) => ({
|
||||
...state,
|
||||
saving: false
|
||||
})
|
||||
),
|
||||
on(updateComponentSuccess, updateProcessorSuccess, updateConnectionSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
const collection: any[] | null = getComponentCollection(draftState, response.type);
|
||||
|
@ -400,20 +429,26 @@ export const flowReducer = createReducer(
|
|||
...state,
|
||||
operationCollapsed
|
||||
})),
|
||||
on(startComponentSuccess, stopComponentSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
const collection: any[] | null = getComponentCollection(draftState, response.type);
|
||||
on(
|
||||
startComponentSuccess,
|
||||
stopComponentSuccess,
|
||||
enableComponentSuccess,
|
||||
disableComponentSuccess,
|
||||
(state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
const collection: any[] | null = getComponentCollection(draftState, response.type);
|
||||
|
||||
if (collection) {
|
||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||
if (componentIndex > -1) {
|
||||
collection[componentIndex] = response.component;
|
||||
if (collection) {
|
||||
const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id);
|
||||
if (componentIndex > -1) {
|
||||
collection[componentIndex] = response.component;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draftState.saving = false;
|
||||
});
|
||||
}),
|
||||
draftState.saving = false;
|
||||
});
|
||||
}
|
||||
),
|
||||
|
||||
on(runOnceSuccess, (state, { response }) => {
|
||||
return produce(state, (draftState) => {
|
||||
|
|
|
@ -655,6 +655,64 @@ export interface RunOnceResponse {
|
|||
component: ComponentEntity;
|
||||
}
|
||||
|
||||
export interface EnableProcessGroupRequest {
|
||||
id: string;
|
||||
type: ComponentType;
|
||||
}
|
||||
|
||||
export interface EnableComponentRequest {
|
||||
id: string;
|
||||
uri: string;
|
||||
type: ComponentType;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface EnableComponentsRequest {
|
||||
components: EnableComponentRequest[];
|
||||
}
|
||||
|
||||
export interface EnableComponentResponse {
|
||||
type: ComponentType;
|
||||
component: ComponentEntity;
|
||||
}
|
||||
|
||||
export interface EnableProcessGroupResponse {
|
||||
type: ComponentType;
|
||||
component: {
|
||||
id: string;
|
||||
state: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DisableProcessGroupRequest {
|
||||
id: string;
|
||||
type: ComponentType;
|
||||
}
|
||||
|
||||
export interface DisableComponentRequest {
|
||||
id: string;
|
||||
uri: string;
|
||||
type: ComponentType;
|
||||
revision: Revision;
|
||||
}
|
||||
|
||||
export interface DisableComponentsRequest {
|
||||
components: DisableComponentRequest[];
|
||||
}
|
||||
|
||||
export interface DisableComponentResponse {
|
||||
type: ComponentType;
|
||||
component: ComponentEntity;
|
||||
}
|
||||
|
||||
export interface DisableProcessGroupResponse {
|
||||
type: ComponentType;
|
||||
component: {
|
||||
id: string;
|
||||
state: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface StartProcessGroupRequest {
|
||||
id: string;
|
||||
type: ComponentType;
|
||||
|
@ -692,10 +750,6 @@ export interface StopProcessGroupResponse {
|
|||
};
|
||||
}
|
||||
|
||||
export interface StartComponentsResponse {
|
||||
components: StartComponentsResponse[];
|
||||
}
|
||||
|
||||
export interface ComponentRunStatusRequest {
|
||||
revision: Revision;
|
||||
state: string;
|
||||
|
|
|
@ -19,6 +19,10 @@ import { Component, Input } from '@angular/core';
|
|||
import {
|
||||
copy,
|
||||
deleteComponents,
|
||||
disableComponents,
|
||||
disableCurrentProcessGroup,
|
||||
enableComponents,
|
||||
enableCurrentProcessGroup,
|
||||
getParameterContextsAndOpenGroupComponentsDialog,
|
||||
navigateToEditComponent,
|
||||
navigateToEditCurrentProcessGroup,
|
||||
|
@ -38,6 +42,8 @@ import { Storage } from '../../../../../../service/storage.service';
|
|||
import {
|
||||
CopyComponentRequest,
|
||||
DeleteComponentRequest,
|
||||
DisableComponentRequest,
|
||||
EnableComponentRequest,
|
||||
MoveComponentRequest,
|
||||
StartComponentRequest,
|
||||
StopComponentRequest
|
||||
|
@ -48,6 +54,7 @@ import { ComponentType } from '../../../../../../state/shared';
|
|||
import { MatButtonModule } from '@angular/material/button';
|
||||
import * as d3 from 'd3';
|
||||
import { CanvasView } from '../../../../service/canvas-view.service';
|
||||
import { Client } from '../../../../../../service/client.service';
|
||||
|
||||
@Component({
|
||||
selector: 'operation-control',
|
||||
|
@ -69,6 +76,7 @@ export class OperationControl {
|
|||
private store: Store<CanvasState>,
|
||||
public canvasUtils: CanvasUtils,
|
||||
private canvasView: CanvasView,
|
||||
private client: Client,
|
||||
private storage: Storage
|
||||
) {
|
||||
try {
|
||||
|
@ -76,7 +84,7 @@ export class OperationControl {
|
|||
OperationControl.CONTROL_VISIBILITY_KEY
|
||||
);
|
||||
if (item) {
|
||||
this.operationCollapsed = item[OperationControl.OPERATION_KEY] === false;
|
||||
this.operationCollapsed = !item[OperationControl.OPERATION_KEY];
|
||||
this.store.dispatch(setOperationCollapsed({ operationCollapsed: this.operationCollapsed }));
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -98,7 +106,7 @@ export class OperationControl {
|
|||
this.storage.setItem(OperationControl.CONTROL_VISIBILITY_KEY, item);
|
||||
}
|
||||
|
||||
getContextIcon(selection: any): string {
|
||||
getContextIcon(selection: d3.Selection<any, any, any, any>): string {
|
||||
if (selection.size() === 0) {
|
||||
if (this.breadcrumbEntity.parentBreadcrumb == null) {
|
||||
return 'icon-drop';
|
||||
|
@ -128,7 +136,7 @@ export class OperationControl {
|
|||
}
|
||||
}
|
||||
|
||||
getContextName(selection: any): string {
|
||||
getContextName(selection: d3.Selection<any, any, any, any>): string {
|
||||
if (selection.size() === 0) {
|
||||
if (this.breadcrumbEntity.permissions.canRead) {
|
||||
return this.breadcrumbEntity.breadcrumb.name;
|
||||
|
@ -153,7 +161,7 @@ export class OperationControl {
|
|||
}
|
||||
}
|
||||
|
||||
getContextType(selection: any): string {
|
||||
getContextType(selection: d3.Selection<any, any, any, any>): string {
|
||||
if (selection.size() === 0) {
|
||||
return 'Process Group';
|
||||
} else if (selection.size() > 1) {
|
||||
|
@ -179,7 +187,7 @@ export class OperationControl {
|
|||
}
|
||||
}
|
||||
|
||||
getContextId(selection: any): string {
|
||||
getContextId(selection: d3.Selection<any, any, any, any>): string {
|
||||
if (selection.size() === 0) {
|
||||
return this.breadcrumbEntity.id;
|
||||
} else if (selection.size() > 1) {
|
||||
|
@ -190,11 +198,11 @@ export class OperationControl {
|
|||
return selectionData.id;
|
||||
}
|
||||
|
||||
canConfigure(selection: any): boolean {
|
||||
canConfigure(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.isConfigurable(selection);
|
||||
}
|
||||
|
||||
configure(selection: any): void {
|
||||
configure(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
this.store.dispatch(navigateToEditCurrentProcessGroup());
|
||||
} else {
|
||||
|
@ -214,11 +222,11 @@ export class OperationControl {
|
|||
return this.canvasUtils.supportsManagedAuthorizer();
|
||||
}
|
||||
|
||||
canManageAccess(selection: any): boolean {
|
||||
canManageAccess(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.canManagePolicies(selection);
|
||||
}
|
||||
|
||||
manageAccess(selection: any): void {
|
||||
manageAccess(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
this.store.dispatch(
|
||||
navigateToManageComponentPolicies({
|
||||
|
@ -265,29 +273,69 @@ export class OperationControl {
|
|||
}
|
||||
}
|
||||
|
||||
canEnable(selection: any): boolean {
|
||||
// TODO - canEnable
|
||||
return false;
|
||||
canEnable(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.canEnable(selection);
|
||||
}
|
||||
|
||||
enable(selection: any): void {
|
||||
// TODO - enable
|
||||
enable(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
// attempting to enable the current process group
|
||||
this.store.dispatch(enableCurrentProcessGroup());
|
||||
} else {
|
||||
const components: EnableComponentRequest[] = [];
|
||||
const enableable = this.canvasUtils.filterEnable(selection);
|
||||
enableable.each((d: any) => {
|
||||
components.push({
|
||||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
enableComponents({
|
||||
request: {
|
||||
components
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
canDisable(selection: any): boolean {
|
||||
// TODO - canDisable
|
||||
return false;
|
||||
canDisable(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.canDisable(selection);
|
||||
}
|
||||
|
||||
disable(selection: any): void {
|
||||
// TODO - disable
|
||||
disable(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
// attempting to disable the current process group
|
||||
this.store.dispatch(disableCurrentProcessGroup());
|
||||
} else {
|
||||
const components: DisableComponentRequest[] = [];
|
||||
const disableable = this.canvasUtils.filterDisable(selection);
|
||||
disableable.each((d: any) => {
|
||||
components.push({
|
||||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
disableComponents({
|
||||
request: {
|
||||
components
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
canStart(selection: any): boolean {
|
||||
canStart(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.areAnyRunnable(selection);
|
||||
}
|
||||
|
||||
start(selection: any): void {
|
||||
start(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
// attempting to start the current process group
|
||||
this.store.dispatch(startCurrentProcessGroup());
|
||||
|
@ -299,7 +347,7 @@ export class OperationControl {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
|
@ -312,11 +360,11 @@ export class OperationControl {
|
|||
}
|
||||
}
|
||||
|
||||
canStop(selection: any): boolean {
|
||||
canStop(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.areAnyStoppable(selection);
|
||||
}
|
||||
|
||||
stop(selection: any): void {
|
||||
stop(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.empty()) {
|
||||
// attempting to start the current process group
|
||||
this.store.dispatch(stopCurrentProcessGroup());
|
||||
|
@ -328,7 +376,7 @@ export class OperationControl {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
|
@ -382,11 +430,11 @@ export class OperationControl {
|
|||
);
|
||||
}
|
||||
|
||||
canGroup(selection: any): boolean {
|
||||
canGroup(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.isDisconnected(selection);
|
||||
}
|
||||
|
||||
group(selection: any): void {
|
||||
group(selection: d3.Selection<any, any, any, any>): void {
|
||||
const moveComponents: MoveComponentRequest[] = [];
|
||||
selection.each(function (d: any) {
|
||||
moveComponents.push({
|
||||
|
@ -408,20 +456,20 @@ export class OperationControl {
|
|||
);
|
||||
}
|
||||
|
||||
canColor(selection: any): boolean {
|
||||
canColor(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
color(selection: any): void {
|
||||
color(selection: d3.Selection<any, any, any, any>): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
canDelete(selection: any): boolean {
|
||||
canDelete(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
return this.canvasUtils.areDeletable(selection);
|
||||
}
|
||||
|
||||
delete(selection: any): void {
|
||||
delete(selection: d3.Selection<any, any, any, any>): void {
|
||||
if (selection.size() === 1) {
|
||||
const selectionData = selection.datum();
|
||||
this.store.dispatch(
|
||||
|
|
Loading…
Reference in New Issue