mirror of https://github.com/apache/nifi.git
NIFI-13044: Adding support to move to front (#8646)
* NIFI-13044: - Adding support to move to front. - Fixing revisions sent in various payloads. * NIFI-13047: - Address review feedback. This closes #8646
This commit is contained in:
parent
2d9943e2d3
commit
a79b210d4e
|
@ -52,7 +52,8 @@ import {
|
|||
stopComponents,
|
||||
stopCurrentProcessGroup,
|
||||
stopVersionControlRequest,
|
||||
downloadFlow
|
||||
downloadFlow,
|
||||
moveToFront
|
||||
} from '../state/flow/flow.actions';
|
||||
import { ComponentType } from '../../../state/shared';
|
||||
import {
|
||||
|
@ -73,6 +74,7 @@ import { promptEmptyQueueRequest, promptEmptyQueuesRequest } from '../state/queu
|
|||
import { getComponentStateAndOpenDialog } from '../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../state/documentation/documentation.actions';
|
||||
import * as d3 from 'd3';
|
||||
import { Client } from '../../../service/client.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
||||
|
@ -557,7 +559,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
|
@ -597,7 +599,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
|
@ -625,7 +627,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
runOnce({
|
||||
request: {
|
||||
uri: d.uri,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -678,7 +680,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -706,7 +708,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
id: d.id,
|
||||
uri: d.uri,
|
||||
type: d.type,
|
||||
revision: d.revision
|
||||
revision: this.client.getRevision(d)
|
||||
});
|
||||
});
|
||||
this.store.dispatch(
|
||||
|
@ -982,12 +984,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
isSeparator: true
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.isConnection(selection);
|
||||
},
|
||||
clazz: 'fa fa-long-arrow-left',
|
||||
text: 'Go to source',
|
||||
action: (selection: any) => {
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
const selectionData = selection.datum();
|
||||
const remoteConnectableType: string = this.canvasUtils.getConnectableTypeForSource(
|
||||
ComponentType.RemoteProcessGroup
|
||||
|
@ -1023,12 +1025,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
}
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.isConnection(selection);
|
||||
},
|
||||
clazz: 'fa fa-long-arrow-right',
|
||||
text: 'Go to destination',
|
||||
action: (selection: any) => {
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
const selectionData = selection.datum();
|
||||
const remoteConnectableType: string = this.canvasUtils.getConnectableTypeForDestination(
|
||||
ComponentType.RemoteProcessGroup
|
||||
|
@ -1072,18 +1074,29 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
subMenuId: this.ALIGN.id
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
// TODO - canMoveToFront
|
||||
return false;
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.canMoveToFront(selection);
|
||||
},
|
||||
clazz: 'fa fa-clone',
|
||||
text: 'Bring to front',
|
||||
action: () => {
|
||||
// TODO - toFront
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
const selectionData = selection.datum();
|
||||
|
||||
this.store.dispatch(
|
||||
moveToFront({
|
||||
request: {
|
||||
componentType: selectionData.type,
|
||||
id: selectionData.id,
|
||||
uri: selectionData.uri,
|
||||
revision: this.client.getRevision(selectionData),
|
||||
zIndex: selectionData.zIndex
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return !selection.empty();
|
||||
},
|
||||
clazz: 'fa fa-crosshairs',
|
||||
|
@ -1104,12 +1117,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
}
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.canRead(selection) && this.canvasUtils.isRemoteProcessGroup(selection);
|
||||
},
|
||||
clazz: 'fa fa-external-link',
|
||||
text: 'Go to',
|
||||
action: (selection: any) => {
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
const selectionData = selection.datum();
|
||||
const uri = selectionData.component.targetUri;
|
||||
|
||||
|
@ -1120,12 +1133,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
isSeparator: true
|
||||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
condition: (selection: d3.Selection<any, any, any, any>) => {
|
||||
return this.canvasUtils.isNotRootGroup();
|
||||
},
|
||||
clazz: 'fa fa-arrows',
|
||||
text: 'Move to parent group',
|
||||
action: (selection: any) => {
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
const components: MoveComponentRequest[] = [];
|
||||
selection.each(function (d: any) {
|
||||
components.push({
|
||||
|
@ -1300,7 +1313,8 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
|
||||
constructor(
|
||||
private store: Store<CanvasState>,
|
||||
private canvasUtils: CanvasUtils
|
||||
private canvasUtils: CanvasUtils,
|
||||
private client: Client
|
||||
) {
|
||||
this.allMenus = new Map<string, ContextMenuDefinition>();
|
||||
this.allMenus.set(this.ROOT_MENU.id, this.ROOT_MENU);
|
||||
|
|
|
@ -1711,4 +1711,16 @@ export class CanvasUtils {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public canMoveToFront(selection: d3.Selection<any, any, any, any>): boolean {
|
||||
// ensure the correct number of components are selected
|
||||
if (selection.size() !== 1) {
|
||||
return false;
|
||||
}
|
||||
if (this.canModify(selection) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isConnection(selection) || this.isLabel(selection);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,8 +270,8 @@ export class ConnectionManager {
|
|||
* @param {type} connections
|
||||
*/
|
||||
private sort(connections: any[]): void {
|
||||
connections.sort(function (a, b) {
|
||||
return a.zIndex === b.zIndex ? 0 : a.zIndex > b.zIndex ? 1 : -1;
|
||||
connections.sort((a, b) => {
|
||||
return this.nifiCommon.compareNumber(a.zIndex, b.zIndex);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,17 @@ export class LabelManager {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the specified labels according to the z index.
|
||||
*
|
||||
* @param {type} labels
|
||||
*/
|
||||
private sort(labels: any[]): void {
|
||||
labels.sort((a, b) => {
|
||||
return this.nifiCommon.compareNumber(a.zIndex, b.zIndex);
|
||||
});
|
||||
}
|
||||
|
||||
private renderLabels(entered: any) {
|
||||
if (entered.empty()) {
|
||||
return entered;
|
||||
|
@ -393,6 +404,7 @@ export class LabelManager {
|
|||
// update
|
||||
const updated = selection.merge(entered);
|
||||
this.updateLabels(updated);
|
||||
this.sort(updated);
|
||||
|
||||
// position
|
||||
this.positionBehavior.position(updated, this.transitionRequired);
|
||||
|
|
|
@ -54,6 +54,7 @@ import {
|
|||
LoadRemoteProcessGroupSuccess,
|
||||
LocalChangesDialogRequest,
|
||||
MoveComponentsRequest,
|
||||
MoveToFrontRequest,
|
||||
NavigateToComponentRequest,
|
||||
NavigateToControllerServicesRequest,
|
||||
NavigateToManageComponentPoliciesRequest,
|
||||
|
@ -766,3 +767,5 @@ export const downloadFlow = createAction(
|
|||
`${CANVAS_PREFIX} Download Flow Request`,
|
||||
props<{ request: DownloadFlowRequest }>()
|
||||
);
|
||||
|
||||
export const moveToFront = createAction(`${CANVAS_PREFIX} Move To Front`, props<{ request: MoveToFrontRequest }>());
|
||||
|
|
|
@ -51,6 +51,7 @@ import {
|
|||
StopVersionControlRequest,
|
||||
StopVersionControlResponse,
|
||||
UpdateComponentFailure,
|
||||
UpdateComponentRequest,
|
||||
UpdateComponentResponse,
|
||||
UpdateConnectionSuccess,
|
||||
UpdateProcessorRequest,
|
||||
|
@ -62,6 +63,7 @@ import {
|
|||
selectChangeVersionRequest,
|
||||
selectCurrentParameterContext,
|
||||
selectCurrentProcessGroupId,
|
||||
selectMaxZIndex,
|
||||
selectParentProcessGroupId,
|
||||
selectProcessGroup,
|
||||
selectProcessor,
|
||||
|
@ -113,6 +115,7 @@ import { SaveVersionDialog } from '../../ui/canvas/items/flow/save-version-dialo
|
|||
import { ChangeVersionDialog } from '../../ui/canvas/items/flow/change-version-dialog/change-version-dialog';
|
||||
import { ChangeVersionProgressDialog } from '../../ui/canvas/items/flow/change-version-progress-dialog/change-version-progress-dialog';
|
||||
import { LocalChangesDialog } from '../../ui/canvas/items/flow/local-changes-dialog/local-changes-dialog';
|
||||
import { ClusterConnectionService } from '../../../../service/cluster-connection.service';
|
||||
|
||||
@Injectable()
|
||||
export class FlowEffects {
|
||||
|
@ -127,6 +130,7 @@ export class FlowEffects {
|
|||
private canvasView: CanvasView,
|
||||
private birdseyeView: BirdseyeView,
|
||||
private connectionManager: ConnectionManager,
|
||||
private clusterConnectionService: ClusterConnectionService,
|
||||
private router: Router,
|
||||
private dialog: MatDialog,
|
||||
private propertyTableHelperService: PropertyTableHelperService,
|
||||
|
@ -2846,7 +2850,7 @@ export class FlowEffects {
|
|||
version: selectedVersion.version
|
||||
},
|
||||
processGroupRevision: request.revision,
|
||||
disconnectedNodeAcknowledged: false
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged()
|
||||
};
|
||||
dialogRef.close();
|
||||
|
||||
|
@ -3153,4 +3157,42 @@ export class FlowEffects {
|
|||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
moveToFront$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowActions.moveToFront),
|
||||
map((action) => action.request),
|
||||
concatLatestFrom((request) => this.store.select(selectMaxZIndex(request.componentType))),
|
||||
filter(([request, maxZIndex]) => request.zIndex < maxZIndex),
|
||||
switchMap(([request, maxZIndex]) => {
|
||||
const updateRequest: UpdateComponentRequest = {
|
||||
id: request.id,
|
||||
type: request.componentType,
|
||||
uri: request.uri,
|
||||
payload: {
|
||||
revision: request.revision,
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
component: {
|
||||
id: request.id,
|
||||
zIndex: maxZIndex + 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return from(this.flowService.updateComponent(updateRequest)).pipe(
|
||||
map((response) => {
|
||||
const updateResponse: UpdateComponentResponse = {
|
||||
id: updateRequest.id,
|
||||
type: updateRequest.type,
|
||||
response
|
||||
};
|
||||
return FlowActions.updateComponentSuccess({ response: updateResponse });
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) =>
|
||||
of(FlowActions.flowSnackbarError({ error: errorResponse.error }))
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import { flowFeatureKey, FlowState, SelectedComponent } from './index';
|
|||
import { createSelector } from '@ngrx/store';
|
||||
import { CanvasState, selectCanvasState } from '../index';
|
||||
import { selectCurrentRoute } from '../../../../state/router/router.selectors';
|
||||
import { ComponentType } from '../../../../state/shared';
|
||||
|
||||
export const selectFlowState = createSelector(selectCanvasState, (state: CanvasState) => state[flowFeatureKey]);
|
||||
|
||||
|
@ -246,3 +247,15 @@ export const selectNavigationCollapsed = createSelector(
|
|||
);
|
||||
|
||||
export const selectOperationCollapsed = createSelector(selectFlowState, (state: FlowState) => state.operationCollapsed);
|
||||
|
||||
export const selectMaxZIndex = (componentType: ComponentType.Connection | ComponentType.Label) => {
|
||||
if (componentType === ComponentType.Connection) {
|
||||
return createSelector(selectConnections, (connections: any[]) =>
|
||||
connections.reduce((maxZIndex, connection) => Math.max(maxZIndex, connection.zIndex), -1)
|
||||
);
|
||||
} else {
|
||||
return createSelector(selectLabels, (labels: any[]) =>
|
||||
labels.reduce((maxZIndex, label) => Math.max(maxZIndex, label.zIndex), -1)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -739,3 +739,11 @@ export interface DownloadFlowRequest {
|
|||
processGroupId: string;
|
||||
includeReferencedServices: boolean;
|
||||
}
|
||||
|
||||
export interface MoveToFrontRequest {
|
||||
componentType: ComponentType.Connection | ComponentType.Label;
|
||||
id: string;
|
||||
uri: string;
|
||||
revision: Revision;
|
||||
zIndex: number;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue