NIFI-475:

- Adding support to create controller services inline when editing a components properties.

NIFI-475:
- Adding support to create controller services inline when editing a components properties.

NIFI-475:
- Prompting the user to save changes before navigating to the controller service definition.

NIFI-475:
- Adding support to create controller services inline when editing a components properties.

NIFI-475:
- Adding support to create controller services inline when editing a components properties.

NIFI-475:
- Prompting the user to save changes before navigating to the controller service definition.

NIFI-475:
- Prompting the user to save changes before navigating to the controller service definition.

NIFI-475:
- Prompting the user to save changes before navigating to the controller service definition.

NIFI-475:
- Only providing the option to go to the service if the dialog is originating from the canvas (not for instance the summary page).

NIFI-475:
- Removing the children from the documented types. This prevents conveying the documented type hierarchies but that isn't necessary given the support for creating instances inline when editing properties.

NIFI-475:
- Removing the type hierarchies from the new controller service dialog.

NIFI-475:
- Including the controller service description in the inline controller service dialog.
This commit is contained in:
Matt Gilman 2015-04-06 16:29:07 -04:00
parent e456ea37f4
commit 2154b822bf
15 changed files with 655 additions and 593 deletions

View File

@ -26,7 +26,6 @@ import javax.xml.bind.annotation.XmlType;
public class DocumentedTypeDTO { public class DocumentedTypeDTO {
private String type; private String type;
private Set<DocumentedTypeDTO> childTypes;
private String description; private String description;
private Set<String> tags; private Set<String> tags;
@ -69,17 +68,4 @@ public class DocumentedTypeDTO {
this.tags = tags; this.tags = tags;
} }
/**
* Child types for this type.
*
* @return
*/
public Set<DocumentedTypeDTO> getChildTypes() {
return childTypes;
}
public void setChildTypes(Set<DocumentedTypeDTO> childTypes) {
this.childTypes = childTypes;
}
} }

View File

@ -34,7 +34,7 @@ public class PropertyDescriptorDTO {
private boolean sensitive; private boolean sensitive;
private boolean dynamic; private boolean dynamic;
private boolean supportsEl; private boolean supportsEl;
private boolean identifiesControllerService; private String identifiesControllerService;
/** /**
* The set of allowable values for this property. If empty then the * The set of allowable values for this property. If empty then the
@ -158,15 +158,16 @@ public class PropertyDescriptorDTO {
} }
/** /**
* Whether this descriptor represents a controller service. * If this property identifies a controller service, this returns the
* fully qualified type, null otherwise.
* *
* @return * @return
*/ */
public boolean isIdentifiesControllerService() { public String getIdentifiesControllerService() {
return identifiesControllerService; return identifiesControllerService;
} }
public void setIdentifiesControllerService(boolean identifiesControllerService) { public void setIdentifiesControllerService(String identifiesControllerService) {
this.identifiesControllerService = identifiesControllerService; this.identifiesControllerService = identifiesControllerService;
} }

View File

@ -252,9 +252,10 @@ public interface NiFiServiceFacade {
/** /**
* Returns the list of controller service types. * Returns the list of controller service types.
* *
* @param serviceType Filters only service types that implement this type
* @return The list of available controller types * @return The list of available controller types
*/ */
Set<DocumentedTypeDTO> getControllerServiceTypes(); Set<DocumentedTypeDTO> getControllerServiceTypes(String serviceType);
/** /**
* Returns the list of reporting task types. * Returns the list of reporting task types.

View File

@ -1718,8 +1718,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
} }
@Override @Override
public Set<DocumentedTypeDTO> getControllerServiceTypes() { public Set<DocumentedTypeDTO> getControllerServiceTypes(final String serviceType) {
return controllerFacade.getControllerServiceTypes(); return controllerFacade.getControllerServiceTypes(serviceType);
} }
@Override @Override

View File

@ -737,6 +737,7 @@ public class ControllerResource extends ApplicationResource {
* @param clientId Optional client id. If the client id is not specified, a * @param clientId Optional client id. If the client id is not specified, a
* new one will be generated. This value (whether specified or generated) is * new one will be generated. This value (whether specified or generated) is
* included in the response. * included in the response.
* @param serviceType Returns only services that implement this type
* @return A controllerServicesTypesEntity. * @return A controllerServicesTypesEntity.
*/ */
@GET @GET
@ -744,7 +745,9 @@ public class ControllerResource extends ApplicationResource {
@Path("/controller-service-types") @Path("/controller-service-types")
@PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')") @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@TypeHint(ControllerServiceTypesEntity.class) @TypeHint(ControllerServiceTypesEntity.class)
public Response getControllerServiceTypes(@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) { public Response getControllerServiceTypes(
@QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
@QueryParam("serviceType") String serviceType) {
// replicate if cluster manager // replicate if cluster manager
if (properties.isClusterManager()) { if (properties.isClusterManager()) {
@ -758,7 +761,7 @@ public class ControllerResource extends ApplicationResource {
// create response entity // create response entity
final ControllerServiceTypesEntity entity = new ControllerServiceTypesEntity(); final ControllerServiceTypesEntity entity = new ControllerServiceTypesEntity();
entity.setRevision(revision); entity.setRevision(revision);
entity.setControllerServiceTypes(serviceFacade.getControllerServiceTypes()); entity.setControllerServiceTypes(serviceFacade.getControllerServiceTypes(serviceType));
// generate the response // generate the response
return clusterContext(generateOkResponse(entity)).build(); return clusterContext(generateOkResponse(entity)).build();

View File

@ -1383,135 +1383,6 @@ public final class DtoFactory {
return types; return types;
} }
/**
* Identifies all baseTypes for the specified type that are assignable to the specified baseType.
*
* @param baseType
* @param type
* @param baseTypes
*/
private void identifyBaseTypes(final Class baseType, final Class type, final Set<Class> baseTypes, final boolean recurse) {
final Class[] interfaces = type.getInterfaces();
for (final Class i : interfaces) {
if (baseType.isAssignableFrom(i) && !baseType.equals(i)) {
baseTypes.add(i);
}
}
if (recurse) {
if (type.getSuperclass() != null) {
identifyBaseTypes(baseType, type.getSuperclass(), baseTypes, recurse);
}
}
}
/**
* Gets the DocumentedTypeDTOs from the specified classes for the specified baseClass.
*
* @param baseClass
* @param classes
* @return
*/
public Set<DocumentedTypeDTO> fromDocumentedTypes(final Class baseClass, final Set<Class> classes) {
final Set<DocumentedTypeDTO> types = new LinkedHashSet<>();
final Set<Class> sortedClasses = new TreeSet<>(CLASS_NAME_COMPARATOR);
sortedClasses.addAll(classes);
// identify all interfaces that extend baseClass for all classes
final Set<Class> interfaces = new HashSet<>();
for (final Class<?> cls : sortedClasses) {
identifyBaseTypes(baseClass, cls, interfaces, true);
}
// build a lookup of all interfaces
final Map<Class, DocumentedTypeDTO> lookup = new HashMap<>();
// convert the interfaces to DTO form
for (final Class<?> i : interfaces) {
final DocumentedTypeDTO type = new DocumentedTypeDTO();
type.setType(i.getName());
type.setDescription(getCapabilityDescription(i));
type.setTags(getTags(i));
type.setChildTypes(new LinkedHashSet<DocumentedTypeDTO>());
lookup.put(i, type);
}
// move the interfaces into the appropriate hierarchy
final Collection<Class> rootTypes = new ArrayList<>();
for (final Class<?> i : interfaces) {
rootTypes.add(i);
// identify the base types
final Set<Class> baseTypes = new LinkedHashSet<>();
identifyBaseTypes(baseClass, i, baseTypes, false);
// move this interfaces into the hierarchy where appropriate
if (!baseTypes.isEmpty()) {
// get the DTO for each base type
for (final Class baseType : baseTypes) {
final DocumentedTypeDTO parentInteface = lookup.get(baseType);
final DocumentedTypeDTO childInterface = lookup.get(i);
// include all parent tags in the respective children
childInterface.getTags().addAll(parentInteface.getTags());
// update the hierarchy
parentInteface.getChildTypes().add(childInterface);
}
// remove this interface from the lookup (this will only
// leave the interfaces that are ancestor roots)
rootTypes.remove(i);
}
}
// include the interfaces
sortedClasses.addAll(rootTypes);
// get the DTO form for all interfaces and classes
for (final Class<?> cls : sortedClasses) {
boolean add = false;
final DocumentedTypeDTO type;
if (rootTypes.contains(cls)) {
type = lookup.get(cls);
add = true;
} else {
type = new DocumentedTypeDTO();
type.setType(cls.getName());
type.setDescription(getCapabilityDescription(cls));
type.setTags(getTags(cls));
}
// identify the base types
final Set<Class> baseTypes = new LinkedHashSet<>();
identifyBaseTypes(baseClass, cls, baseTypes, false);
// include this type if it doesn't belong to another hierarchy
if (baseTypes.isEmpty()) {
add = true;
} else {
// get the DTO for each base type
for (final Class baseType : baseTypes) {
final DocumentedTypeDTO parentInterface = lookup.get(baseType);
// include all parent tags in the respective children
type.getTags().addAll(parentInterface.getTags());
// update the hierarchy
parentInterface.getChildTypes().add(type);
}
}
// add if appropriate
if (add) {
types.add(type);
}
}
return types;
}
/** /**
* Creates a ProcessorDTO from the specified ProcessorNode. * Creates a ProcessorDTO from the specified ProcessorNode.
* *
@ -1958,7 +1829,11 @@ public final class DtoFactory {
dto.setDescription(propertyDescriptor.getDescription()); dto.setDescription(propertyDescriptor.getDescription());
dto.setDefaultValue(propertyDescriptor.getDefaultValue()); dto.setDefaultValue(propertyDescriptor.getDefaultValue());
dto.setSupportsEl(propertyDescriptor.isExpressionLanguageSupported()); dto.setSupportsEl(propertyDescriptor.isExpressionLanguageSupported());
dto.setIdentifiesControllerService(propertyDescriptor.getControllerServiceDefinition() != null);
// set the identifies controller service is applicable
if (propertyDescriptor.getControllerServiceDefinition() != null) {
dto.setIdentifiesControllerService(propertyDescriptor.getControllerServiceDefinition().getName());
}
final Class<? extends ControllerService> serviceDefinition = propertyDescriptor.getControllerServiceDefinition(); final Class<? extends ControllerService> serviceDefinition = propertyDescriptor.getControllerServiceDefinition();
if (propertyDescriptor.getAllowableValues() == null) { if (propertyDescriptor.getAllowableValues() == null) {

View File

@ -108,6 +108,7 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO; import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.DownloadableContent; import org.apache.nifi.web.DownloadableContent;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.admin.service.UserService; import org.apache.nifi.admin.service.UserService;
import org.apache.nifi.authorization.DownloadAuthorization; import org.apache.nifi.authorization.DownloadAuthorization;
@ -348,12 +349,48 @@ public class ControllerFacade {
} }
/** /**
* Gets the ControllerService types that this controller supports. * Returns whether the specified type implements the specified serviceType.
* *
* @param baseType
* @param type
* @return * @return
*/ */
public Set<DocumentedTypeDTO> getControllerServiceTypes() { private boolean implementsServiceType(final String serviceType, final Class type) {
return dtoFactory.fromDocumentedTypes(ControllerService.class, ExtensionManager.getExtensions(ControllerService.class)); final List<Class<?>> interfaces = ClassUtils.getAllInterfaces(type);
for (final Class i : interfaces) {
if (ControllerService.class.isAssignableFrom(i) && i.getName().equals(serviceType)) {
return true;
}
}
return false;
}
/**
* Gets the ControllerService types that this controller supports.
*
* @param serviceType
* @return
*/
public Set<DocumentedTypeDTO> getControllerServiceTypes(final String serviceType) {
final Set<Class> serviceImplementations = ExtensionManager.getExtensions(ControllerService.class);
// identify the controller services that implement the specified serviceType if applicable
final Set<Class> matchingServiceImplementions;
if (serviceType != null) {
matchingServiceImplementions = new HashSet<>();
// check each type and remove those that aren't in the specified ancestry
for (final Class type : serviceImplementations) {
if (implementsServiceType(serviceType, type)) {
matchingServiceImplementions.add(type);
}
}
} else {
matchingServiceImplementions = serviceImplementations;
}
return dtoFactory.fromDocumentedTypes(matchingServiceImplementions);
} }
/** /**
@ -362,7 +399,7 @@ public class ControllerFacade {
* @return * @return
*/ */
public Set<DocumentedTypeDTO> getReportingTaskTypes() { public Set<DocumentedTypeDTO> getReportingTaskTypes() {
return dtoFactory.fromDocumentedTypes(ReportingTask.class, ExtensionManager.getExtensions(ReportingTask.class)); return dtoFactory.fromDocumentedTypes(ExtensionManager.getExtensions(ReportingTask.class));
} }
/** /**

View File

@ -222,7 +222,7 @@ public final class SnippetUtils {
} }
final PropertyDescriptorDTO propertyDescriptorDto = descriptors.get(propName); final PropertyDescriptorDTO propertyDescriptorDto = descriptors.get(propName);
if ( propertyDescriptorDto != null && propertyDescriptorDto.isIdentifiesControllerService() ) { if ( propertyDescriptorDto != null && propertyDescriptorDto.getIdentifiesControllerService() != null ) {
final ControllerServiceNode serviceNode = flowController.getControllerServiceNode(propValue); final ControllerServiceNode serviceNode = flowController.getControllerServiceNode(propValue);
if ( serviceNode != null ) { if ( serviceNode != null ) {
addControllerServicesToSnippet(snippet, serviceNode); addControllerServicesToSnippet(snippet, serviceNode);
@ -363,7 +363,7 @@ public final class SnippetUtils {
final Map<String, PropertyDescriptorDTO> descriptors = serviceDTO.getDescriptors(); final Map<String, PropertyDescriptorDTO> descriptors = serviceDTO.getDescriptors();
if ( properties != null && descriptors != null ) { if ( properties != null && descriptors != null ) {
for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) { for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) {
if ( descriptor.isIdentifiesControllerService() ) { if ( descriptor.getIdentifiesControllerService() != null ) {
final String currentServiceId = properties.get(descriptor.getName()); final String currentServiceId = properties.get(descriptor.getName());
if ( currentServiceId == null ) { if ( currentServiceId == null ) {
continue; continue;
@ -558,7 +558,7 @@ public final class SnippetUtils {
final Map<String, PropertyDescriptorDTO> descriptors = configDto.getDescriptors(); final Map<String, PropertyDescriptorDTO> descriptors = configDto.getDescriptors();
if ( properties != null && descriptors != null ) { if ( properties != null && descriptors != null ) {
for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) { for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) {
if ( descriptor.isIdentifiesControllerService() ) { if ( descriptor.getIdentifiesControllerService() != null ) {
final String currentServiceId = properties.get(descriptor.getName()); final String currentServiceId = properties.get(descriptor.getName());
if ( currentServiceId == null ) { if ( currentServiceId == null ) {
continue; continue;

View File

@ -43,21 +43,6 @@
cursor: pointer; cursor: pointer;
} }
span.expansion-button {
width: 10px;
height: 10px;
float: left;
}
span.ancestor-type {
font-weight: bold;
}
span.ancestor-type-rollup {
margin-left: 3px;
color: #aaa;
}
/* settings tabs */ /* settings tabs */
#settings-tabs-container { #settings-tabs-container {

View File

@ -103,6 +103,49 @@ div.new-property-button-container {
padding: 0 8px 10px; padding: 0 8px 10px;
} }
/*
New inline controller service dialog
*/
div.new-inline-controller-service-dialog {
z-index: 1301;
display: none;
padding: 10px;
border: 3px solid #365C6A;
box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.9);
cursor: move;
width: 350px;
height: 250px;
}
div.new-inline-controller-service-combo {
height: 18px;
width: 340px;
margin-bottom: 10px;
}
div.new-inline-controller-service-tags {
height: 18px;
width: 340px;
margin-bottom: 10px;
overflow: hidden;
white-space: nowrap;
}
div.new-inline-controller-service-description {
height: 115px;
width: 340px;
overflow: auto;
}
div.new-inline-controller-service-button-container {
position: absolute;
left: 0;
bottom: 0;
right: 0;
padding: 0 8px 10px;
}
/* /*
Styles for the property editor. Styles for the property editor.
*/ */

View File

@ -23,7 +23,17 @@
* *
* { * {
* readOnly: true, * readOnly: true,
* newPropertyDialogContainer: 'body' * dialogContainer: 'body',
* descriptorDeferred: function () {
* return $.Deferred(function (deferred) {
* deferred.resolve();
* }).promise;
* },
* goToServiceDeferred: function () {
* return $.Deferred(function (deferred) {
* deferred.resolve();
* }).promise;
* }
* } * }
*/ */
@ -444,6 +454,10 @@
var descriptors = gridContainer.data('descriptors'); var descriptors = gridContainer.data('descriptors');
propertyDescriptor = descriptors[args.item.property]; propertyDescriptor = descriptors[args.item.property];
// get the options
var propertyContainer = gridContainer.closest('.property-container');
var configurationOptions = propertyContainer.data('options');
// create the wrapper // create the wrapper
wrapper = $('<div></div>').css({ wrapper = $('<div></div>').css({
'z-index': 1999, 'z-index': 1999,
@ -491,6 +505,15 @@
}); });
} }
// if this descriptor identifies a controller service, provide a way to create one
if (nf.Common.isDefinedAndNotNull(propertyDescriptor.identifiesControllerService)) {
options.push({
text: 'Create new service...',
value: undefined,
optionClass: 'unset'
});
}
// determine the max height // determine the max height
var position = args.position; var position = args.position;
var windowHeight = $(window).height(); var windowHeight = $(window).height();
@ -499,7 +522,16 @@
// build the combo field // build the combo field
combo = $('<div class="value-combo combo"></div>').combo({ combo = $('<div class="value-combo combo"></div>').combo({
options: options, options: options,
maxHeight: maxHeight maxHeight: maxHeight,
select: function (option) {
if (typeof option.value === 'undefined') {
// cancel the current edit
scope.cancel();
// prompt for the new service type
promptForNewControllerService(gridContainer, args.grid, args.item, propertyDescriptor.identifiesControllerService, configurationOptions);
}
}
}).width(position.width - 16).appendTo(wrapper); }).width(position.width - 16).appendTo(wrapper);
// add buttons for handling user input // add buttons for handling user input
@ -745,6 +777,154 @@
} }
}; };
/**
* Gets the available controller services that implement the specified type and
* prompts the user to create one.
*
* @param {jQuery} gridContainer The grid container
* @param {slickgrid} grid The grid
* @param {object} item The item
* @param {type} serviceType The type of service to create
* @param {object} configurationOptions The configuration options
*/
var promptForNewControllerService = function (gridContainer, grid, item, serviceType, configurationOptions) {
$.ajax({
type: 'GET',
url: '../nifi-api/controller/controller-service-types',
data: {
serviceType: serviceType
},
dataType: 'json'
}).done(function (response) {
var options = [];
$.each(response.controllerServiceTypes, function (i, controllerServiceType) {
options.push({
text: nf.Common.substringAfterLast(controllerServiceType.type, '.'),
value: controllerServiceType.type,
description: nf.Common.escapeHtml(controllerServiceType.description)
});
});
// ensure there are some applicable controller services
if (options.length === 0) {
nf.Dialog.showOkDialog({
dialogContent: 'No controller service types found that are applicable for this property.',
overlayBackground: false
});
} else {
var newControllerServiceDialogMarkup =
'<div class="new-inline-controller-service-dialog dialog cancellable">' +
'<div>' +
'<div class="setting-name">Controller Service</div>' +
'<div class="setting-field">' +
'<div class="new-inline-controller-service-combo"></div>' +
'</div>' +
'</div>' +
'<div>' +
'<div class="setting-name">Tags</div>' +
'<div class="setting-field">' +
'<div class="new-inline-controller-service-tags"></div>' +
'</div>' +
'</div>' +
'<div>' +
'<div class="setting-name">Description</div>' +
'<div class="setting-field">' +
'<div class="new-inline-controller-service-description"></div>' +
'</div>' +
'</div>' +
'<div class="new-inline-controller-service-button-container">' +
'<div class="new-inline-controller-service-create button button-normal">Create</div>' +
'<div class="new-inline-controller-service-cancel button button-normal">Cancel</div>' +
'<div class="clear"></div>' +
'</div>' +
'</div>';
var newControllerServiceDialog = $(newControllerServiceDialogMarkup).appendTo(configurationOptions.dialogContainer);
var newControllerServiceCombo = newControllerServiceDialog.find('div.new-inline-controller-service-combo');
var newControllerServiceTags = newControllerServiceDialog.find('div.new-inline-controller-service-tags');
var newControllerServiceDescription = newControllerServiceDialog.find('div.new-inline-controller-service-description');
// build the combo field
newControllerServiceCombo.combo({
options: options,
select: function (option) {
var service;
$.each(response.controllerServiceTypes, function (i, controllerServiceType) {
if (controllerServiceType.type === option.value) {
service = controllerServiceType;
return false;
}
});
// set the service details
newControllerServiceTags.text(service.tags.join(', ')).ellipsis();
newControllerServiceDescription.text(service.description);
}
});
var create = function () {
var newControllerServiceType = newControllerServiceCombo.combo('getSelectedOption').value;
// create service of the specified type
var revision = nf.Client.getRevision();
// add the new controller service
$.ajax({
type: 'POST',
url: '../nifi-api/controller/controller-services/node',
data: {
version: revision.version,
clientId: revision.clientId,
type: newControllerServiceType
},
dataType: 'json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
$.Deferred(function (deferred) {
// load the property descriptor if possible
if (typeof configurationOptions.descriptorDeferred === 'function') {
configurationOptions.descriptorDeferred(item.property).done(function(response) {
var descriptor = response.propertyDescriptor;
// store the descriptor for use later
var descriptors = gridContainer.data('descriptors');
if (!nf.Common.isUndefined(descriptors)) {
descriptors[descriptor.name] = descriptor;
}
deferred.resolve();
});
} else {
deferred.resolve();
}
}).done(function() {
// add a row for the new property
var data = grid.getData();
data.updateItem(item.id, $.extend(item, {
value: response.controllerService.id
}));
// close the dialog
newControllerServiceDialog.hide();
});
}).fail(nf.Common.handleAjaxError);
};
var cancel = function () {
newControllerServiceDialog.hide();
};
// make the new property dialog draggable
newControllerServiceDialog.draggable({
cancel: 'input, textarea, pre, .button, .' + editorClass,
containment: 'body'
}).on('click', 'div.new-inline-controller-service-create', create).on('click', 'div.new-inline-controller-service-cancel', cancel).modal('show');
}
}).fail(nf.Common.handleAjaxError);
};
var initPropertiesTable = function (table, options) { var initPropertiesTable = function (table, options) {
// function for formatting the property name // function for formatting the property name
var nameFormatter = function (row, cell, value, columnDef, dataContext) { var nameFormatter = function (row, cell, value, columnDef, dataContext) {
@ -826,20 +1006,37 @@
{id: 'value', field: 'value', name: 'Value', sortable: false, resizable: true, cssClass: 'pointer', rerenderOnResize: true, formatter: valueFormatter} {id: 'value', field: 'value', name: 'Value', sortable: false, resizable: true, cssClass: 'pointer', rerenderOnResize: true, formatter: valueFormatter}
]; ];
if (options.readOnly !== true) {
// custom formatter for the actions column // custom formatter for the actions column
var actionFormatter = function (row, cell, value, columnDef, dataContext) { var actionFormatter = function (row, cell, value, columnDef, dataContext) {
var markup = ''; var markup = '';
// get the property descriptor
var descriptors = table.data('descriptors');
var propertyDescriptor = descriptors[dataContext.property];
var identifiesControllerService = nf.Common.isDefinedAndNotNull(propertyDescriptor.identifiesControllerService);
var isConfigured = nf.Common.isDefinedAndNotNull(dataContext.value);
var isOnCanvas = nf.Common.isDefinedAndNotNull(nf.Canvas);
// check to see if we should provide a button for going to a controller service
if (identifiesControllerService && isConfigured && isOnCanvas) {
// ensure the configured value is referencing a valid service
$.each(propertyDescriptor.allowableValues, function (_, allowableValue) {
if (allowableValue.value === dataContext.value) {
markup = '<img src="images/iconGoTo.png" title="Go To" class="go-to-service pointer" style="margin-top: 2px" />';
return false;
}
});
}
// allow user defined properties to be removed // allow user defined properties to be removed
if (dataContext.type === 'userDefined') { if (options.readOnly !== true && dataContext.type === 'userDefined') {
markup = '<img src="images/iconDelete.png" title="Delete" class="delete-property pointer" style="margin-top: 2px" />'; markup = '<img src="images/iconDelete.png" title="Delete" class="delete-property pointer" style="margin-top: 2px" />';
} }
return markup; return markup;
}; };
propertyColumns.push({id: "actions", name: "&nbsp;", minWidth: 20, width: 20, formatter: actionFormatter}); propertyColumns.push({id: "actions", name: "&nbsp;", minWidth: 20, width: 20, formatter: actionFormatter});
}
var propertyConfigurationOptions = { var propertyConfigurationOptions = {
forceFitColumns: true, forceFitColumns: true,
@ -900,6 +1097,39 @@
} }
}; };
var goToControllerService = function (property) {
// close the dialog
var dialog = table.closest('.dialog');
if (dialog.hasClass('modal')) {
dialog.modal('hide');
} else {
dialog.hide();
}
$.Deferred(function (deferred) {
if ($('#settings').is(':visible')) {
deferred.resolve();
} else {
// reload the settings and show
nf.Settings.loadSettings().done(function () {
nf.Settings.showSettings();
deferred.resolve();
});
}
}).done(function () {
var controllerServiceGrid = $('#controller-services-table').data('gridInstance');
var controllerServiceData = controllerServiceGrid.getData();
// select the desired service
var row = controllerServiceData.getRowById(property.value);
controllerServiceGrid.setSelectedRows([row]);
controllerServiceGrid.scrollRowIntoView(row);
// select the controller services tab
$('#settings-tabs').find('li:eq(1)').click();
});
};
// initialize the grid // initialize the grid
var propertyGrid = new Slick.Grid(table, propertyData, propertyColumns, propertyConfigurationOptions); var propertyGrid = new Slick.Grid(table, propertyData, propertyColumns, propertyConfigurationOptions);
propertyGrid.setSelectionModel(new Slick.RowSelectionModel()); propertyGrid.setSelectionModel(new Slick.RowSelectionModel());
@ -916,10 +1146,11 @@
// prevents standard edit logic // prevents standard edit logic
e.stopImmediatePropagation(); e.stopImmediatePropagation();
} else if (propertyGrid.getColumns()[args.cell].id === 'actions') { } else if (propertyGrid.getColumns()[args.cell].id === 'actions') {
var property = propertyData.getItem(args.row);
var target = $(e.target); var target = $(e.target);
if (target.hasClass('delete-property')) { if (target.hasClass('delete-property')) {
// mark the property in question for removal // mark the property in question for removal
var property = propertyData.getItem(args.row);
property.hidden = true; property.hidden = true;
// refresh the table // refresh the table
@ -927,6 +1158,17 @@
// prevents standard edit logic // prevents standard edit logic
e.stopImmediatePropagation(); e.stopImmediatePropagation();
} else if (target.hasClass('go-to-service')) {
if (options.readOnly === true) {
goToControllerService(property);
} else {
// load the property descriptor if possible
if (typeof options.goToServiceDeferred === 'function') {
options.goToServiceDeferred().done(function() {
goToControllerService(property);
});
}
}
} }
} }
}); });
@ -1076,8 +1318,8 @@
nf.Common.removeAllPropertyDetailDialogs(); nf.Common.removeAllPropertyDetailDialogs();
} else { } else {
// clear any existing new property dialogs // clear any existing new property dialogs
if (nf.Common.isDefinedAndNotNull(options.newPropertyDialogContainer)) { if (nf.Common.isDefinedAndNotNull(options.dialogContainer)) {
$(options.newPropertyDialogContainer).children('div.new-property-dialog').hide(); $(options.dialogContainer).children('div.new-property-dialog').hide();
} }
} }
@ -1108,7 +1350,7 @@
var propertyTableContainer = $(this); var propertyTableContainer = $(this);
// clear any current contents, remote events, and store options // clear any current contents, remote events, and store options
propertyTableContainer.empty().unbind().data('options', options); propertyTableContainer.empty().unbind().addClass('property-container').data('options', options);
// build the component // build the component
var header = $('<div class="properties-header"></div>').appendTo(propertyTableContainer); var header = $('<div class="properties-header"></div>').appendTo(propertyTableContainer);
@ -1118,7 +1360,7 @@
var table = $('<div class="property-table"></div>').appendTo(propertyTableContainer); var table = $('<div class="property-table"></div>').appendTo(propertyTableContainer);
// optionally add a add new property button // optionally add a add new property button
if (options.readOnly !== true && nf.Common.isDefinedAndNotNull(options.newPropertyDialogContainer)) { if (options.readOnly !== true && nf.Common.isDefinedAndNotNull(options.dialogContainer)) {
// build the new property dialog // build the new property dialog
var newPropertyDialogMarkup = var newPropertyDialogMarkup =
'<div class="new-property-dialog dialog cancellable">' + '<div class="new-property-dialog dialog cancellable">' +
@ -1135,7 +1377,7 @@
'</div>' + '</div>' +
'</div>'; '</div>';
var newPropertyDialog = $(newPropertyDialogMarkup).appendTo(options.newPropertyDialogContainer); var newPropertyDialog = $(newPropertyDialogMarkup).appendTo(options.dialogContainer);
var newPropertyNameField = newPropertyDialog.find('input.new-property-name'); var newPropertyNameField = newPropertyDialog.find('input.new-property-name');
var add = function () { var add = function () {
@ -1295,8 +1537,9 @@
clear(propertyTableContainer); clear(propertyTableContainer);
// clear any existing new property dialogs // clear any existing new property dialogs
if (nf.Common.isDefinedAndNotNull(options.newPropertyDialogContainer)) { if (nf.Common.isDefinedAndNotNull(options.dialogContainer)) {
$(options.newPropertyDialogContainer).children('div.new-property-dialog').remove(); $(options.dialogContainer).children('div.new-property-dialog').remove();
$(options.dialogContainer).children('div.new-inline-controller-service-dialog').remove();
} }
}); });
}, },

View File

@ -374,6 +374,7 @@ nf.ControllerService = (function () {
// select the selected row // select the selected row
var row = controllerServiceData.getRowById(referencingComponent.id); var row = controllerServiceData.getRowById(referencingComponent.id);
controllerServiceGrid.setSelectedRows([row]); controllerServiceGrid.setSelectedRows([row]);
controllerServiceGrid.scrollRowIntoView(row);
// close the dialog and shell // close the dialog and shell
referenceContainer.closest('.dialog').modal('hide'); referenceContainer.closest('.dialog').modal('hide');
@ -419,6 +420,7 @@ nf.ControllerService = (function () {
// select the selected row // select the selected row
var row = reportingTaskData.getRowById(referencingComponent.id); var row = reportingTaskData.getRowById(referencingComponent.id);
reportingTaskGrid.setSelectedRows([row]); reportingTaskGrid.setSelectedRows([row]);
reportingTaskGrid.scrollRowIntoView(row);
// select the reporting task tab // select the reporting task tab
$('#settings-tabs').find('li:last').click(); $('#settings-tabs').find('li:last').click();
@ -1069,6 +1071,83 @@ nf.ControllerService = (function () {
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
}; };
/**
* Goes to a service configuration from the property table.
*/
var goToServiceFromProperty = function () {
return $.Deferred(function (deferred) {
// close all fields currently being edited
$('#controller-service-properties').propertytable('saveRow');
// determine if changes have been made
if (isSaveRequired()) {
// see if those changes should be saved
nf.Dialog.showYesNoDialog({
dialogContent: 'Save changes before going to this Controller Service?',
overlayBackground: false,
noHandler: function () {
deferred.resolve();
},
yesHandler: function () {
var controllerService = $('#controller-service-configuration').data('controllerServiceDetails');
saveControllerService(controllerService).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();
});
}
});
} else {
deferred.resolve();
}
}).promise();
};
var saveControllerService = function (controllerService) {
// marshal the settings and properties and update the controller service
var updatedControllerService = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedControllerService)) {
var previouslyReferencedServiceIds = [];
$.each(identifyReferencedServiceDescriptors(controllerService), function (_, descriptor) {
var modifyingService = !nf.Common.isUndefined(updatedControllerService.controllerService.properties) && !nf.Common.isUndefined(updatedControllerService.controllerService.properties[descriptor.name]);
var isCurrentlyConfigured = nf.Common.isDefinedAndNotNull(controllerService.properties[descriptor.name]);
// if we are attempting to update a controller service reference
if (modifyingService && isCurrentlyConfigured) {
// record the current value if set
previouslyReferencedServiceIds.push(controllerService.properties[descriptor.name]);
}
});
// update the selected component
return $.ajax({
type: 'PUT',
data: JSON.stringify(updatedControllerService),
url: controllerService.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
// update the revision
nf.Client.setRevision(response.revision);
// reload all previously referenced controller services
$.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
reloadControllerService(oldServiceReferenceId);
});
}
}).fail(handleControllerServiceConfigurationError);
} else {
return $.Deferred(function (deferred) {
deferred.reject();
}).promise();
}
};
/** /**
* Identifies the descriptors that identify controller services. * Identifies the descriptors that identify controller services.
* *
@ -1078,7 +1157,7 @@ nf.ControllerService = (function () {
var referencedServiceDescriptors = []; var referencedServiceDescriptors = [];
$.each(component.descriptors, function(_, descriptor) { $.each(component.descriptors, function(_, descriptor) {
if (descriptor.identifiesControllerService === true) { if (nf.Common.isDefinedAndNotNull(descriptor.identifiesControllerService)) {
referencedServiceDescriptors.push(descriptor); referencedServiceDescriptors.push(descriptor);
} }
}); });
@ -1180,8 +1259,9 @@ nf.ControllerService = (function () {
// initialize the property table // initialize the property table
$('#controller-service-properties').propertytable({ $('#controller-service-properties').propertytable({
readOnly: false, readOnly: false,
newPropertyDialogContainer: '#new-controller-service-property-container', dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
}); });
// initialize the disable service dialog // initialize the disable service dialog
@ -1324,8 +1404,9 @@ nf.ControllerService = (function () {
// initialize the property table // initialize the property table
$('#controller-service-properties').propertytable('destroy').propertytable({ $('#controller-service-properties').propertytable('destroy').propertytable({
readOnly: false, readOnly: false,
newPropertyDialogContainer: '#new-controller-service-property-container', dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
}); });
// update the mode // update the mode
@ -1392,49 +1473,15 @@ nf.ControllerService = (function () {
// close all fields currently being edited // close all fields currently being edited
$('#controller-service-properties').propertytable('saveRow'); $('#controller-service-properties').propertytable('saveRow');
// marshal the settings and properties and update the controller service // save the controller service
var updatedControllerService = marshalDetails(); saveControllerService(controllerService).done(function (response) {
// ensure details are valid as far as we can tell
if (validateDetails(updatedControllerService)) {
var previouslyReferencedServiceIds = [];
$.each(identifyReferencedServiceDescriptors(controllerService), function (_, descriptor) {
var modifyingService = !nf.Common.isUndefined(updatedControllerService.controllerService.properties) && !nf.Common.isUndefined(updatedControllerService.controllerService.properties[descriptor.name]);
var isCurrentlyConfigured = nf.Common.isDefinedAndNotNull(controllerService.properties[descriptor.name]);
// if we are attempting to update a controller service reference
if (modifyingService && isCurrentlyConfigured) {
// record the current value if set
previouslyReferencedServiceIds.push(controllerService.properties[descriptor.name]);
}
});
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedControllerService),
url: controllerService.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
nf.Client.setRevision(response.revision);
// reload the controller service // reload the controller service
renderControllerService(response.controllerService); renderControllerService(response.controllerService);
reloadControllerServiceReferences(response.controllerService); reloadControllerServiceReferences(response.controllerService);
// reload all previously referenced controller services
$.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
reloadControllerService(oldServiceReferenceId);
});
// close the details panel // close the details panel
controllerServiceDialog.modal('hide'); controllerServiceDialog.modal('hide');
} });
}).fail(handleControllerServiceConfigurationError);
}
} }
} }
}, { }, {
@ -1480,47 +1527,10 @@ nf.ControllerService = (function () {
overlayBackground: false, overlayBackground: false,
noHandler: openCustomUi, noHandler: openCustomUi,
yesHandler: function () { yesHandler: function () {
// marshal the settings and properties and update the controller service saveControllerService(controllerService).done(function () {
var updatedControllerService = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedControllerService)) {
var previouslyReferencedServiceIds = [];
$.each(identifyReferencedServiceDescriptors(controllerService), function (_, descriptor) {
var modifyingService = !nf.Common.isUndefined(updatedControllerService.controllerService.properties) && !nf.Common.isUndefined(updatedControllerService.controllerService.properties[descriptor.name]);
var isCurrentlyConfigured = nf.Common.isDefinedAndNotNull(controllerService.properties[descriptor.name]);
// if we are attempting to update a controller service reference
if (modifyingService && isCurrentlyConfigured) {
// record the current value if set
previouslyReferencedServiceIds.push(controllerService.properties[descriptor.name]);
}
});
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedControllerService),
url: controllerService.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
// update the revision
nf.Client.setRevision(response.revision);
// reload all previously referenced controller services
$.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
reloadControllerService(oldServiceReferenceId);
});
// open the custom ui // open the custom ui
openCustomUi(); openCustomUi();
} });
}).fail(handleControllerServiceConfigurationError);
}
} }
}); });
} else { } else {

View File

@ -381,6 +381,70 @@ nf.ProcessorConfiguration = (function () {
}); });
}; };
/**
* Goes to a service configuration from the property table.
*/
var goToServiceFromProperty = function () {
return $.Deferred(function (deferred) {
// close all fields currently being edited
$('#processor-properties').propertytable('saveRow');
// determine if changes have been made
if (isSaveRequired()) {
// see if those changes should be saved
nf.Dialog.showYesNoDialog({
dialogContent: 'Save changes before going to this Controller Service?',
overlayBackground: false,
noHandler: function () {
deferred.resolve();
},
yesHandler: function () {
var processor = $('#processor-configuration').data('processorDetails');
saveProcessor(processor).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();
});
}
});
} else {
deferred.resolve();
}
}).promise();
};
/**
*
* @param {type} processor
* @returns {undefined}
*/
var saveProcessor = function (processor) {
// marshal the settings and properties and update the processor
var updatedProcessor = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedProcessor)) {
// update the selected component
return $.ajax({
type: 'PUT',
data: JSON.stringify(updatedProcessor),
url: processor.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.processor)) {
// update the revision
nf.Client.setRevision(response.revision);
}
}).fail(handleProcessorConfigurationError);
} else {
return $.Deferred(function (deferred) {
deferred.reject();
}).promise();
}
};
return { return {
/** /**
* Initializes the processor properties tab. * Initializes the processor properties tab.
@ -470,7 +534,7 @@ nf.ProcessorConfiguration = (function () {
// initialize the property table // initialize the property table
$('#processor-properties').propertytable({ $('#processor-properties').propertytable({
readOnly: false, readOnly: false,
newPropertyDialogContainer: '#new-processor-property-container', dialogContainer: '#new-processor-property-container',
descriptorDeferred: function(propertyName) { descriptorDeferred: function(propertyName) {
var processor = $('#processor-configuration').data('processorDetails'); var processor = $('#processor-configuration').data('processorDetails');
return $.ajax({ return $.ajax({
@ -481,7 +545,8 @@ nf.ProcessorConfiguration = (function () {
}, },
dataType: 'json' dataType: 'json'
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
} },
goToServiceDeferred: goToServiceFromProperty
}); });
}, },
@ -625,24 +690,8 @@ nf.ProcessorConfiguration = (function () {
// close all fields currently being edited // close all fields currently being edited
$('#processor-properties').propertytable('saveRow'); $('#processor-properties').propertytable('saveRow');
// marshal the settings and properties and update the processor // save the processor
var updatedProcessor = marshalDetails(); saveProcessor(processor).done(function (response) {
// ensure details are valid as far as we can tell
if (validateDetails(updatedProcessor)) {
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedProcessor),
url: processor.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.processor)) {
// update the revision
nf.Client.setRevision(response.revision);
// set the new processor state based on the response // set the new processor state based on the response
nf.Processor.set(response.processor); nf.Processor.set(response.processor);
@ -651,9 +700,7 @@ nf.ProcessorConfiguration = (function () {
// close the details panel // close the details panel
$('#processor-configuration').modal('hide'); $('#processor-configuration').modal('hide');
} });
}).fail(handleProcessorConfigurationError);
}
} }
} }
}, { }, {
@ -696,29 +743,10 @@ nf.ProcessorConfiguration = (function () {
overlayBackground: false, overlayBackground: false,
noHandler: openCustomUi, noHandler: openCustomUi,
yesHandler: function () { yesHandler: function () {
// marshal the settings and properties and update the processor saveProcessor(processor).done(function (deferred) {
var updatedProcessor = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedProcessor)) {
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedProcessor),
url: processor.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.processor)) {
// update the revision
nf.Client.setRevision(response.revision);
// open the custom ui // open the custom ui
openCustomUi(); openCustomUi();
} });
}).fail(handleProcessorConfigurationError);
}
} }
}); });
} else { } else {

View File

@ -206,6 +206,70 @@ nf.ReportingTask = (function () {
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
}; };
/**
* Goes to a service configuration from the property table.
*/
var goToServiceFromProperty = function () {
return $.Deferred(function (deferred) {
// close all fields currently being edited
$('#reporting-task-properties').propertytable('saveRow');
// determine if changes have been made
if (isSaveRequired()) {
// see if those changes should be saved
nf.Dialog.showYesNoDialog({
dialogContent: 'Save changes before going to this Controller Service?',
overlayBackground: false,
noHandler: function () {
deferred.resolve();
},
yesHandler: function () {
var reportingTask = $('#reporting-task-configuration').data('reportingTaskDetails');
saveReportingTask(reportingTask).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();
});
}
});
} else {
deferred.resolve();
}
}).promise();
};
/**
* Saves the specified reporting task.
*
* @param {type} reportingTask
*/
var saveReportingTask = function (reportingTask) {
// marshal the settings and properties and update the reporting task
var updatedReportingTask = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedReportingTask)) {
// update the selected component
return $.ajax({
type: 'PUT',
data: JSON.stringify(updatedReportingTask),
url: reportingTask.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.reportingTask)) {
// update the revision
nf.Client.setRevision(response.revision);
}
}).fail(handleReportingTaskConfigurationError);
} else {
return $.Deferred(function (deferred) {
deferred.reject();
}).promise();
}
};
/** /**
* Gets a property descriptor for the controller service currently being configured. * Gets a property descriptor for the controller service currently being configured.
* *
@ -288,8 +352,9 @@ nf.ReportingTask = (function () {
// initialize the property table // initialize the property table
$('#reporting-task-properties').propertytable({ $('#reporting-task-properties').propertytable({
readOnly: false, readOnly: false,
newPropertyDialogContainer: '#new-reporting-task-property-container', dialogContainer: '#new-reporting-task-property-container',
deferredDescriptor: getReportingTaskPropertyDescriptor deferredDescriptor: getReportingTaskPropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
}); });
}, },
@ -308,8 +373,9 @@ nf.ReportingTask = (function () {
// initialize the property table // initialize the property table
$('#reporting-task-properties').propertytable('destroy').propertytable({ $('#reporting-task-properties').propertytable('destroy').propertytable({
readOnly: false, readOnly: false,
newPropertyDialogContainer: '#new-reporting-task-property-container', dialogContainer: '#new-reporting-task-property-container',
deferredDescriptor: getReportingTaskPropertyDescriptor deferredDescriptor: getReportingTaskPropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
}); });
// update the mode // update the mode
@ -407,33 +473,15 @@ nf.ReportingTask = (function () {
// close all fields currently being edited // close all fields currently being edited
$('#reporting-task-properties').propertytable('saveRow'); $('#reporting-task-properties').propertytable('saveRow');
// marshal the settings and properties and update the reporting task // save the reporting task
var updatedReportingTask = marshalDetails(); saveReportingTask(reportingTask).done(function (response) {
// ensure details are valid as far as we can tell
if (validateDetails(updatedReportingTask)) {
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedReportingTask),
url: reportingTask.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.reportingTask)) {
// update the revision
nf.Client.setRevision(response.revision);
// reload the reporting task // reload the reporting task
renderReportingTask(response.reportingTask); renderReportingTask(response.reportingTask);
nf.ControllerService.reloadReferencedServices(response.reportingTask); nf.ControllerService.reloadReferencedServices(response.reportingTask);
// close the details panel // close the details panel
$('#reporting-task-configuration').modal('hide'); $('#reporting-task-configuration').modal('hide');
} });
}).fail(handleReportingTaskConfigurationError);
}
} }
} }
}, { }, {
@ -481,29 +529,10 @@ nf.ReportingTask = (function () {
overlayBackground: false, overlayBackground: false,
noHandler: openCustomUi, noHandler: openCustomUi,
yesHandler: function () { yesHandler: function () {
// marshal the settings and properties and update the reporting task saveReportingTask(reportingTask).done(function () {
var updatedReportingTask = marshalDetails();
// ensure details are valid as far as we can tell
if (validateDetails(updatedReportingTask)) {
// update the selected component
$.ajax({
type: 'PUT',
data: JSON.stringify(updatedReportingTask),
url: reportingTask.uri,
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.reportingTask)) {
// update the revision
nf.Client.setRevision(response.revision);
// open the custom ui // open the custom ui
openCustomUi(); openCustomUi();
} });
}).fail(handleReportingTaskConfigurationError);
}
} }
}); });
} else { } else {

View File

@ -167,34 +167,6 @@ nf.Settings = (function () {
} }
}; };
/**
* Determines if all of the ancestors of the specified item are expanded.
*
* @param {type} item
* @returns {Boolean}
*/
var areAncestorsExpanded = function (item) {
var documentedType = item;
while (documentedType.parent !== null) {
if (documentedType.parent.collapsed === true) {
return false;
}
documentedType = documentedType.parent;
}
return true;
};
/**
* Determines if the specified item is an ancestor.
*
* @param {type} item
* @returns {Boolean}
*/
var isAncestor = function (item) {
return item.children.length > 0;
};
/** /**
* Hides the selected controller service. * Hides the selected controller service.
*/ */
@ -232,27 +204,6 @@ nf.Settings = (function () {
* @returns {Boolean} Whether or not to include the item * @returns {Boolean} Whether or not to include the item
*/ */
var filterControllerServiceTypes = function (item, args) { var filterControllerServiceTypes = function (item, args) {
if (!areAncestorsExpanded(item)) {
// if this item is currently selected and its parent is not collapsed
if ($('#selected-controller-service-type').text() === item['type']) {
clearControllerServiceSelection();
}
// update visibility flag
item.visible = false;
return false;
}
// don't allow ancestors to be filtered out (unless any of their ancestors
// are collapsed)
if (isAncestor(item)) {
// update visibility flag
item.visible = false;
return true;
}
// determine if the item matches the filter // determine if the item matches the filter
var matchesFilter = matchesRegex(item, args); var matchesFilter = matchesRegex(item, args);
@ -274,9 +225,6 @@ nf.Settings = (function () {
clearControllerServiceSelection(); clearControllerServiceSelection();
} }
// update visibility flag
item.visible = matches;
return matches; return matches;
}; };
@ -330,64 +278,6 @@ nf.Settings = (function () {
return matches; return matches;
}; };
/**
* Formats the type by introducing expand/collapse where appropriate.
*
* @param {type} row
* @param {type} cell
* @param {type} value
* @param {type} columnDef
* @param {type} dataContext
*/
var expandableTypeFormatter = function (row, cell, value, columnDef, dataContext) {
var markup = '';
var indent = 0;
var documentedType = dataContext;
while (documentedType.parent !== null) {
indent += 20;
documentedType = documentedType.parent;
}
var padding = 3;
// create the markup for the row
if (dataContext.children.length > 0) {
// determine how to render the expansion button
var expansionStyle = 'expanded';
if (dataContext.collapsed === true) {
expansionStyle = 'collapsed';
}
// calculate the number of visible/total children
var visibleChildren = 0;
var totalChildren = 0;
var countChildren = function (item) {
$.each(item.children, function (_, child) {
if (child.children.length > 0) {
countChildren(child);
} else {
if (child.visible) {
visibleChildren++;
}
totalChildren++;
}
});
};
countChildren(dataContext);
markup += ('<span style="margin-top: 5px; margin-left: ' + indent + 'px;" class="expansion-button ' + expansionStyle + '"></span><span class="ancestor-type" style="margin-left: ' + padding + 'px;">' + value + '</span><span class="ancestor-type-rollup">(' + visibleChildren + ' of ' + totalChildren + ')</span>');
} else {
if (dataContext.parent === null) {
padding = 0;
}
markup += ('<span style="margin-left: ' + (indent + padding) + 'px;">' + value + '</span>');
}
return markup;
};
/** /**
* Adds a new controller service of the specified type. * Adds a new controller service of the specified type.
* *
@ -431,6 +321,7 @@ nf.Settings = (function () {
// select the new controller service // select the new controller service
var row = controllerServicesData.getRowById(controllerService.id); var row = controllerServicesData.getRowById(controllerService.id);
controllerServicesGrid.setSelectedRows([row]); controllerServicesGrid.setSelectedRows([row]);
controllerServicesGrid.scrollRowIntoView(row);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
// hide the dialog // hide the dialog
@ -488,7 +379,7 @@ nf.Settings = (function () {
// initialize the processor type table // initialize the processor type table
var controllerServiceTypesColumns = [ var controllerServiceTypesColumns = [
{id: 'type', name: 'Type', field: 'label', formatter: expandableTypeFormatter, sortable: false, resizable: true}, {id: 'type', name: 'Type', field: 'label', sortable: false, resizable: true},
{id: 'tags', name: 'Tags', field: 'tags', sortable: false, resizable: true} {id: 'tags', name: 'Tags', field: 'tags', sortable: false, resizable: true}
]; ];
@ -502,32 +393,6 @@ nf.Settings = (function () {
property: $('#controller-service-type-filter-options').combo('getSelectedOption').value property: $('#controller-service-type-filter-options').combo('getSelectedOption').value
}); });
controllerServiceTypesData.setFilter(filterControllerServiceTypes); controllerServiceTypesData.setFilter(filterControllerServiceTypes);
controllerServiceTypesData.getItemMetadata = function (index) {
var item = controllerServiceTypesData.getItem(index);
if (item && item.children.length > 0) {
return {
selectable: false,
columns: {
0: {
colspan: '*'
}
}
};
} else {
return {};
}
};
var getVisibleControllerServiceCount = function () {
var count = 0;
for (var i = 0; i < controllerServiceTypesData.getLength(); i++) {
var item = controllerServiceTypesData.getItem(i);
if (item.children.length === 0) {
count++;
}
}
return count;
};
// initialize the grid // initialize the grid
var controllerServiceTypesGrid = new Slick.Grid('#controller-service-types-table', controllerServiceTypesData, controllerServiceTypesColumns, gridOptions); var controllerServiceTypesGrid = new Slick.Grid('#controller-service-types-table', controllerServiceTypesData, controllerServiceTypesColumns, gridOptions);
@ -539,8 +404,6 @@ nf.Settings = (function () {
var controllerServiceTypeIndex = args.rows[0]; var controllerServiceTypeIndex = args.rows[0];
var controllerServiceType = controllerServiceTypesGrid.getDataItem(controllerServiceTypeIndex); var controllerServiceType = controllerServiceTypesGrid.getDataItem(controllerServiceTypeIndex);
// only allow selection of service implementations
if (controllerServiceType.children.length === 0) {
// set the controller service type description // set the controller service type description
if (nf.Common.isBlank(controllerServiceType.description)) { if (nf.Common.isBlank(controllerServiceType.description)) {
$('#controller-service-type-description').attr('title', '').html('<span class="unset">No description specified</span>'); $('#controller-service-type-description').attr('title', '').html('<span class="unset">No description specified</span>');
@ -556,25 +419,6 @@ nf.Settings = (function () {
// show the selected controller service // show the selected controller service
$('#controller-service-description-container').show(); $('#controller-service-description-container').show();
} }
}
});
controllerServiceTypesGrid.onClick.subscribe(function (e, args) {
var item = controllerServiceTypesData.getItem(args.row);
if (item && item.children.length > 0) {
// update the grid
item.collapsed = !item.collapsed;
controllerServiceTypesData.updateItem(item.id, item);
// update any affected ancestors
var parent = item.parent;
while (parent !== null) {
controllerServiceTypesData.updateItem(parent.id, parent);
parent = parent.parent;
}
// prevent selection within slickgrid
e.stopImmediatePropagation();
}
}); });
controllerServiceTypesGrid.onDblClick.subscribe(function (e, args) { controllerServiceTypesGrid.onDblClick.subscribe(function (e, args) {
var controllerServiceType = controllerServiceTypesGrid.getDataItem(args.row); var controllerServiceType = controllerServiceTypesGrid.getDataItem(args.row);
@ -587,7 +431,7 @@ nf.Settings = (function () {
controllerServiceTypesGrid.render(); controllerServiceTypesGrid.render();
// update the total number of displayed processors // update the total number of displayed processors
$('#displayed-controller-service-types').text(getVisibleControllerServiceCount()); $('#displayed-controller-service-types').text(args.current);
}); });
controllerServiceTypesData.onRowsChanged.subscribe(function (e, args) { controllerServiceTypesData.onRowsChanged.subscribe(function (e, args) {
controllerServiceTypesGrid.invalidateRows(args.rows); controllerServiceTypesGrid.invalidateRows(args.rows);
@ -610,46 +454,28 @@ nf.Settings = (function () {
// begin the update // begin the update
controllerServiceTypesData.beginUpdate(); controllerServiceTypesData.beginUpdate();
var addType = function (parentItem, documentedType) { // go through each controller service type
var item = { $.each(response.controllerServiceTypes, function (i, documentedType) {
// add the documented type
controllerServiceTypesData.addItem({
id: id++, id: id++,
label: nf.Common.substringAfterLast(documentedType.type, '.'), label: nf.Common.substringAfterLast(documentedType.type, '.'),
type: documentedType.type, type: documentedType.type,
description: nf.Common.escapeHtml(documentedType.description), description: nf.Common.escapeHtml(documentedType.description),
tags: documentedType.tags.join(', '), tags: documentedType.tags.join(', ')
parent: parentItem, });
children: [],
collapsed: false,
visible: true
};
// add the documented type
controllerServiceTypesData.addItem(item);
// count the frequency of each tag for this type // count the frequency of each tag for this type
$.each(documentedType.tags, function (i, tag) { $.each(documentedType.tags, function (i, tag) {
tags.push(tag.toLowerCase()); tags.push(tag.toLowerCase());
}); });
// add each of its children
$.each(documentedType.childTypes, function (_, documentedChildType) {
var childItem = addType(item, documentedChildType);
item.children.push(childItem);
});
return item;
};
// go through each controller service type
$.each(response.controllerServiceTypes, function (i, documentedType) {
addType(null, documentedType);
}); });
// end the udpate // end the udpate
controllerServiceTypesData.endUpdate(); controllerServiceTypesData.endUpdate();
// set the total number of processors // set the total number of processors
$('#total-controller-service-types, #displayed-controller-service-types').text(getVisibleControllerServiceCount()); $('#total-controller-service-types, #displayed-controller-service-types').text(response.controllerServiceTypes.length);
// create the tag cloud // create the tag cloud
$('#controller-service-tag-cloud').tagcloud({ $('#controller-service-tag-cloud').tagcloud({
@ -1098,9 +924,6 @@ nf.Settings = (function () {
clearReportingTaskSelection(); clearReportingTaskSelection();
} }
// update visibility flag
item.visible = matches;
return matches; return matches;
}; };
@ -1147,6 +970,7 @@ nf.Settings = (function () {
// select the new reporting task // select the new reporting task
var row = reportingTaskData.getRowById(reportingTask.id); var row = reportingTaskData.getRowById(reportingTask.id);
reportingTaskGrid.setSelectedRows([row]); reportingTaskGrid.setSelectedRows([row]);
reportingTaskGrid.scrollRowIntoView(row);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
// hide the dialog // hide the dialog
@ -1287,10 +1111,7 @@ nf.Settings = (function () {
label: nf.Common.substringAfterLast(documentedType.type, '.'), label: nf.Common.substringAfterLast(documentedType.type, '.'),
type: documentedType.type, type: documentedType.type,
description: nf.Common.escapeHtml(documentedType.description), description: nf.Common.escapeHtml(documentedType.description),
tags: documentedType.tags.join(', '), tags: documentedType.tags.join(', ')
children: [],
collapsed: false,
visible: true
}); });
// count the frequency of each tag for this type // count the frequency of each tag for this type