NIFI-618:

- Adding a context menu item that allows users to move components out of a process group.
This commit is contained in:
Matt Gilman 2015-06-15 21:27:06 -04:00
parent 3295f7f193
commit f72fdcdb15
5 changed files with 110 additions and 49 deletions

View File

@ -1685,7 +1685,11 @@ public final class StandardProcessGroup implements ProcessGroup {
}
if (isRootGroup() && (!snippet.getInputPorts().isEmpty() || !snippet.getOutputPorts().isEmpty())) {
throw new IllegalStateException("Cannot move Ports from the Root Group to a Non-Root Group");
throw new IllegalStateException("Cannot move Ports out of the root group");
}
if (destination.isRootGroup() && (!snippet.getInputPorts().isEmpty() || !snippet.getOutputPorts().isEmpty())) {
throw new IllegalStateException("Cannot move Ports into the root group");
}
for (final String id : replaceNullWithEmptySet(snippet.getInputPorts())) {

View File

@ -914,6 +914,21 @@ nf.Actions = (function () {
});
},
/**
* Moves the currently selected component into the current parent group.
*/
moveIntoParent: function () {
var selection = nf.CanvasUtils.getSelection();
// ensure that components have been specified
if (selection.empty()) {
return;
}
// move the current selection into the parent group
nf.CanvasUtils.moveComponentsToParent(selection);
},
/**
* Creates a new template based off the currently selected components. If no components
* are selected, a template of the entire canvas is made.

View File

@ -51,6 +51,58 @@ nf.CanvasUtils = (function () {
return mid;
};
var moveComponents = function (components, groupId) {
return $.Deferred(function (deferred) {
// ensure the current selection is eligible for move into the specified group
nf.CanvasUtils.eligibleForMove(components, groupId).done(function () {
// create a snippet for the specified components and link to the data flow
var snippetDetails = nf.Snippet.marshal(components, true);
nf.Snippet.create(snippetDetails).done(function (response) {
var snippet = response.snippet;
// move the snippet into the target
nf.Snippet.move(snippet.id, groupId).done(function () {
var componentMap = d3.map();
// add the id to the type's array
var addComponent = function (type, id) {
if (!componentMap.has(type)) {
componentMap.set(type, []);
}
componentMap.get(type).push(id);
};
// go through each component being removed
components.each(function (d) {
addComponent(d.type, d.component.id);
});
// refresh all component types as necessary (handle components that have been removed)
componentMap.forEach(function (type, ids) {
nf[type].remove(ids);
});
// refresh the birdseye
nf.Birdseye.refresh();
deferred.resolve();
}).fail(nf.Common.handleAjaxError).fail(function () {
deferred.reject();
}).always(function () {
// unable to acutally move the components so attempt to
// unlink and remove just the snippet
nf.Snippet.unlink(snippet.id).done(function () {
nf.Snippet.remove(snippet.id);
});
});
}).fail(nf.Common.handleAjaxError).fail(function () {
deferred.reject();
});
}).fail(function () {
deferred.reject();
});
}).promise();
};
return {
config: {
systemTooltipConfig: {
@ -1025,6 +1077,22 @@ nf.CanvasUtils = (function () {
return origin;
},
/**
* Moves the specified components into the current parent group.
*
* @param {selection} components
*/
moveComponentsToParent: function (components) {
var groupId = nf.Canvas.getParentGroupId();
// if the group id is null, we're already in the top most group
if (groupId === null) {
nf.Dialog.showOkDialog('Components are already in the topmost group.');
} else {
moveComponents(components, groupId);
}
},
/**
* Moves the specified components into the specified group.
*
@ -1034,45 +1102,10 @@ nf.CanvasUtils = (function () {
moveComponents: function (components, group) {
var groupData = group.datum();
// ensure the current selection is eligible for move into the specified group
nf.CanvasUtils.eligibleForMove(components, group).done(function () {
// create a snippet for the specified components and link to the data flow
var snippetDetails = nf.Snippet.marshal(components, true);
nf.Snippet.create(snippetDetails).done(function (response) {
var snippet = response.snippet;
// move the snippet into the target
nf.Snippet.move(snippet.id, groupData.component.id).done(function () {
var componentMap = d3.map();
// add the id to the type's array
var addComponent = function (type, id) {
if (!componentMap.has(type)) {
componentMap.set(type, []);
}
componentMap.get(type).push(id);
};
// go through each component being removed
components.each(function (d) {
addComponent(d.type, d.component.id);
});
// refresh all component types as necessary (handle components that have been removed)
componentMap.forEach(function (type, ids) {
nf[type].remove(ids);
});
// move the components into the destination and...
moveComponents(components, groupData.component.id).done(function () {
// reload the target group
nf.ProcessGroup.reload(groupData.component);
}).fail(nf.Common.handleAjaxError).always(function () {
// unable to acutally move the components so attempt to
// unlink and remove just the snippet
nf.Snippet.unlink(snippet.id).done(function () {
nf.Snippet.remove(snippet.id);
});
});
}).fail(nf.Common.handleAjaxError);
});
},
@ -1161,15 +1194,15 @@ nf.CanvasUtils = (function () {
},
/**
* Ensures components are eligible to be moved. The new target can be optionally specified.
* Ensures components are eligible to be moved. The new group can be optionally specified.
*
* 1) Ensuring that the input and output ports are not connected outside of this group
* 2) If the target is specified; ensuring there are no port name conflicts in the target group
*
* @argument {selection} selection The selection being moved
* @argument {selection} group The selection containing the new group
* @argument {string} groupId The id of the new group
*/
eligibleForMove: function (selection, group) {
eligibleForMove: function (selection, groupId) {
var inputPorts = [];
var outputPorts = [];
@ -1191,7 +1224,7 @@ nf.CanvasUtils = (function () {
// ports in the root group cannot be moved
if (nf.Canvas.getParentGroupId() === null) {
nf.Dialog.showOkDialog({
dialogContent: 'Ports in the root group cannot be moved into another group.',
dialogContent: 'Cannot move Ports out of the root group',
overlayBackground: false
});
portConnectionDeferred.reject();
@ -1245,12 +1278,11 @@ nf.CanvasUtils = (function () {
// create a deferred for checking port names in the target
var portNameCheck = function () {
return $.Deferred(function (portNameDeferred) {
var groupData = group.datum();
// add the get request
$.ajax({
type: 'GET',
url: config.urls.controller + '/process-groups/' + encodeURIComponent(groupData.component.id),
url: config.urls.controller + '/process-groups/' + encodeURIComponent(groupId),
data: {
verbose: true
},
@ -1294,7 +1326,7 @@ nf.CanvasUtils = (function () {
// execute the checks in order
portConnectionCheck().done(function () {
if (nf.Common.isDefinedAndNotNull(group)) {
if (nf.Common.isDefinedAndNotNull(groupId)) {
$.when(portNameCheck()).done(function () {
deferred.resolve();
}).fail(function () {

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
/* global nf */
/* global nf, d3 */
nf.ContextMenu = (function () {
@ -277,6 +277,15 @@ nf.ContextMenu = (function () {
return nf.Common.isDFM() && nf.CanvasUtils.canAllStopTransmitting(selection);
};
/**
* Determines if the components in the specified selection can be moved into a parent group.
*
* @param {type} selection
*/
var canMoveToParent = function (selection) {
return !selection.empty() && nf.CanvasUtils.isDisconnected(selection) && nf.Canvas.getParentGroupId() !== null;
};
/**
* Adds a menu item to the context menu.
*
@ -363,6 +372,7 @@ nf.ContextMenu = (function () {
{condition: isNotConnection, menuItem: {img: 'images/iconCenterView.png', text: 'Center in view', action: 'center'}},
{condition: isCopyable, menuItem: {img: 'images/iconCopy.png', text: 'Copy', action: 'copy'}},
{condition: isPastable, menuItem: {img: 'images/iconPaste.png', text: 'Paste', action: 'paste'}},
{condition: canMoveToParent, menuItem: {img: 'images/iconMoveToParent.png', text: 'Move to parent group', action: 'moveIntoParent'}},
{condition: isDeletable, menuItem: {img: 'images/iconDelete.png', text: 'Delete', action: 'delete'}}
];