NIFI-1742:

- Addressing issues when creating a new inline controller service.
- Ensuring controller service referencing components are updated.
- Including revisions and status with each component.
- Dynamically updating component and authorization states.
- This closes #435
This commit is contained in:
Matt Gilman 2016-05-12 11:17:48 -04:00
parent 687a686b21
commit 3cc16d35ed
53 changed files with 2725 additions and 2323 deletions

View File

@ -17,8 +17,11 @@
package org.apache.nifi.web.api.dto.flow;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.util.TimeAdapter;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Date;
/**
* The NiFi flow starting at a given Process Group.
@ -31,6 +34,7 @@ public class ProcessGroupFlowDTO {
private String parentGroupId;
private FlowBreadcrumbDTO breadcrumb;
private FlowDTO flow;
private Date lastRefreshed;
/**
* @return contents of this process group. This field will be populated if the request is marked verbose
@ -108,5 +112,15 @@ public class ProcessGroupFlowDTO {
this.uri = uri;
}
@XmlJavaTypeAdapter(TimeAdapter.class)
@ApiModelProperty(
value = "The time the flow for the process group was last refreshed."
)
public Date getLastRefreshed() {
return lastRefreshed;
}
public void setLastRefreshed(Date lastRefreshed) {
this.lastRefreshed = lastRefreshed;
}
}

View File

@ -19,6 +19,7 @@ package org.apache.nifi.web.api.entity;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.PositionDTO;
import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
@ -30,6 +31,7 @@ import java.util.List;
public class ConnectionEntity extends ComponentEntity {
private ConnectionDTO component;
private ConnectionStatusDTO status;
private List<PositionDTO> bends;
private Integer labelIndex;
private String sourceId;
@ -48,6 +50,20 @@ public class ConnectionEntity extends ComponentEntity {
this.component = component;
}
/**
* @return the connection status
*/
@ApiModelProperty(
value = "The status of the connection."
)
public ConnectionStatusDTO getStatus() {
return status;
}
public void setStatus(ConnectionStatusDTO status) {
this.status = status;
}
/**
* @return position of the bend points on this connection
*/

View File

@ -16,7 +16,9 @@
*/
package org.apache.nifi.web.api.entity;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.PortDTO;
import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import javax.xml.bind.annotation.XmlRootElement;
@ -27,6 +29,7 @@ import javax.xml.bind.annotation.XmlRootElement;
public class PortEntity extends ComponentEntity {
private PortDTO component;
private PortStatusDTO status;
private String portType;
/**
@ -40,6 +43,20 @@ public class PortEntity extends ComponentEntity {
this.component = component;
}
/**
* @return the port status
*/
@ApiModelProperty(
value = "The status of the port."
)
public PortStatusDTO getStatus() {
return status;
}
public void setStatus(PortStatusDTO status) {
this.status = status;
}
public String getPortType() {
return portType;
}

View File

@ -17,7 +17,10 @@
package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ProcessGroupDTO.
@ -26,6 +29,17 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO;
public class ProcessGroupEntity extends ComponentEntity {
private ProcessGroupDTO component;
private ProcessGroupStatusDTO status;
private Integer runningCount;
private Integer stoppedCount;
private Integer invalidCount;
private Integer disabledCount;
private Integer activeRemotePortCount;
private Integer inactiveRemotePortCount;
private Integer inputPortCount;
private Integer outputPortCount;
/**
* The ProcessGroupDTO that is being serialized.
@ -40,4 +54,129 @@ public class ProcessGroupEntity extends ComponentEntity {
this.component = component;
}
/**
* @return the process group status
*/
@ApiModelProperty(
value = "The status of the process group."
)
public ProcessGroupStatusDTO getStatus() {
return status;
}
public void setStatus(ProcessGroupStatusDTO status) {
this.status = status;
}
/**
* @return number of input ports contained in this process group
*/
@ApiModelProperty(
value = "The number of input ports in the process group."
)
public Integer getInputPortCount() {
return inputPortCount;
}
public void setInputPortCount(Integer inputPortCount) {
this.inputPortCount = inputPortCount;
}
/**
* @return number of invalid components in this process group
*/
@ApiModelProperty(
value = "The number of invalid components in the process group."
)
public Integer getInvalidCount() {
return invalidCount;
}
public void setInvalidCount(Integer invalidCount) {
this.invalidCount = invalidCount;
}
/**
* @return number of output ports in this process group
*/
@ApiModelProperty(
value = "The number of output ports in the process group."
)
public Integer getOutputPortCount() {
return outputPortCount;
}
public void setOutputPortCount(Integer outputPortCount) {
this.outputPortCount = outputPortCount;
}
/**
* @return number of running component in this process group
*/
@ApiModelProperty(
value = "The number of running componetns in this process group."
)
public Integer getRunningCount() {
return runningCount;
}
public void setRunningCount(Integer runningCount) {
this.runningCount = runningCount;
}
/**
* @return number of stopped components in this process group
*/
@ApiModelProperty(
value = "The number of stopped components in the process group."
)
public Integer getStoppedCount() {
return stoppedCount;
}
public void setStoppedCount(Integer stoppedCount) {
this.stoppedCount = stoppedCount;
}
/**
* @return number of disabled components in this process group
*/
@ApiModelProperty(
value = "The number of disabled components in the process group."
)
public Integer getDisabledCount() {
return disabledCount;
}
public void setDisabledCount(Integer disabledCount) {
this.disabledCount = disabledCount;
}
/**
* @return number of active remote ports in this process group
*/
@ApiModelProperty(
value = "The number of active remote ports in the process group."
)
public Integer getActiveRemotePortCount() {
return activeRemotePortCount;
}
public void setActiveRemotePortCount(Integer activeRemotePortCount) {
this.activeRemotePortCount = activeRemotePortCount;
}
/**
* @return number of inactive remote ports in this process group
*/
@ApiModelProperty(
value = "The number of inactive remote ports in the process group."
)
public Integer getInactiveRemotePortCount() {
return inactiveRemotePortCount;
}
public void setInactiveRemotePortCount(Integer inactiveRemotePortCount) {
this.inactiveRemotePortCount = inactiveRemotePortCount;
}
}

View File

@ -17,7 +17,10 @@
package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement;
import com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
/**
* A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RemoteProcessGroupDTO.
@ -26,6 +29,10 @@ import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
public class RemoteProcessGroupEntity extends ComponentEntity {
private RemoteProcessGroupDTO component;
private RemoteProcessGroupStatusDTO status;
private Integer inputPortCount;
private Integer outputPortCount;
/**
* The RemoteProcessGroupDTO that is being serialized.
@ -40,4 +47,45 @@ public class RemoteProcessGroupEntity extends ComponentEntity {
this.component = component;
}
/**
* @return the remote process group status
*/
@ApiModelProperty(
value = "The status of the remote process group."
)
public RemoteProcessGroupStatusDTO getStatus() {
return status;
}
public void setStatus(RemoteProcessGroupStatusDTO status) {
this.status = status;
}
/**
* @return number of Remote Input Ports currently available in the remote NiFi instance
*/
@ApiModelProperty(
value = "The number of remote input ports currently available on the target."
)
public Integer getInputPortCount() {
return inputPortCount;
}
public void setInputPortCount(Integer inputPortCount) {
this.inputPortCount = inputPortCount;
}
/**
* @return number of Remote Output Ports currently available in the remote NiFi instance
*/
@ApiModelProperty(
value = "The number of remote output ports currently available on the target."
)
public Integer getOutputPortCount() {
return outputPortCount;
}
public void setOutputPortCount(Integer outputPortCount) {
this.outputPortCount = outputPortCount;
}
}

View File

@ -16,10 +16,6 @@
*/
package org.apache.nifi.web;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.repository.claim.ContentDirection;
import org.apache.nifi.controller.service.ControllerServiceState;
@ -49,7 +45,6 @@ import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
import org.apache.nifi.web.api.dto.ResourceDTO;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.SnippetDTO;
import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
@ -83,6 +78,10 @@ import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.SnippetEntity;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Defines the NiFiServiceFacade interface.
*/
@ -214,10 +213,9 @@ public interface NiFiServiceFacade {
/**
* Creates a new archive of the flow configuration.
*
* @param revision Revision to compare with current base revision
* @return snapshot
*/
ProcessGroupEntity createArchive(Revision revision);
ProcessGroupEntity createArchive();
/**
* Sets the annotation data for a processor.
@ -297,13 +295,6 @@ public interface NiFiServiceFacade {
*/
Set<DocumentedTypeDTO> getWorkQueuePrioritizerTypes();
/**
* Returns the current revision.
*
* @return revision
*/
RevisionDTO getRevision();
// ----------------------------------------
// Template methods
// ----------------------------------------
@ -328,14 +319,13 @@ public interface NiFiServiceFacade {
/**
* Instantiate the corresponding template.
*
* @param revision revision
* @param groupId group id
* @param templateId template id
* @param originX x
* @param originY y
* @return snapshot
*/
FlowEntity createTemplateInstance(Revision revision, String groupId, Double originX, Double originY, String templateId);
FlowEntity createTemplateInstance(String groupId, Double originX, Double originY, String templateId);
/**
* Gets the template with the specified id.
@ -373,12 +363,11 @@ public interface NiFiServiceFacade {
/**
* Creates a new Processor.
*
* @param revision Revision to compare with current base revision
* @param groupId Group id
* @param processorDTO The processor DTO
* @return The new processor DTO
*/
ProcessorEntity createProcessor(Revision revision, String groupId, ProcessorDTO processorDTO);
ProcessorEntity createProcessor(String groupId, ProcessorDTO processorDTO);
/**
* Gets the Processor transfer object for the specified id.
@ -492,12 +481,11 @@ public interface NiFiServiceFacade {
/**
* Creates a new Relationship target.
*
* @param revision Revision to compare with current base revision
* @param groupId group
* @param connectionDTO The Connection DTO
* @return The Connection DTO
*/
ConnectionEntity createConnection(Revision revision, String groupId, ConnectionDTO connectionDTO);
ConnectionEntity createConnection(String groupId, ConnectionDTO connectionDTO);
/**
* Determines if this connection can be listed.
@ -618,12 +606,11 @@ public interface NiFiServiceFacade {
/**
* Creates a new input port.
*
* @param revision Revision to compare with current base revision
* @param groupId The id of the group this port should be create in
* @param inputPortDTO The input PortDTO
* @return snapshot
*/
PortEntity createInputPort(Revision revision, String groupId, PortDTO inputPortDTO);
PortEntity createInputPort(String groupId, PortDTO inputPortDTO);
/**
* Gets an input port.
@ -687,12 +674,11 @@ public interface NiFiServiceFacade {
/**
* Creates a new output port.
*
* @param revision Revision to compare with current base revision
* @param groupId The id of the group this port should be create in
* @param outputPortDTO The output PortDTO
* @return snapshot
*/
PortEntity createOutputPort(Revision revision, String groupId, PortDTO outputPortDTO);
PortEntity createOutputPort( String groupId, PortDTO outputPortDTO);
/**
* Gets an output port.
@ -769,11 +755,10 @@ public interface NiFiServiceFacade {
* Creates a new process group.
*
* @param parentGroupId The id of the parent group
* @param revision Revision to compare with current base revision
* @param processGroupDTO The ProcessGroupDTO
* @return snapshot
*/
ProcessGroupEntity createProcessGroup(String parentGroupId, Revision revision, ProcessGroupDTO processGroupDTO);
ProcessGroupEntity createProcessGroup(String parentGroupId, ProcessGroupDTO processGroupDTO);
/**
* Returns the process group.
@ -829,12 +814,11 @@ public interface NiFiServiceFacade {
/**
* Creates a new remote process group.
*
* @param revision Revision to compare with current base revision
* @param groupId The id of the parent group
* @param remoteProcessGroupDTO The RemoteProcessGroupDTO
* @return snapshot
*/
RemoteProcessGroupEntity createRemoteProcessGroup(Revision revision, String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO);
RemoteProcessGroupEntity createRemoteProcessGroup(String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO);
/**
* Gets a remote process group.
@ -942,12 +926,11 @@ public interface NiFiServiceFacade {
/**
* Creates a funnel.
*
* @param revision Revision to compare with current base revision
* @param groupId group
* @param funnelDTO funnel
* @return The funnel DTO
*/
FunnelEntity createFunnel(Revision revision, String groupId, FunnelDTO funnelDTO);
FunnelEntity createFunnel(String groupId, FunnelDTO funnelDTO);
/**
* Gets the specified funnel.
@ -1072,12 +1055,11 @@ public interface NiFiServiceFacade {
/**
* Creates a label.
*
* @param revision Revision to compare with current base revision
* @param groupId group
* @param labelDTO The label DTO
* @return The label DTO
*/
LabelEntity createLabel(Revision revision, String groupId, LabelDTO labelDTO);
LabelEntity createLabel(String groupId, LabelDTO labelDTO);
/**
* Gets the specified label.
@ -1320,23 +1302,21 @@ public interface NiFiServiceFacade {
/**
* Creates a new snippet based off the existing snippet.
*
* @param revision revision
* @param groupId group id
* @param snippetId snippet id
* @param originX x
* @param originY y
* @return snapshot
*/
FlowEntity copySnippet(Revision revision, String groupId, String snippetId, Double originX, Double originY);
FlowEntity copySnippet(String groupId, String snippetId, Double originX, Double originY);
/**
* Creates a new snippet.
*
* @param revision revision
* @param snippet snippet
* @return snapshot
*/
ConfigurationSnapshot<SnippetDTO> createSnippet(Revision revision, SnippetDTO snippet);
SnippetEntity createSnippet(SnippetDTO snippet);
/**
* Gets the specified snippet.
@ -1344,7 +1324,7 @@ public interface NiFiServiceFacade {
* @param snippetId id
* @return snippet
*/
SnippetDTO getSnippet(String snippetId);
SnippetEntity getSnippet(String snippetId);
/**
* Determines if this snippet can be updated.
@ -1360,7 +1340,7 @@ public interface NiFiServiceFacade {
* @param snippetDto snippet
* @return snapshot
*/
ConfigurationSnapshot<SnippetDTO> updateSnippet(Revision revision, SnippetDTO snippetDto);
UpdateResult<SnippetEntity> updateSnippet(Revision revision, SnippetDTO snippetDto);
/**
* Determines if this snippet can be removed.

View File

@ -102,7 +102,6 @@ public class ControllerResource extends ApplicationResource {
* Alternatively, we could have performed a PUT request. However, PUT requests are supposed to be idempotent and this endpoint is certainly not.
*
* @param httpServletRequest request
* @param revisionEntity The revision is used to verify the client is working with the latest version of the flow.
* @return A processGroupEntity.
*/
@POST
@ -129,17 +128,7 @@ public class ControllerResource extends ApplicationResource {
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response createArchive(
@Context HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision used to verify the client is working with the latest version of the flow.",
required = true
) Entity revisionEntity) {
// ensure the revision was specified
if (revisionEntity == null || revisionEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
public Response createArchive(@Context HttpServletRequest httpServletRequest) {
// replicate if cluster manager
if (properties.isClusterManager()) {
@ -154,8 +143,7 @@ public class ControllerResource extends ApplicationResource {
}
// create the archive
final RevisionDTO requestRevision = revisionEntity.getRevision();
final ProcessGroupEntity entity = serviceFacade.createArchive(new Revision(requestRevision.getVersion(), requestRevision.getClientId()));
final ProcessGroupEntity entity = serviceFacade.createArchive();
// generate the response
URI uri = URI.create(generateResourceUri("controller", "archive"));

View File

@ -33,6 +33,8 @@ import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.context.ClusterContext;
import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
import org.apache.nifi.cluster.manager.NodeResponse;
import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
import org.apache.nifi.cluster.manager.impl.WebClusterManager;
@ -96,8 +98,10 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* RESTful endpoint for managing a Flow.
@ -208,10 +212,9 @@ public class FlowResource extends ApplicationResource {
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("process-groups/{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets a process group",
response = ProcessGroupEntity.class,
response = ProcessGroupFlowEntity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@ -268,6 +271,43 @@ public class FlowResource extends ApplicationResource {
return clusterContext(generateOkResponse(processGroupEntity)).build();
}
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.TEXT_PLAIN)
@Path("client-id")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Generates a client id.",
response = String.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 404, message = "The specified resource could not be found."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response generateClientId() {
authorizeFlow();
final String clientId;
final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
if (clusterContext != null) {
clientId = UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString();
} else {
clientId = UUID.randomUUID().toString();
}
return clusterContext(generateOkResponse(clientId)).build();
}
// ------
// search
// ------
@ -319,59 +359,6 @@ public class FlowResource extends ApplicationResource {
return clusterContext(noCache(Response.ok(entity))).build();
}
/**
* Gets current revision of this NiFi.
*
* @return A revisionEntity
*/
@GET
@Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON)
@Path("revision")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation(
value = "Gets the current revision of this NiFi",
notes = "NiFi employs an optimistic locking strategy where the client must include a revision in their request when "
+ "performing an update. If the specified revision does not match the current base revision a 409 status code "
+ "is returned. The revision is comprised of a clientId and a version number. The version is a simple integer "
+ "value that is incremented with each change. Including the most recent version tells NiFi that your working "
+ "with the most recent flow. In addition to the version the client who is performing the updates is recorded. "
+ "This allows the same client to submit multiple requests without having to wait for the previously ones to "
+ "return. Invoking this endpoint will return the current base revision. It is also available when retrieving "
+ "a process group and in the response of all mutable requests.",
response = Entity.class,
authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@Authorization(value = "Administrator", type = "ROLE_ADMIN")
}
)
@ApiResponses(
value = {
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
@ApiResponse(code = 401, message = "Client could not be authenticated."),
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response getRevision() {
authorizeFlow();
if (properties.isClusterManager()) {
return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
}
// create the current revision
final RevisionDTO revision = serviceFacade.getRevision();
// create the response entity
final Entity entity = new Entity();
entity.setRevision(revision);
// generate the response
return clusterContext(generateOkResponse(entity)).build();
}
/**
* Retrieves the status for this NiFi.
*

View File

@ -16,44 +16,19 @@
*/
package org.apache.nifi.web.api;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import com.sun.jersey.api.core.ResourceContext;
import com.sun.jersey.multipart.FormDataParam;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.cluster.context.ClusterContext;
import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
import org.apache.nifi.cluster.manager.impl.WebClusterManager;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.ConfigurationSnapshot;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.UpdateResult;
@ -96,14 +71,36 @@ import org.apache.nifi.web.util.Availability;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.core.ResourceContext;
import com.sun.jersey.multipart.FormDataParam;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* RESTful endpoint for managing a Group.
@ -207,6 +204,19 @@ public class ProcessGroupResource extends ApplicationResource {
return flow;
}
/**
* Populate the uri's for the specified snippet.
*
* @param entity processors
* @return dtos
*/
private SnippetEntity populateRemainingSnippetEntityContent(SnippetEntity entity) {
if (entity.getSnippet() != null) {
populateRemainingSnippetContent(entity.getSnippet());
}
return entity;
}
/**
* Populates the uri for the specified snippet.
*/
@ -473,10 +483,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Process group details must be specified.");
}
if (processGroupEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (processGroupEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Process group ID cannot be specified.");
}
@ -506,8 +512,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the process group contents
final RevisionDTO revision = processGroupEntity.getRevision();
final ProcessGroupEntity entity = serviceFacade.createProcessGroup(groupId, new Revision(revision.getVersion(), revision.getClientId()), processGroupEntity.getComponent());
final ProcessGroupEntity entity = serviceFacade.createProcessGroup(groupId, processGroupEntity.getComponent());
populateRemainingProcessGroupEntityContent(entity);
// generate a 201 created response
@ -623,10 +628,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Processor details must be specified.");
}
if (processorEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (processorEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Processor ID cannot be specified.");
}
@ -660,8 +661,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the new processor
final RevisionDTO revision = processorEntity.getRevision();
final ProcessorEntity entity = serviceFacade.createProcessor(new Revision(revision.getVersion(), revision.getClientId()), groupId, processorEntity.getComponent());
final ProcessorEntity entity = serviceFacade.createProcessor(groupId, processorEntity.getComponent());
processorResource.populateRemainingProcessorEntityContent(entity);
// generate a 201 created response
@ -770,10 +770,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Port details must be specified.");
}
if (portEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (portEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Input port ID cannot be specified.");
}
@ -803,8 +799,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the input port and generate the json
final RevisionDTO revision = portEntity.getRevision();
final PortEntity entity = serviceFacade.createInputPort(new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
final PortEntity entity = serviceFacade.createInputPort(groupId, portEntity.getComponent());
inputPortResource.populateRemainingInputPortEntityContent(entity);
// build the response
@ -910,10 +905,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Port details must be specified.");
}
if (portEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (portEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Output port ID cannot be specified.");
}
@ -943,9 +934,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the output port and generate the json
final RevisionDTO revision = portEntity.getRevision();
final PortEntity entity = serviceFacade.createOutputPort(
new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
final PortEntity entity = serviceFacade.createOutputPort(groupId, portEntity.getComponent());
outputPortResource.populateRemainingOutputPortEntityContent(entity);
// build the response
@ -1052,10 +1041,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Funnel details must be specified.");
}
if (funnelEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (funnelEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Funnel ID cannot be specified.");
}
@ -1085,8 +1070,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the funnel and generate the json
final RevisionDTO revision = funnelEntity.getRevision();
final FunnelEntity entity = serviceFacade.createFunnel(new Revision(revision.getVersion(), revision.getClientId()), groupId, funnelEntity.getComponent());
final FunnelEntity entity = serviceFacade.createFunnel(groupId, funnelEntity.getComponent());
funnelResource.populateRemainingFunnelEntityContent(entity);
// build the response
@ -1193,10 +1177,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Label details must be specified.");
}
if (labelEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (labelEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Label ID cannot be specified.");
}
@ -1226,9 +1206,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the label and generate the json
final RevisionDTO revision = labelEntity.getRevision();
final LabelEntity entity = serviceFacade.createLabel(
new Revision(revision.getVersion(), revision.getClientId()), groupId, labelEntity.getComponent());
final LabelEntity entity = serviceFacade.createLabel(groupId, labelEntity.getComponent());
labelResource.populateRemainingLabelEntityContent(entity);
// build the response
@ -1335,10 +1313,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Remote process group details must be specified.");
}
if (remoteProcessGroupEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
final RemoteProcessGroupDTO requestProcessGroupDTO = remoteProcessGroupEntity.getComponent();
if (requestProcessGroupDTO.getId() != null) {
@ -1400,8 +1374,7 @@ public class ProcessGroupResource extends ApplicationResource {
requestProcessGroupDTO.setTargetUri(controllerUri);
// create the remote process group
final RevisionDTO revision = remoteProcessGroupEntity.getRevision();
final RemoteProcessGroupEntity entity = serviceFacade.createRemoteProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), groupId, requestProcessGroupDTO);
final RemoteProcessGroupEntity entity = serviceFacade.createRemoteProcessGroup(groupId, requestProcessGroupDTO);
remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntityContent(entity);
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
@ -1526,10 +1499,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Connection ID cannot be specified.");
}
if (connectionEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (connectionEntity.getComponent().getParentGroupId() != null && !groupId.equals(connectionEntity.getComponent().getParentGroupId())) {
throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
connectionEntity.getComponent().getParentGroupId(), groupId));
@ -1559,8 +1528,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the new relationship target
final RevisionDTO revision = connectionEntity.getRevision();
final ConnectionEntity entity = serviceFacade.createConnection(new Revision(revision.getVersion(), revision.getClientId()), groupId, connection);
final ConnectionEntity entity = serviceFacade.createConnection(groupId, connection);
connectionResource.populateRemainingConnectionEntityContent(entity);
// extract the href and build the response
@ -1670,10 +1638,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Snippet details must be specified.");
}
if (snippetEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (snippetEntity.getSnippet().getId() != null) {
throw new IllegalArgumentException("Snippet ID cannot be specified.");
}
@ -1708,24 +1672,11 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the snippet
final RevisionDTO revision = snippetEntity.getRevision();
final ConfigurationSnapshot<SnippetDTO> response = serviceFacade.createSnippet(new Revision(revision.getVersion(), revision.getClientId()), snippetEntity.getSnippet());
// get the snippet
final SnippetDTO snippet = response.getConfiguration();
// get the updated revision
final RevisionDTO updatedRevision = new RevisionDTO();
updatedRevision.setClientId(revision.getClientId());
updatedRevision.setVersion(response.getVersion());
// build the response entity
SnippetEntity entity = new SnippetEntity();
entity.setRevision(updatedRevision);
entity.setSnippet(populateRemainingSnippetContent(snippet));
final SnippetEntity entity = serviceFacade.createSnippet(snippetEntity.getSnippet());
populateRemainingSnippetEntityContent(entity);
// build the response
return clusterContext(generateCreatedResponse(URI.create(snippet.getUri()), entity)).build();
return clusterContext(generateCreatedResponse(URI.create(entity.getSnippet().getUri()), entity)).build();
}
/**
@ -1775,15 +1726,8 @@ public class ProcessGroupResource extends ApplicationResource {
}
// get the snippet
final SnippetDTO snippet = serviceFacade.getSnippet(id);
// create the revision
final RevisionDTO revision = new RevisionDTO();
// create the response entity
final SnippetEntity entity = new SnippetEntity();
entity.setRevision(revision);
entity.setSnippet(populateRemainingSnippetContent(snippet));
final SnippetEntity entity = serviceFacade.getSnippet(id);
populateRemainingSnippetEntityContent(entity);
return clusterContext(generateOkResponse(entity)).build();
}
@ -1856,32 +1800,25 @@ public class ProcessGroupResource extends ApplicationResource {
}
// handle expects request (usually from the cluster manager)
final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
if (expects != null) {
final Revision revision = getRevision(snippetEntity, id);
final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
serviceFacade.claimRevision(revision);
}
if (validationPhase) {
serviceFacade.verifyUpdateSnippet(requestSnippetDTO);
return generateContinueResponse().build();
}
// update the snippet
final RevisionDTO revision = snippetEntity.getRevision();
final ConfigurationSnapshot<SnippetDTO> controllerResponse = serviceFacade.updateSnippet(
new Revision(revision.getVersion(), revision.getClientId()), snippetEntity.getSnippet());
final UpdateResult<SnippetEntity> updateResult = serviceFacade.updateSnippet(revision, snippetEntity.getSnippet());
// get the results
final SnippetDTO snippet = controllerResponse.getConfiguration();
final SnippetEntity entity = updateResult.getResult();
populateRemainingSnippetEntityContent(entity);
// get the updated revision
final RevisionDTO updatedRevision = new RevisionDTO();
updatedRevision.setClientId(revision.getClientId());
updatedRevision.setVersion(controllerResponse.getVersion());
// build the response entity
SnippetEntity entity = new SnippetEntity();
entity.setRevision(updatedRevision);
entity.setSnippet(populateRemainingSnippetContent(snippet));
if (controllerResponse.isNew()) {
return clusterContext(generateCreatedResponse(URI.create(snippet.getUri()), entity)).build();
if (updateResult.isNew()) {
return clusterContext(generateCreatedResponse(URI.create(entity.getSnippet().getUri()), entity)).build();
} else {
return clusterContext(generateOkResponse(entity)).build();
}
@ -1920,7 +1857,7 @@ public class ProcessGroupResource extends ApplicationResource {
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
}
)
public Response removeSnippet(
public Response deleteSnippet(
@Context HttpServletRequest httpServletRequest,
@ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.",
@ -1948,21 +1885,23 @@ public class ProcessGroupResource extends ApplicationResource {
return clusterManager.applyRequest(HttpMethod.DELETE, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
}
final Revision revision = new Revision(version == null ? null : version.getLong(), clientId.getClientId(), id);
// handle expects request (usually from the cluster manager)
final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
if (expects != null) {
final boolean validationPhase = isValidationPhase(httpServletRequest);
// We need to claim the revision for the Processor if either this is the first phase of a two-phase
// request, or if this is not a two-phase request.
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
serviceFacade.claimRevision(revision);
}
if (validationPhase) {
serviceFacade.verifyDeleteSnippet(id);
return generateContinueResponse().build();
}
// determine the specified version
Long clientVersion = null;
if (version != null) {
clientVersion = version.getLong();
}
// delete the specified snippet
final SnippetEntity snippetEntity = serviceFacade.deleteSnippet(new Revision(clientVersion, clientId.getClientId()), id);
final SnippetEntity snippetEntity = serviceFacade.deleteSnippet(revision, id);
return clusterContext(generateOkResponse(snippetEntity)).build();
}
@ -2032,9 +1971,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// copy the specified snippet
final RevisionDTO requestRevision = copySnippetEntity.getRevision();
final FlowEntity flowEntity = serviceFacade.copySnippet(
new Revision(requestRevision.getVersion(), requestRevision.getClientId()),
groupId, copySnippetEntity.getSnippetId(), copySnippetEntity.getOriginX(), copySnippetEntity.getOriginY());
// get the snippet
@ -2118,9 +2055,7 @@ public class ProcessGroupResource extends ApplicationResource {
}
// create the template and generate the json
final RevisionDTO requestRevision = instantiateTemplateRequestEntity.getRevision();
final FlowEntity entity = serviceFacade.createTemplateInstance(
new Revision(requestRevision.getVersion(), requestRevision.getClientId()), groupId, instantiateTemplateRequestEntity.getOriginX(),
final FlowEntity entity = serviceFacade.createTemplateInstance(groupId, instantiateTemplateRequestEntity.getOriginX(),
instantiateTemplateRequestEntity.getOriginY(), instantiateTemplateRequestEntity.getTemplateId());
final FlowDTO flowSnippet = entity.getFlow();
@ -2473,10 +2408,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Controller service details must be specified.");
}
if (controllerServiceEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (controllerServiceEntity.getControllerService().getId() != null) {
throw new IllegalArgumentException("Controller service ID cannot be specified.");
}

View File

@ -16,30 +16,6 @@
*/
package org.apache.nifi.web.api.dto;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.ws.rs.WebApplicationException;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.component.details.ComponentDetails;
import org.apache.nifi.action.component.details.ExtensionDetails;
@ -123,7 +99,6 @@ import org.apache.nifi.provenance.lineage.ProvenanceEventLineageNode;
import org.apache.nifi.remote.RemoteGroupPort;
import org.apache.nifi.remote.RootGroupPort;
import org.apache.nifi.reporting.Bulletin;
import org.apache.nifi.reporting.BulletinRepository;
import org.apache.nifi.reporting.ReportingTask;
import org.apache.nifi.scheduling.SchedulingStrategy;
import org.apache.nifi.util.FormatUtils;
@ -160,6 +135,32 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusSnapshotDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity;
import org.apache.nifi.web.revision.RevisionManager;
import javax.ws.rs.WebApplicationException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public final class DtoFactory {
@ -664,9 +665,6 @@ public final class DtoFactory {
if (funnel == null) {
return null;
}
if (!funnel.isAuthorized(authorizer, RequestAction.READ)) {
return null;
}
final FunnelDTO dto = new FunnelDTO();
dto.setId(funnel.getIdentifier());
@ -766,7 +764,7 @@ public final class DtoFactory {
return dto;
}
public ProcessGroupStatusDTO createProcessGroupStatusDto(final BulletinRepository bulletinRepository, final ProcessGroupStatus processGroupStatus) {
public ProcessGroupStatusDTO createConciseProcessGroupStatusDto(final ProcessGroupStatus processGroupStatus) {
final ProcessGroupStatusDTO processGroupStatusDto = new ProcessGroupStatusDTO();
processGroupStatusDto.setId(processGroupStatus.getId());
processGroupStatusDto.setName(processGroupStatus.getName());
@ -794,6 +792,12 @@ public final class DtoFactory {
snapshot.setBytesReceived(processGroupStatus.getBytesReceived());
snapshot.setActiveThreadCount(processGroupStatus.getActiveThreadCount());
StatusMerger.updatePrettyPrintedFields(snapshot);
return processGroupStatusDto;
}
public ProcessGroupStatusDTO createProcessGroupStatusDto(final ProcessGroupStatus processGroupStatus) {
final ProcessGroupStatusDTO processGroupStatusDto = createConciseProcessGroupStatusDto(processGroupStatus);
final ProcessGroupStatusSnapshotDTO snapshot = processGroupStatusDto.getAggregateSnapshot();
// processor status
final Collection<ProcessorStatusSnapshotDTO> processorStatDtoCollection = new ArrayList<>();
@ -823,7 +827,7 @@ public final class DtoFactory {
final Collection<ProcessGroupStatus> childProcessGroupStatusCollection = processGroupStatus.getProcessGroupStatus();
if (childProcessGroupStatusCollection != null) {
for (final ProcessGroupStatus childProcessGroupStatus : childProcessGroupStatusCollection) {
final ProcessGroupStatusDTO childProcessGroupStatusDto = createProcessGroupStatusDto(bulletinRepository, childProcessGroupStatus);
final ProcessGroupStatusDTO childProcessGroupStatusDto = createProcessGroupStatusDto(childProcessGroupStatus);
childProcessGroupStatusDtoCollection.add(childProcessGroupStatusDto.getAggregateSnapshot());
}
}
@ -1504,11 +1508,12 @@ public final class DtoFactory {
return createProcessGroupDto(group, false);
}
public ProcessGroupFlowDTO createProcessGroupFlowDto(final ProcessGroup group, final boolean recurse) {
public ProcessGroupFlowDTO createProcessGroupFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final RevisionManager revisionManager) {
final ProcessGroupFlowDTO dto = new ProcessGroupFlowDTO();
dto.setId(group.getIdentifier());
dto.setLastRefreshed(new Date());
dto.setBreadcrumb(createBreadcrumbDto(group));
dto.setFlow(createFlowDto(group));
dto.setFlow(createFlowDto(group, groupStatus, revisionManager));
final ProcessGroup parent = group.getParent();
if (parent != null) {
@ -1518,7 +1523,7 @@ public final class DtoFactory {
return dto;
}
public FlowDTO createFlowDto(final ProcessGroup group, final FlowSnippetDTO snippet) {
public FlowDTO createFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final FlowSnippetDTO snippet, final RevisionManager revisionManager) {
if (snippet == null) {
return null;
}
@ -1526,96 +1531,172 @@ public final class DtoFactory {
final FlowDTO flow = new FlowDTO();
for (final ConnectionDTO connection : snippet.getConnections()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connection.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getConnection(connection.getId()));
flow.getConnections().add(entityFactory.createConnectionEntity(connection, null, accessPolicy));
final ConnectionStatusDTO status = getComponentStatus(
() -> groupStatus.getConnectionStatus().stream().filter(connectionStatus -> connection.getId().equals(connectionStatus.getId())).findFirst().orElse(null),
connectionStatus -> createConnectionStatusDto(connectionStatus)
);
flow.getConnections().add(entityFactory.createConnectionEntity(connection, null, accessPolicy, status));
}
for (final ControllerServiceDTO controllerService : snippet.getControllerServices()) {
flow.getControllerServices().add(entityFactory.createControllerServiceEntity(controllerService, null, null));
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(controllerService.getId()));
flow.getControllerServices().add(entityFactory.createControllerServiceEntity(controllerService, revision, null));
}
for (final FunnelDTO funnel : snippet.getFunnels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getFunnel(funnel.getId()));
flow.getFunnels().add(entityFactory.createFunnelEntity(funnel, null, accessPolicy));
flow.getFunnels().add(entityFactory.createFunnelEntity(funnel, revision, accessPolicy));
}
for (final PortDTO inputPort : snippet.getInputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getInputPort(inputPort.getId()));
flow.getInputPorts().add(entityFactory.createPortEntity(inputPort, null, accessPolicy));
final PortStatusDTO status = getComponentStatus(
() -> groupStatus.getInputPortStatus().stream().filter(inputPortStatus -> inputPort.getId().equals(inputPortStatus.getId())).findFirst().orElse(null),
inputPortStatus -> createPortStatusDto(inputPortStatus)
);
flow.getInputPorts().add(entityFactory.createPortEntity(inputPort, revision, accessPolicy, status));
}
for (final PortDTO outputPort : snippet.getOutputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getOutputPort(outputPort.getId()));
flow.getOutputPorts().add(entityFactory.createPortEntity(outputPort, null, accessPolicy));
final PortStatusDTO status = getComponentStatus(
() -> groupStatus.getOutputPortStatus().stream().filter(outputPortStatus -> outputPort.getId().equals(outputPortStatus.getId())).findFirst().orElse(null),
outputPortStatus -> createPortStatusDto(outputPortStatus)
);
flow.getOutputPorts().add(entityFactory.createPortEntity(outputPort, revision, accessPolicy, status));
}
for (final LabelDTO label : snippet.getLabels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getLabel(label.getId()));
flow.getLabels().add(entityFactory.createLabelEntity(label, null, accessPolicy));
flow.getLabels().add(entityFactory.createLabelEntity(label, revision, accessPolicy));
}
for (final ProcessGroupDTO processGroup : snippet.getProcessGroups()) {
// clear the contents as we only return a single level/group at a time
processGroup.setContents(null);
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processGroup.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessGroup(processGroup.getId()));
flow.getProcessGroups().add(entityFactory.createProcessGroupEntity(processGroup, null, accessPolicy));
final ProcessGroupStatusDTO status = getComponentStatus(
() -> groupStatus.getProcessGroupStatus().stream().filter(processGroupStatus -> processGroup.getId().equals(processGroupStatus.getId())).findFirst().orElse(null),
processGroupStatus -> createConciseProcessGroupStatusDto(processGroupStatus)
);
flow.getProcessGroups().add(entityFactory.createProcessGroupEntity(processGroup, revision, accessPolicy, status));
}
for (final ProcessorDTO processor : snippet.getProcessors()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processor.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessor(processor.getId()));
flow.getProcessors().add(entityFactory.createProcessorEntity(processor, null, accessPolicy));
final ProcessorStatusDTO status = getComponentStatus(
() -> groupStatus.getProcessorStatus().stream().filter(processorStatus -> processor.getId().equals(processorStatus.getId())).findFirst().orElse(null),
processorStatus -> createProcessorStatusDto(processorStatus)
);
flow.getProcessors().add(entityFactory.createProcessorEntity(processor, revision, accessPolicy, status));
}
for (final RemoteProcessGroupDTO remoteProcessGroup : snippet.getRemoteProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(remoteProcessGroup.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getRemoteProcessGroup(remoteProcessGroup.getId()));
flow.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(remoteProcessGroup, null, accessPolicy));
final RemoteProcessGroupStatusDTO status = getComponentStatus(
() -> groupStatus.getRemoteProcessGroupStatus().stream().filter(rpgStatus -> remoteProcessGroup.getId().equals(rpgStatus.getId())).findFirst().orElse(null),
remoteProcessGroupStatus -> createRemoteProcessGroupStatusDto(remoteProcessGroupStatus)
);
flow.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(remoteProcessGroup, revision, accessPolicy, status));
}
return flow;
}
public FlowDTO createFlowDto(final ProcessGroup group) {
private <T, S> T getComponentStatus(final Supplier<S> getComponentStatus, final Function<S, T> convertToDto) {
final T statusDTO;
final S status = getComponentStatus.get();
if (status != null) {
statusDTO = convertToDto.apply(status);
} else {
statusDTO = null;
}
return statusDTO;
}
public FlowDTO createFlowDto(final ProcessGroup group, final ProcessGroupStatus groupStatus, final RevisionManager revisionManager) {
final FlowDTO dto = new FlowDTO();
for (final ProcessorNode procNode : group.getProcessors()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(procNode.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(procNode);
dto.getProcessors().add(entityFactory.createProcessorEntity(createProcessorDto(procNode), null, accessPolicy));
final ProcessorStatusDTO status = getComponentStatus(
() -> groupStatus.getProcessorStatus().stream().filter(processorStatus -> procNode.getIdentifier().equals(processorStatus.getId())).findFirst().orElse(null),
processorStatus -> createProcessorStatusDto(processorStatus)
);
dto.getProcessors().add(entityFactory.createProcessorEntity(createProcessorDto(procNode), revision, accessPolicy, status));
}
for (final Connection connNode : group.getConnections()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connNode.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(connNode);
dto.getConnections().add(entityFactory.createConnectionEntity(createConnectionDto(connNode), null, accessPolicy));
final ConnectionStatusDTO status = getComponentStatus(
() -> groupStatus.getConnectionStatus().stream().filter(connectionStatus -> connNode.getIdentifier().equals(connectionStatus.getId())).findFirst().orElse(null),
connectionStatus -> createConnectionStatusDto(connectionStatus)
);
dto.getConnections().add(entityFactory.createConnectionEntity(createConnectionDto(connNode), revision, accessPolicy, status));
}
for (final Label label : group.getLabels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(label);
dto.getLabels().add(entityFactory.createLabelEntity(createLabelDto(label), null, accessPolicy));
dto.getLabels().add(entityFactory.createLabelEntity(createLabelDto(label), revision, accessPolicy));
}
for (final Funnel funnel : group.getFunnels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(funnel);
dto.getFunnels().add(entityFactory.createFunnelEntity(createFunnelDto(funnel), null, accessPolicy));
dto.getFunnels().add(entityFactory.createFunnelEntity(createFunnelDto(funnel), revision, accessPolicy));
}
for (final ProcessGroup childGroup : group.getProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(childGroup.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(childGroup);
dto.getProcessGroups().add(entityFactory.createProcessGroupEntity(createProcessGroupDto(childGroup), null, accessPolicy));
final ProcessGroupStatusDTO status = getComponentStatus(
() -> groupStatus.getProcessGroupStatus().stream().filter(processGroupStatus -> childGroup.getIdentifier().equals(processGroupStatus.getId())).findFirst().orElse(null),
processGroupStatus -> createConciseProcessGroupStatusDto(processGroupStatus)
);
dto.getProcessGroups().add(entityFactory.createProcessGroupEntity(createProcessGroupDto(childGroup), revision, accessPolicy, status));
}
for (final RemoteProcessGroup rpg : group.getRemoteProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(rpg.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(rpg);
dto.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(createRemoteProcessGroupDto(rpg), null, accessPolicy));
final RemoteProcessGroupStatusDTO status = getComponentStatus(
() -> groupStatus.getRemoteProcessGroupStatus().stream().filter(remoteProcessGroupStatus -> rpg.getIdentifier().equals(remoteProcessGroupStatus.getId())).findFirst().orElse(null),
remoteProcessGroupStatus -> createRemoteProcessGroupStatusDto(remoteProcessGroupStatus)
);
dto.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(createRemoteProcessGroupDto(rpg), revision, accessPolicy, status));
}
for (final Port inputPort : group.getInputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(inputPort);
dto.getInputPorts().add(entityFactory.createPortEntity(createPortDto(inputPort), null, accessPolicy));
final PortStatusDTO status = getComponentStatus(
() -> groupStatus.getInputPortStatus().stream().filter(inputPortStatus -> inputPort.getIdentifier().equals(inputPortStatus.getId())).findFirst().orElse(null),
inputPortStatus -> createPortStatusDto(inputPortStatus)
);
dto.getInputPorts().add(entityFactory.createPortEntity(createPortDto(inputPort), revision, accessPolicy, status));
}
for (final Port outputPort : group.getOutputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(outputPort);
dto.getOutputPorts().add(entityFactory.createPortEntity(createPortDto(outputPort), null, accessPolicy));
final PortStatusDTO status = getComponentStatus(
() -> groupStatus.getOutputPortStatus().stream().filter(outputPortStatus -> outputPort.getIdentifier().equals(outputPortStatus.getId())).findFirst().orElse(null),
outputPortStatus -> createPortStatusDto(outputPortStatus)
);
dto.getOutputPorts().add(entityFactory.createPortEntity(createPortDto(outputPort), revision, accessPolicy, status));
}
// TODO - controller services once they are accessible from the group
@ -2741,10 +2822,10 @@ public final class DtoFactory {
return revisionDTO;
}
public RevisionDTO createRevisionDTO(final Long version, final String clientId) {
public RevisionDTO createRevisionDTO(final Revision revision) {
final RevisionDTO dto = new RevisionDTO();
dto.setVersion(version);
dto.setClientId(clientId);
dto.setVersion(revision.getVersion());
dto.setClientId(revision.getClientId());
return dto;
}

View File

@ -16,6 +16,11 @@
*/
package org.apache.nifi.web.api.dto;
import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.entity.ConnectionEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity;
@ -31,11 +36,12 @@ import org.apache.nifi.web.api.entity.SnippetEntity;
public final class EntityFactory {
public ProcessorEntity createProcessorEntity(final ProcessorDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
public ProcessorEntity createProcessorEntity(final ProcessorDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy, final ProcessorStatusDTO status) {
final ProcessorEntity entity = new ProcessorEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId());
entity.setPosition(dto.getPosition());
if (accessPolicy != null && accessPolicy.getCanRead()) {
@ -45,11 +51,12 @@ public final class EntityFactory {
return entity;
}
public PortEntity createPortEntity(final PortDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
public PortEntity createPortEntity(final PortDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy, final PortStatusDTO status) {
final PortEntity entity = new PortEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId());
entity.setPosition(dto.getPosition());
entity.setPortType(dto.getType());
@ -60,13 +67,22 @@ public final class EntityFactory {
return entity;
}
public ProcessGroupEntity createProcessGroupEntity(final ProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
public ProcessGroupEntity createProcessGroupEntity(final ProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy, final ProcessGroupStatusDTO status) {
final ProcessGroupEntity entity = new ProcessGroupEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId());
entity.setPosition(dto.getPosition());
entity.setInputPortCount(dto.getInputPortCount());
entity.setOutputPortCount(dto.getOutputPortCount());
entity.setRunningCount(dto.getRunningCount());
entity.setStoppedCount(dto.getStoppedCount());
entity.setInvalidCount(dto.getInvalidCount());
entity.setDisabledCount(dto.getDisabledCount());
entity.setActiveRemotePortCount(dto.getActiveRemotePortCount());
entity.setInactiveRemotePortCount(dto.getInactiveRemotePortCount());
if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto);
}
@ -108,11 +124,12 @@ public final class EntityFactory {
return entity;
}
public ConnectionEntity createConnectionEntity(final ConnectionDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
public ConnectionEntity createConnectionEntity(final ConnectionDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy, final ConnectionStatusDTO status) {
final ConnectionEntity entity = new ConnectionEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId());
entity.setPosition(dto.getPosition());
entity.setBends(dto.getBends());
@ -142,13 +159,18 @@ public final class EntityFactory {
return entity;
}
public RemoteProcessGroupEntity createRemoteProcessGroupEntity(final RemoteProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
public RemoteProcessGroupEntity createRemoteProcessGroupEntity(
final RemoteProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy,final RemoteProcessGroupStatusDTO status) {
final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
entity.setRevision(revision);
if (dto != null) {
entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId());
entity.setPosition(dto.getPosition());
entity.setInputPortCount(dto.getInputPortCount());
entity.setOutputPortCount(dto.getOutputPortCount());
if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto);
}

View File

@ -102,12 +102,7 @@ import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO;
import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO.LineageRequestType;
import org.apache.nifi.web.api.dto.search.ComponentSearchResultDTO;
import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.security.ProxiedEntitiesUtils;
import org.slf4j.Logger;
@ -494,12 +489,12 @@ public class ControllerFacade implements Authorizable {
* @param groupId group id
* @return the status for the specified process group
*/
public ProcessGroupStatusDTO getProcessGroupStatus(final String groupId) {
public ProcessGroupStatus getProcessGroupStatus(final String groupId) {
final ProcessGroupStatus processGroupStatus = flowController.getGroupStatus(groupId);
if (processGroupStatus == null) {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
return dtoFactory.createProcessGroupStatusDto(flowController.getBulletinRepository(), processGroupStatus);
return processGroupStatus;
}
/**
@ -508,7 +503,7 @@ public class ControllerFacade implements Authorizable {
* @param processorId processor id
* @return the status for the specified processor
*/
public ProcessorStatusDTO getProcessorStatus(final String processorId) {
public ProcessorStatus getProcessorStatus(final String processorId) {
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final ProcessorNode processor = root.findProcessor(processorId);
@ -524,13 +519,12 @@ public class ControllerFacade implements Authorizable {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
for (final ProcessorStatus processorStatus : processGroupStatus.getProcessorStatus()) {
if (processorId.equals(processorStatus.getId())) {
return dtoFactory.createProcessorStatusDto(processorStatus);
}
final ProcessorStatus status = processGroupStatus.getProcessorStatus().stream().filter(processorStatus -> processorId.equals(processorStatus.getId())).findFirst().orElse(null);
if (status == null) {
throw new ResourceNotFoundException(String.format("Unable to locate processor with id '%s'.", processorId));
}
throw new ResourceNotFoundException(String.format("Unable to locate processor with id '%s'.", processorId));
return status;
}
/**
@ -539,7 +533,7 @@ public class ControllerFacade implements Authorizable {
* @param connectionId connection id
* @return the status for the specified connection
*/
public ConnectionStatusDTO getConnectionStatus(final String connectionId) {
public ConnectionStatus getConnectionStatus(final String connectionId) {
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Connection connection = root.findConnection(connectionId);
@ -555,13 +549,12 @@ public class ControllerFacade implements Authorizable {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
for (final ConnectionStatus connectionStatus : processGroupStatus.getConnectionStatus()) {
if (connectionId.equals(connectionStatus.getId())) {
return dtoFactory.createConnectionStatusDto(connectionStatus);
}
final ConnectionStatus status = processGroupStatus.getConnectionStatus().stream().filter(connectionStatus -> connectionId.equals(connectionStatus.getId())).findFirst().orElse(null);
if (status == null) {
throw new ResourceNotFoundException(String.format("Unable to locate connection with id '%s'.", connectionId));
}
throw new ResourceNotFoundException(String.format("Unable to locate connection with id '%s'.", connectionId));
return status;
}
/**
@ -570,7 +563,7 @@ public class ControllerFacade implements Authorizable {
* @param portId input port id
* @return the status for the specified input port
*/
public PortStatusDTO getInputPortStatus(final String portId) {
public PortStatus getInputPortStatus(final String portId) {
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Port port = root.findInputPort(portId);
@ -585,13 +578,12 @@ public class ControllerFacade implements Authorizable {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
for (final PortStatus portStatus : processGroupStatus.getInputPortStatus()) {
if (portId.equals(portStatus.getId())) {
return dtoFactory.createPortStatusDto(portStatus);
}
final PortStatus status = processGroupStatus.getInputPortStatus().stream().filter(portStatus -> portId.equals(portStatus.getId())).findFirst().orElse(null);
if (status == null) {
throw new ResourceNotFoundException(String.format("Unable to locate input port with id '%s'.", portId));
}
throw new ResourceNotFoundException(String.format("Unable to locate input port with id '%s'.", portId));
return status;
}
/**
@ -600,7 +592,7 @@ public class ControllerFacade implements Authorizable {
* @param portId output port id
* @return the status for the specified output port
*/
public PortStatusDTO getOutputPortStatus(final String portId) {
public PortStatus getOutputPortStatus(final String portId) {
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Port port = root.findOutputPort(portId);
@ -615,13 +607,12 @@ public class ControllerFacade implements Authorizable {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
for (final PortStatus portStatus : processGroupStatus.getOutputPortStatus()) {
if (portId.equals(portStatus.getId())) {
return dtoFactory.createPortStatusDto(portStatus);
}
final PortStatus status = processGroupStatus.getOutputPortStatus().stream().filter(portStatus -> portId.equals(portStatus.getId())).findFirst().orElse(null);
if (status == null) {
throw new ResourceNotFoundException(String.format("Unable to locate output port with id '%s'.", portId));
}
throw new ResourceNotFoundException(String.format("Unable to locate output port with id '%s'.", portId));
return status;
}
/**
@ -630,7 +621,7 @@ public class ControllerFacade implements Authorizable {
* @param remoteProcessGroupId remote process group id
* @return the status for the specified remote process group
*/
public RemoteProcessGroupStatusDTO getRemoteProcessGroupStatus(final String remoteProcessGroupId) {
public RemoteProcessGroupStatus getRemoteProcessGroupStatus(final String remoteProcessGroupId) {
final ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final RemoteProcessGroup remoteProcessGroup = root.findRemoteProcessGroup(remoteProcessGroupId);
@ -640,18 +631,17 @@ public class ControllerFacade implements Authorizable {
}
final String groupId = remoteProcessGroup.getProcessGroup().getIdentifier();
final ProcessGroupStatus processGroupStatus = flowController.getGroupStatus(groupId);
if (processGroupStatus == null) {
final ProcessGroupStatus groupStatus = flowController.getGroupStatus(groupId);
if (groupStatus == null) {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
}
for (final RemoteProcessGroupStatus remoteProcessGroupStatus : processGroupStatus.getRemoteProcessGroupStatus()) {
if (remoteProcessGroupId.equals(remoteProcessGroupStatus.getId())) {
return dtoFactory.createRemoteProcessGroupStatusDto(remoteProcessGroupStatus);
}
final RemoteProcessGroupStatus status = groupStatus.getRemoteProcessGroupStatus().stream().filter(rpgStatus -> remoteProcessGroupId.equals(rpgStatus.getId())).findFirst().orElse(null);
if (status == null) {
throw new ResourceNotFoundException(String.format("Unable to locate remote process group with id '%s'.", remoteProcessGroupId));
}
throw new ResourceNotFoundException(String.format("Unable to locate remote process group with id '%s'.", remoteProcessGroupId));
return status;
}
/**

View File

@ -152,7 +152,7 @@ md-toolbar.md-small .md-toolbar-tools {
}
#current-user {
font-family: 'Roboto+Slab';
font-family: 'Roboto Slab';
font-style: normal;
font-weight: normal;
font-size: 12px;

View File

@ -102,7 +102,7 @@ div.graph-control-header-icon {
div.graph-control-header {
float: left;
font-size: 12px;
font-family: 'Roboto+Slab';
font-family: 'Roboto Slab';
color: #262626;
letter-spacing: 0.05rem;
line-height: 15px;

View File

@ -510,7 +510,7 @@
}
// if this descriptor identifies a controller service, provide a way to create one
if (nf.Common.isDefinedAndNotNull(propertyDescriptor.identifiesControllerService)) {
if (nf.Common.isDefinedAndNotNull(propertyDescriptor.identifiesControllerService) && nf.Common.isDefinedAndNotNull(configurationOptions.groupId)) {
options.push({
text: 'Create new service...',
value: undefined,
@ -885,23 +885,21 @@
var create = function () {
var newControllerServiceType = newControllerServiceCombo.combo('getSelectedOption').value;
// create service of the specified type
var revision = nf.Client.getRevision();
// build the controller service entity
var controllerServiceEntity = {
'controllerService': {
'type': newControllerServiceType
}
};
// add the new controller service
$.ajax({
type: 'POST',
url: '../nifi-api/controller-services/node',
data: {
version: revision.version,
clientId: revision.clientId,
type: newControllerServiceType
},
dataType: 'json'
url: '../nifi-api/process-groups/' + encodeURIComponent(configurationOptions.groupId) + '/controller-services/node',
data: JSON.stringify(controllerServiceEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// load the descriptor and update the property
configurationOptions.descriptorDeferred(item.property).done(function(descriptorResponse) {
var descriptor = descriptorResponse.propertyDescriptor;

View File

@ -134,7 +134,7 @@ nf.ng.Canvas.OperateCtrl = function () {
if (color !== selectedData.component.style['background-color']) {
// build the request entity
var entity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(selectedData),
'component': {
'id': selectedData.id,
'style': {
@ -151,9 +151,6 @@ nf.ng.Canvas.OperateCtrl = function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// update the component
nf[selectedData.type].set(response);
}).fail(function (xhr, status, error) {

View File

@ -64,7 +64,6 @@ nf.ng.FunnelComponent = function (serviceProvider) {
*/
createFunnel: function(pt) {
var outputPortEntity = {
'revision': nf.Client.getRevision(),
'component': {
'position': {
'x': pt.x,
@ -82,9 +81,6 @@ nf.ng.FunnelComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the funnel to the graph
nf.Graph.add({
'funnels': [response]

View File

@ -28,7 +28,6 @@ nf.ng.GroupComponent = function (serviceProvider) {
*/
var createGroup = function (groupName, pt) {
var processGroupEntity = {
'revision': nf.Client.getRevision(),
'component': {
'name': groupName,
'position': {
@ -47,9 +46,6 @@ nf.ng.GroupComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the process group to the graph
nf.Graph.add({
'processGroups': [response]

View File

@ -28,7 +28,6 @@ nf.ng.InputPortComponent = function (serviceProvider) {
*/
var createInputPort = function (portName, pt) {
var inputPortEntity = {
'revision': nf.Client.getRevision(),
'component': {
'name': portName,
'position': {
@ -47,9 +46,6 @@ nf.ng.InputPortComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the port to the graph
nf.Graph.add({
'inputPorts': [response]

View File

@ -64,7 +64,6 @@ nf.ng.LabelComponent = function (serviceProvider) {
*/
createLabel: function(pt) {
var labelEntity = {
'revision': nf.Client.getRevision(),
'component': {
'width': nf.Label.config.width,
'height': nf.Label.config.height,
@ -84,9 +83,6 @@ nf.ng.LabelComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the label to the graph
nf.Graph.add({
'labels': [response]

View File

@ -28,7 +28,6 @@ nf.ng.OutputPortComponent = function (serviceProvider) {
*/
var createOutputPort = function (portName, pt) {
var outputPortEntity = {
'revision': nf.Client.getRevision(),
'component': {
'name': portName,
'position': {
@ -47,9 +46,6 @@ nf.ng.OutputPortComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the port to the graph
nf.Graph.add({
'outputPorts': [response]

View File

@ -202,7 +202,6 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
*/
var createProcessor = function (name, processorType, pt) {
var processorEntity = {
'revision': nf.Client.getRevision(),
'component': {
'type': processorType,
'name': name,
@ -222,9 +221,6 @@ nf.ng.ProcessorComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the processor to the graph
nf.Graph.add({
'processors': [response]

View File

@ -28,7 +28,6 @@ nf.ng.RemoteProcessGroupComponent = function (serviceProvider) {
*/
var createRemoteProcessGroup = function (remoteProcessGroupUri, pt) {
var remoteProcessGroupEntity = {
'revision': nf.Client.getRevision(),
'component': {
'targetUri': remoteProcessGroupUri,
'position': {
@ -47,9 +46,6 @@ nf.ng.RemoteProcessGroupComponent = function (serviceProvider) {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// add the processor to the graph
nf.Graph.add({
'remoteProcessGroups': [response]

View File

@ -28,7 +28,6 @@ nf.ng.TemplateComponent = function (serviceProvider) {
*/
var createTemplate = function (templateId, pt) {
var instantiateTemplateInstance = {
'revision': nf.Client.getRevision(),
'templateId': templateId,
'originX': pt.x,
'originY': pt.y
@ -42,9 +41,6 @@ nf.ng.TemplateComponent = function (serviceProvider) {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// populate the graph accordingly
nf.Graph.add(response.flow, true);

View File

@ -60,18 +60,12 @@ nf.Actions = (function () {
* @param {object} entity
*/
var updateResource = function (uri, entity) {
// add the revision
entity['revision'] = nf.Client.getRevision();
return $.ajax({
type: 'PUT',
url: uri,
data: JSON.stringify(entity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
}).fail(function (xhr, status, error) {
if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
nf.Dialog.showOkDialog({
@ -404,6 +398,7 @@ nf.Actions = (function () {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': {
'id': d.id,
'state': 'STOPPED'
@ -446,6 +441,7 @@ nf.Actions = (function () {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': {
'id': d.id,
'state': 'DISABLED'
@ -528,6 +524,7 @@ nf.Actions = (function () {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': component
};
@ -602,6 +599,7 @@ nf.Actions = (function () {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': component
};
@ -644,6 +642,7 @@ nf.Actions = (function () {
componentsToEnable.each(function (d) {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': {
'id': d.id,
'transmitting': true
@ -671,6 +670,7 @@ nf.Actions = (function () {
componentsToDisable.each(function (d) {
// build the entity
var entity = {
'revision': nf.Client.getRevision(d),
'component': {
'id': d.id,
'transmitting': false
@ -772,8 +772,10 @@ nf.Actions = (function () {
/**
* Reloads the status for the entire canvas (components and flow.)
*/
reloadStatus: function () {
nf.Canvas.reloadStatus();
reload: function () {
nf.Canvas.reload({
'transition': true
});
},
/**
@ -790,7 +792,7 @@ nf.Actions = (function () {
} else {
if (selection.size() === 1) {
var selectionData = selection.datum();
var revision = nf.Client.getRevision();
var revision = nf.Client.getRevision(selectionData);
$.ajax({
type: 'DELETE',
@ -800,9 +802,6 @@ nf.Actions = (function () {
}),
dataType: 'json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// remove the component/connection in question
nf[selectionData.type].remove(selectionData.id);
@ -828,11 +827,9 @@ nf.Actions = (function () {
} else {
// create a snippet for the specified component and link to the data flow
var snippetDetails = nf.Snippet.marshal(selection, true);
nf.Snippet.create(snippetDetails).done(function (response) {
var snippet = response.snippet;
nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
// remove the snippet, effectively removing the components
nf.Snippet.remove(snippet.id).done(function () {
nf.Snippet.remove(snippetEntity).done(function () {
var components = d3.map();
// add the id to the type's array
@ -876,11 +873,11 @@ nf.Actions = (function () {
// inform Angular app values have changed
nf.ng.Bridge.digest();
}).fail(function (xhr, status, error) {
// unable to acutally remove the components so attempt to
// unable to actually remove the components so attempt to
// unlink and remove just the snippet - if unlinking fails
// just ignore
nf.Snippet.unlink(snippet.id).done(function () {
nf.Snippet.remove(snippet.id);
nf.Snippet.unlink(snippetEntity).done(function (unlinkedSnippetEntity) {
nf.Snippet.remove(unlinkedSnippetEntity);
});
nf.Common.handleAjaxError(xhr, status, error);
@ -1092,7 +1089,7 @@ nf.Actions = (function () {
var processor = selection.datum();
// view the state for the selected processor
nf.ComponentState.showState(processor.component, nf.CanvasUtils.supportsModification(selection));
nf.ComponentState.showState(processor.component, processor.revision, nf.CanvasUtils.supportsModification(selection));
},
/**
@ -1228,12 +1225,11 @@ nf.Actions = (function () {
var snippetDetails = nf.Snippet.marshal(selection, false);
// create the snippet
nf.Snippet.create(snippetDetails).done(function (response) {
var snippet = response.snippet;
nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
var createSnippetEntity = {
'name': templateName,
'description': templateDescription,
'snippetId': snippet.id
'snippetId': snippetEntity.id
};
// create the template
@ -1251,7 +1247,7 @@ nf.Actions = (function () {
});
}).always(function () {
// remove the snippet
nf.Snippet.remove(snippet.id);
nf.Snippet.remove(snippetEntity);
// clear the template dialog fields
$('#new-template-name').val('');
@ -1327,9 +1323,7 @@ nf.Actions = (function () {
};
// create a snippet from the details
nf.Snippet.create(data['snippet']).done(function (createResponse) {
var snippet = createResponse.snippet;
nf.Snippet.create(data['snippet']).done(function (snippetEntity) {
// determine the origin of the bounding box of the copy
var origin = pasteLocation;
var snippetOrigin = data['origin'];
@ -1342,7 +1336,7 @@ nf.Actions = (function () {
}
// copy the snippet to the new location
nf.Snippet.copy(snippet.id, origin).done(function (copyResponse) {
nf.Snippet.copy(snippetEntity.id, origin).done(function (copyResponse) {
var snippetFlow = copyResponse.flow;
// update the graph accordingly
@ -1355,7 +1349,7 @@ nf.Actions = (function () {
nf.Birdseye.refresh();
// remove the original snippet
nf.Snippet.remove(snippet.id).fail(reject);
nf.Snippet.remove(snippetEntity).fail(reject);
}).fail(function () {
// an error occured while performing the copy operation, reload the
// graph in case it was a partial success
@ -1414,7 +1408,7 @@ nf.Actions = (function () {
// build the connection entity
var connectionEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(connection),
'component': {
'id': connection.id,
'zIndex': zIndex
@ -1432,9 +1426,6 @@ nf.Actions = (function () {
// update the edge's zIndex
nf.Connection.set(response);
nf.Connection.reorder();
// update the revision
nf.Client.setRevision(response.revision);
});
}
}

View File

@ -57,11 +57,9 @@ nf.CanvasUtils = (function () {
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;
nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
// move the snippet into the target
nf.Snippet.move(snippet.id, groupId).done(function () {
nf.Snippet.move(snippetEntity, groupId).done(function () {
var componentMap = d3.map();
// add the id to the type's array
@ -90,8 +88,8 @@ nf.CanvasUtils = (function () {
}).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);
nf.Snippet.unlink(snippetEntity).done(function (unlinkedSnippetEntity) {
nf.Snippet.remove(unlinkedSnippetEntity);
});
});
}).fail(nf.Common.handleAjaxError).fail(function () {
@ -200,7 +198,10 @@ nf.CanvasUtils = (function () {
var refreshGraph = $.Deferred(function (deferred) {
// load a different group if necessary
if (groupId !== nf.Canvas.getGroupId()) {
// set the new group id
nf.Canvas.setGroupId(groupId);
// reload
nf.Canvas.reload().done(function () {
deferred.resolve();
}).fail(function () {
@ -258,21 +259,60 @@ nf.CanvasUtils = (function () {
// calculate the difference between the center point and the position of this component and convert to screen space
nf.Canvas.View.translate([(center[0] - boundingBox.x) * scale, (center[1] - boundingBox.y) * scale]);
},
/**
* Enables/disables the editable behavior for the specified selection based on their access policies.
*
* @param selection selection
*/
editable: function (selection) {
var selectionData = selection.datum();
if (selectionData.accessPolicy.canWrite && selectionData.accessPolicy.canRead) {
if (!selection.classed('connectable')) {
selection.call(nf.Connectable.activate);
}
if (!selection.classed('moveable')) {
selection.call(nf.Draggable.activate);
}
} else {
if (selection.classed('connectable')) {
selection.call(nf.Connectable.deactivate);
}
if (selection.classed('moveable')) {
selection.call(nf.Draggable.deactivate);
}
}
},
/**
* Conditionally apply the transition.
*
* @param selection selection
* @param transition transition
*/
transition: function (selection, transition) {
if (transition && !selection.empty()) {
return selection.transition().duration(400);
} else {
return selection;
}
},
/**
* Position the component accordingly.
*
* @param {selection} updated
*/
position: function (updated) {
position: function (updated, transition) {
if (updated.empty()) {
return;
}
// update the processors positioning
updated.attr('transform', function (d) {
return 'translate(' + d.position.x + ', ' + d.position.y + ')';
});
return nf.CanvasUtils.transition(updated, transition)
.attr('transform', function (d) {
return 'translate(' + d.position.x + ', ' + d.position.y + ')';
});
},
/**
@ -458,7 +498,7 @@ nf.CanvasUtils = (function () {
}
// if there are bulletins show them, otherwise hide
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins)) {
if (!nf.Common.isEmpty(d.status.bulletins)) {
// update the tooltip
selection.select('text.bulletin-icon')
.each(function () {
@ -1135,9 +1175,6 @@ nf.CanvasUtils = (function () {
// set the new group id
nf.Canvas.setGroupId(groupId);
// clear the current components
nf.Graph.removeAll();
// reload the graph
return nf.Canvas.reload().done(function () {
// attempt to restore the view

View File

@ -108,8 +108,7 @@ nf.Canvas = (function () {
var MIN_SCALE = 0.2;
var MIN_SCALE_TO_RENDER = 0.6;
var revisionPolling = false;
var statusPolling = false;
var polling = false;
var groupId = 'root';
var groupName = null;
var parentGroupId = null;
@ -135,58 +134,31 @@ nf.Canvas = (function () {
};
/**
* Starts polling for the revision.
* Starts polling.
*
* @argument {int} autoRefreshInterval The auto refresh interval
*/
var startRevisionPolling = function (autoRefreshInterval) {
var startPolling = function (autoRefreshInterval) {
// set polling flag
revisionPolling = true;
pollForRevision(autoRefreshInterval);
polling = true;
poll(autoRefreshInterval);
};
/**
* Polls for the revision.
* Register the pooler.
*
* @argument {int} autoRefreshInterval The auto refresh interval
*/
var pollForRevision = function (autoRefreshInterval) {
var poll = function (autoRefreshInterval) {
// ensure we're suppose to poll
if (revisionPolling) {
// check the revision
checkRevision().done(function () {
// start the wait to poll again
setTimeout(function () {
pollForRevision(autoRefreshInterval);
}, autoRefreshInterval * 1000);
});
}
};
/**
* Start polling for the status.
*
* @argument {int} autoRefreshInterval The auto refresh interval
*/
var startStatusPolling = function (autoRefreshInterval) {
// set polling flag
statusPolling = true;
pollForStatus(autoRefreshInterval);
};
/**
* Register the status poller.
*
* @argument {int} autoRefreshInterval The auto refresh interval
*/
var pollForStatus = function (autoRefreshInterval) {
// ensure we're suppose to poll
if (statusPolling) {
if (polling) {
// reload the status
nf.Canvas.reloadStatus().done(function () {
nf.Canvas.reload({
'transition': true
}).done(function () {
// start the wait to poll again
setTimeout(function () {
pollForStatus(autoRefreshInterval);
poll(autoRefreshInterval);
}, autoRefreshInterval * 1000);
});
}
@ -195,50 +167,50 @@ nf.Canvas = (function () {
/**
* Checks the current revision against this version of the flow.
*/
var checkRevision = function () {
// get the revision
return $.ajax({
type: 'GET',
url: config.urls.revision,
dataType: 'json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.revision)) {
var revision = response.revision;
var currentRevision = nf.Client.getRevision();
// if there is a newer revision, there are outstanding
// changes that need to be updated
if (revision.version > currentRevision.version && revision.clientId !== currentRevision.clientId) {
var refreshContainer = $('#refresh-required-container');
var settingsRefreshIcon = $('#settings-refresh-required-icon');
// insert the refresh needed text in the canvas - if necessary
if (!refreshContainer.is(':visible')) {
$('#stats-last-refreshed').addClass('alert');
var refreshMessage = "This flow has been modified by '" + revision.lastModifier + "'. Please refresh.";
// update the tooltip
var refreshRequiredIcon = $('#refresh-required-icon');
if (refreshRequiredIcon.data('qtip')) {
refreshRequiredIcon.qtip('option', 'content.text', refreshMessage);
} else {
refreshRequiredIcon.qtip($.extend({
content: refreshMessage
}, nf.CanvasUtils.config.systemTooltipConfig));
}
refreshContainer.show();
}
// insert the refresh needed text in the settings - if necessary
if (!settingsRefreshIcon.is(':visible')) {
$('#settings-last-refreshed').addClass('alert');
settingsRefreshIcon.show();
}
}
}
}).fail(nf.Common.handleAjaxError);
};
// var checkRevision = function () {
// // get the revision
// return $.ajax({
// type: 'GET',
// url: config.urls.revision,
// dataType: 'json'
// }).done(function (response) {
// if (nf.Common.isDefinedAndNotNull(response.revision)) {
// var revision = response.revision;
// var currentRevision = nf.Client.getRevision();
//
// // if there is a newer revision, there are outstanding
// // changes that need to be updated
// if (revision.version > currentRevision.version && revision.clientId !== currentRevision.clientId) {
// var refreshContainer = $('#refresh-required-container');
// var settingsRefreshIcon = $('#settings-refresh-required-icon');
//
// // insert the refresh needed text in the canvas - if necessary
// if (!refreshContainer.is(':visible')) {
// $('#stats-last-refreshed').addClass('alert');
// var refreshMessage = "This flow has been modified by '" + revision.lastModifier + "'. Please refresh.";
//
// // update the tooltip
// var refreshRequiredIcon = $('#refresh-required-icon');
// if (refreshRequiredIcon.data('qtip')) {
// refreshRequiredIcon.qtip('option', 'content.text', refreshMessage);
// } else {
// refreshRequiredIcon.qtip($.extend({
// content: refreshMessage
// }, nf.CanvasUtils.config.systemTooltipConfig));
// }
//
// refreshContainer.show();
// }
//
// // insert the refresh needed text in the settings - if necessary
// if (!settingsRefreshIcon.is(':visible')) {
// $('#settings-last-refreshed').addClass('alert');
// settingsRefreshIcon.show();
// }
// }
// }
// }).fail(nf.Common.handleAjaxError);
// };
/**
* Initializes the canvas.
@ -555,7 +527,7 @@ nf.Canvas = (function () {
if (isCtrl) {
if (evt.keyCode === 82) {
// ctrl-r
nf.Actions.reloadStatus();
nf.Actions.reload();
// default prevented in nf-universal-capture.js
} else if (evt.keyCode === 65) {
@ -631,8 +603,9 @@ nf.Canvas = (function () {
* Refreshes the graph.
*
* @argument {string} processGroupId The process group id
* @argument {object} options Configuration options
*/
var reloadProcessGroup = function (processGroupId) {
var reloadProcessGroup = function (processGroupId, options) {
// load the controller
return $.ajax({
type: 'GET',
@ -642,9 +615,6 @@ nf.Canvas = (function () {
},
dataType: 'json'
}).done(function (flowResponse) {
// set the revision
nf.Client.setRevision(flowResponse.revision);
// get the controller and its contents
var processGroupFlow = flowResponse.processGroupFlow;
@ -654,6 +624,10 @@ nf.Canvas = (function () {
// update the breadcrumbs
nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetBreadcrumbs();
nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').generateBreadcrumbs(processGroupFlow.breadcrumb);
nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetScrollPosition();
// update the timestamp
$('#stats-last-refreshed').text(processGroupFlow.lastRefreshed);
// set the parent id if applicable
if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) {
@ -662,57 +636,22 @@ nf.Canvas = (function () {
nf.Canvas.setParentGroupId(null);
}
// since we're getting a new group, we want to clear it
nf.Graph.removeAll();
// refresh the graph
nf.Graph.add(processGroupFlow.flow, false);
nf.Graph.set(processGroupFlow.flow, $.extend({
'selectAll': false
}, options));
// update component visibility
nf.Canvas.View.updateVisibility();
// update the birdseye
nf.Birdseye.refresh();
// inform Angular app values have changed
nf.ng.Bridge.digest();
}).fail(nf.Common.handleAjaxError);
};
/**
* Refreshes the status for the resources that exist in the specified process group.
*
* @argument {string} processGroupId The id of the process group
*/
var reloadStatus = function (processGroupId) {
// get the stats
return $.Deferred(function (deferred) {
$.ajax({
type: 'GET',
url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupId) + '/status',
data: {
recursive: false
},
dataType: 'json'
}).done(function (response) {
// report the updated stats
if (nf.Common.isDefinedAndNotNull(response.processGroupStatus)) {
var processGroupStatus = response.processGroupStatus;
var aggregateSnapshot = processGroupStatus.aggregateSnapshot;
// update all the stats
nf.Graph.setStatus(aggregateSnapshot);
// update the timestamp
$('#stats-last-refreshed').text(processGroupStatus.statsLastRefreshed);
}
deferred.resolve();
}).fail(function (xhr, status, error) {
// if clustered, a 404 likely means the flow status at the ncm is stale
if (!nf.Canvas.isClustered() || xhr.status !== 404) {
nf.Common.handleAjaxError(xhr, status, error);
deferred.reject();
} else {
deferred.resolve();
}
});
}).promise();
};
return {
CANVAS_OFFSET: 0,
@ -728,59 +667,29 @@ nf.Canvas = (function () {
$('#splash').fadeOut();
},
/**
* Stop polling for revision.
*/
stopRevisionPolling: function () {
// set polling flag
revisionPolling = false;
},
/**
* Remove the status poller.
*/
stopStatusPolling: function () {
stopPolling: function () {
// set polling flag
statusPolling = false;
polling = false;
},
/**
* Reloads the flow from the server based on the currently specified group id.
* To load another group, update nf.Canvas.setGroupId and call nf.Canvas.reload.
* To load another group, update nf.Canvas.setGroupId, clear the canvas, and call nf.Canvas.reload.
*/
reload: function () {
reload: function (options) {
return $.Deferred(function (deferred) {
// hide the context menu
nf.ContextMenu.hide();
// get the process group to refresh everything
var processGroupXhr = reloadProcessGroup(nf.Canvas.getGroupId());
var processGroupXhr = reloadProcessGroup(nf.Canvas.getGroupId(), options);
var statusXhr = nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl.flowStatusCtrl').reloadFlowStatus();
var settingsXhr = nf.Settings.loadSettings(false); // don't reload the status as we want to wait for deferreds to complete
$.when(processGroupXhr, statusXhr, settingsXhr).done(function (processGroupResult) {
// adjust breadcrumbs if necessary
nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetScrollPosition();
// don't load the status until the graph is loaded
reloadStatus(nf.Canvas.getGroupId()).done(function () {
deferred.resolve(processGroupResult);
}).fail(function () {
deferred.reject();
});
});
}).promise();
},
/**
* Reloads the status.
*/
reloadStatus: function () {
return $.Deferred(function (deferred) {
// refresh the status and check any bulletins
$.when(reloadStatus(nf.Canvas.getGroupId()),
nf.ng.Bridge.get('appCtrl.serviceProvider.headerCtrl.flowStatusCtrl').reloadFlowStatus(),
checkRevision()).done(function () {
deferred.resolve();
deferred.resolve(processGroupResult);
}).fail(function () {
deferred.reject();
});
@ -863,6 +772,9 @@ nf.Canvas = (function () {
});
}).promise();
userXhr.done(function () {
// load the client id
var clientXhr = nf.Client.init();
// get the controller config to register the status poller
var configXhr = $.ajax({
type: 'GET',
@ -889,7 +801,7 @@ nf.Canvas = (function () {
}).promise();
// ensure the config requests are loaded
$.when(configXhr, userXhr).done(function (configResult) {
$.when(configXhr, userXhr, clientXhr).done(function (configResult, loginResult, aboutResult) {
var configResponse = configResult[0];
// calculate the canvas offset
@ -953,10 +865,9 @@ nf.Canvas = (function () {
// determine the split between the polling
var pollingSplit = autoRefreshIntervalSeconds / 2;
// register the revision and status polling
startRevisionPolling(autoRefreshIntervalSeconds);
// register the polling
setTimeout(function () {
startStatusPolling(autoRefreshIntervalSeconds);
startPolling(autoRefreshIntervalSeconds);
}, pollingSplit * 1000);
// hide the splash screen

View File

@ -205,6 +205,7 @@ nf.ComponentState = (function () {
// clear the component
$('#component-state-table').removeData('component');
$('#component-state-table').removeData('revision');
};
return {
@ -251,11 +252,13 @@ nf.ComponentState = (function () {
var stateEntryCount = componentStateGrid.getDataLength();
if (stateEntryCount > 0) {
var revision = componentStateTable.data('revision');
// clear the state
var revision = {
'revision': nf.Client.getRevision()
'revision': revision
};
var component = componentStateTable.data('component');
$.ajax({
type: 'POST',
@ -263,8 +266,8 @@ nf.ComponentState = (function () {
data: JSON.stringify(revision),
dataType: 'json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// clear the table
clearTable();
@ -356,7 +359,7 @@ nf.ComponentState = (function () {
* @param {object} component
* @param {boolean} canClear
*/
showState: function (component, canClear) {
showState: function (component, revision, canClear) {
return $.ajax({
type: 'GET',
url: component.uri + '/state',
@ -374,6 +377,7 @@ nf.ComponentState = (function () {
// store the component
componentStateTable.data('component', component);
componentStateTable.data('revision', revision);
// show the dialog
$('#component-state-dialog').modal('show');

View File

@ -25,13 +25,13 @@ nf.Connectable = (function () {
/**
* Determines if we want to allow adding connections in the current state:
*
*
* 1) When shift is down, we could be adding components to the current selection.
* 2) When the selection box is visible, we are in the process of moving all the
* components currently selected.
* 3) When the drag selection box is visible, we are in the process or selecting components
* using the selection box.
*
*
* @returns {boolean}
*/
var allowConnection = function () {
@ -44,207 +44,217 @@ nf.Connectable = (function () {
// dragging behavior for the connector
connect = d3.behavior.drag()
.origin(function (d) {
origin = d3.mouse(canvas.node());
return {
x: origin[0],
y: origin[1]
};
})
.on('dragstart', function (d) {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
.origin(function (d) {
origin = d3.mouse(canvas.node());
return {
x: origin[0],
y: origin[1]
};
})
.on('dragstart', function (d) {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
// unselect the previous components
nf.CanvasUtils.getSelection().classed('selected', false);
// unselect the previous components
nf.CanvasUtils.getSelection().classed('selected', false);
// mark the source component has selected
var source = d3.select(this.parentNode).classed('selected', true);
// mark the source component has selected
var source = d3.select(this.parentNode).classed('selected', true);
// mark this component as dragging and selected
d3.select(this).classed('dragging', true);
// mark this component as dragging and selected
d3.select(this).classed('dragging', true);
// mark the source of the drag
// mark the source of the drag
var sourceData = source.datum();
// start the drag line and insert it first to keep it on the bottom
var position = d3.mouse(canvas.node());
canvas.insert('path', ':first-child')
.datum({
'sourceId': sourceData.id,
'sourceWidth': sourceData.dimensions.width,
'x': position[0],
'y': position[1]
})
.attr({
'class': 'connector',
'd': function (pathDatum) {
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + pathDatum.x + ' ' + pathDatum.y;
}
});
// updates the location of the connection img
d3.select(this).attr('transform', function () {
return 'translate(' + position[0] + ', ' + (position[1] + 20) + ')';
});
// re-append the image to keep it on top
canvas.node().appendChild(this);
})
.on('drag', function (d) {
// updates the location of the connection img
d3.select(this).attr('transform', function () {
return 'translate(' + d3.event.x + ', ' + (d3.event.y + 20) + ')';
});
// mark node's connectable if supported
var destination = d3.select('g.hover').classed('connectable-destination', function () {
// ensure the mouse has moved at least 10px in any direction, it seems that
// when the drag event is trigger is not consistent between browsers. as a result
// some browser would trigger when the mouse hadn't moved yet which caused
// click and contextmenu events to appear like an attempt to connection the
// component to itself. requiring the mouse to have actually moved before
// checking the eligiblity of the destination addresses the issue
return (Math.abs(origin[0] - d3.event.x) > 10 || Math.abs(origin[1] - d3.event.y) > 10) &&
nf.CanvasUtils.isValidConnectionDestination(d3.select(this));
});
// update the drag line
d3.select('path.connector').classed('connectable', function () {
if (destination.empty()) {
return false;
}
// if there is a potential destination, see if its connectable
return destination.classed('connectable-destination');
}).attr('d', function (pathDatum) {
if (!destination.empty() && destination.classed('connectable-destination')) {
var destinationData = destination.datum();
// show the line preview as appropriate
if (pathDatum.sourceId === destinationData.id) {
var x = pathDatum.x;
var y = pathDatum.y;
var componentOffset = pathDatum.sourceWidth / 2;
var xOffset = nf.Connection.config.selfLoopXOffset;
var yOffset = nf.Connection.config.selfLoopYOffset;
return 'M' + x + ' ' + y + 'L' + (x + componentOffset + xOffset) + ' ' + (y - yOffset) + 'L' + (x + componentOffset + xOffset) + ' ' + (y + yOffset) + 'Z';
} else {
// get the position on the destination perimeter
var end = nf.CanvasUtils.getPerimeterPoint(pathDatum, {
'x': destinationData.position.x,
'y': destinationData.position.y,
'width': destinationData.dimensions.width,
'height': destinationData.dimensions.height
});
// direct line between components to provide a 'snap feel'
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + end.x + ' ' + end.y;
}
} else {
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + d3.event.x + ' ' + d3.event.y;
}
});
})
.on('dragend', function (d) {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
// get the add connect img
var addConnect = d3.select(this);
// get the connector, if it the current point is not over a new destination
// the connector will be removed. otherwise it will be removed after the
// connection has been configured/cancelled
var connector = d3.select('path.connector');
var connectorData = connector.datum();
// get the destination
var destination = d3.select('g.connectable-destination');
// we are not over a new destination
if (destination.empty()) {
// get the source to determine if we are still over it
var source = d3.select('#id-' + connectorData.sourceId);
var sourceData = source.datum();
// start the drag line and insert it first to keep it on the bottom
var position = d3.mouse(canvas.node());
canvas.insert('path', ':first-child')
.datum({
'sourceId': sourceData.id,
'sourceWidth': sourceData.dimensions.width,
'x': position[0],
'y': position[1]
})
.attr({
'class': 'connector',
'd': function (pathDatum) {
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + pathDatum.x + ' ' + pathDatum.y;
}
});
// get the mouse position relative to the source
var position = d3.mouse(source.node());
// updates the location of the connection img
d3.select(this).attr('transform', function () {
return 'translate(' + position[0] + ', ' + (position[1] + 20) + ')';
});
// re-append the image to keep it on top
canvas.node().appendChild(this);
})
.on('drag', function (d) {
// updates the location of the connection img
d3.select(this).attr('transform', function () {
return 'translate(' + d3.event.x + ', ' + (d3.event.y + 20) + ')';
});
// mark node's connectable if supported
var destination = d3.select('g.hover').classed('connectable-destination', function () {
// ensure the mouse has moved at least 10px in any direction, it seems that
// when the drag event is trigger is not consistent between browsers. as a result
// some browser would trigger when the mouse hadn't moved yet which caused
// click and contextmenu events to appear like an attempt to connection the
// component to itself. requiring the mouse to have actually moved before
// checking the eligiblity of the destination addresses the issue
return (Math.abs(origin[0] - d3.event.x) > 10 || Math.abs(origin[1] - d3.event.y) > 10) &&
nf.CanvasUtils.isValidConnectionDestination(d3.select(this));
});
// update the drag line
d3.select('path.connector').classed('connectable', function () {
if (destination.empty()) {
return false;
}
// if there is a potential destination, see if its connectable
return destination.classed('connectable-destination');
}).attr('d', function (pathDatum) {
if (!destination.empty() && destination.classed('connectable-destination')) {
var destinationData = destination.datum();
// show the line preview as appropriate
if (pathDatum.sourceId === destinationData.id) {
var x = pathDatum.x;
var y = pathDatum.y;
var componentOffset = pathDatum.sourceWidth / 2;
var xOffset = nf.Connection.config.selfLoopXOffset;
var yOffset = nf.Connection.config.selfLoopYOffset;
return 'M' + x + ' ' + y + 'L' + (x + componentOffset + xOffset) + ' ' + (y - yOffset) + 'L' + (x + componentOffset + xOffset) + ' ' + (y + yOffset) + 'Z';
} else {
// get the position on the destination perimeter
var end = nf.CanvasUtils.getPerimeterPoint(pathDatum, {
'x': destinationData.position.x,
'y': destinationData.position.y,
'width': destinationData.dimensions.width,
'height': destinationData.dimensions.height
});
// direct line between components to provide a 'snap feel'
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + end.x + ' ' + end.y;
}
} else {
return 'M' + pathDatum.x + ' ' + pathDatum.y + 'L' + d3.event.x + ' ' + d3.event.y;
}
});
})
.on('dragend', function (d) {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
// get the add connect img
var addConnect = d3.select(this);
// get the connector, if it the current point is not over a new destination
// the connector will be removed. otherwise it will be removed after the
// connection has been configured/cancelled
var connector = d3.select('path.connector');
var connectorData = connector.datum();
// get the destination
var destination = d3.select('g.connectable-destination');
// we are not over a new destination
if (destination.empty()) {
// get the source to determine if we are still over it
var source = d3.select('#id-' + connectorData.sourceId);
var sourceData = source.datum();
// get the mouse position relative to the source
var position = d3.mouse(source.node());
// if the position is outside the component, remove the add connect img
if (position[0] < 0 || position[0] > sourceData.dimensions.width || position[1] < 0 || position[1] > sourceData.dimensions.height) {
addConnect.remove();
} else {
// reset the add connect img by restoring the position and place in the DOM
addConnect.classed('dragging', false).attr('transform', function () {
return 'translate(' + d.origX + ', ' + d.origY + ')';
});
source.node().appendChild(this);
}
// remove the connector
connector.remove();
} else {
// remove the add connect img
// if the position is outside the component, remove the add connect img
if (position[0] < 0 || position[0] > sourceData.dimensions.width || position[1] < 0 || position[1] > sourceData.dimensions.height) {
addConnect.remove();
// create the connection
var destinationData = destination.datum();
nf.ConnectionConfiguration.createConnection(connectorData.sourceId, destinationData.id);
} else {
// reset the add connect img by restoring the position and place in the DOM
addConnect.classed('dragging', false).attr('transform', function () {
return 'translate(' + d.origX + ', ' + d.origY + ')';
});
source.node().appendChild(this);
}
});
// remove the connector
connector.remove();
} else {
// remove the add connect img
addConnect.remove();
// create the connection
var destinationData = destination.datum();
nf.ConnectionConfiguration.createConnection(connectorData.sourceId, destinationData.id);
}
});
},
activate: function (components) {
components
.on('mouseenter.connectable', function (d) {
if (allowConnection()) {
var selection = d3.select(this);
.classed('connectable', true)
.on('mouseenter.connectable', function (d) {
if (allowConnection()) {
var selection = d3.select(this);
// ensure the current component supports connection source
if (nf.CanvasUtils.isValidConnectionSource(selection)) {
// see if theres already a connector rendered
var addConnect = d3.select('image.add-connect');
if (addConnect.empty()) {
var x = (d.dimensions.width / 2) - 14;
var y = (d.dimensions.height / 2) - 14;
// ensure the current component supports connection source
if (nf.CanvasUtils.isValidConnectionSource(selection)) {
// see if theres already a connector rendered
var addConnect = d3.select('image.add-connect');
if (addConnect.empty()) {
var x = (d.dimensions.width / 2) - 14;
var y = (d.dimensions.height / 2) - 14;
selection.append('image')
.datum({
origX: x,
origY: y
})
.call(connect)
.call(nf.CanvasUtils.disableImageHref)
.attr({
'class': 'add-connect',
'xlink:href': 'images/addConnect.png',
'width': 28,
'height': 28,
'transform': 'translate(' + x + ', ' + y + ')'
});
}
selection.append('image')
.datum({
origX: x,
origY: y
})
.call(connect)
.call(nf.CanvasUtils.disableImageHref)
.attr({
'class': 'add-connect',
'xlink:href': 'images/addConnect.png',
'width': 28,
'height': 28,
'transform': 'translate(' + x + ', ' + y + ')'
});
}
}
})
.on('mouseleave.connectable', function () {
// conditionally remove the connector
var addConnect = d3.select(this).select('image.add-connect');
if (!addConnect.empty() && !addConnect.classed('dragging')) {
addConnect.remove();
}
})
// Using mouseover/out to workaround chrome issue #122746
.on('mouseover.connectable', function () {
// mark that we are hovering when appropriate
d3.select(this).classed('hover', function () {
return allowConnection();
});
})
.on('mouseout.connection', function () {
// remove all hover related classes
d3.select(this).classed('hover connectable-destination', false);
}
})
.on('mouseleave.connectable', function () {
// conditionally remove the connector
var addConnect = d3.select(this).select('image.add-connect');
if (!addConnect.empty() && !addConnect.classed('dragging')) {
addConnect.remove();
}
})
// Using mouseover/out to workaround chrome issue #122746
.on('mouseover.connectable', function () {
// mark that we are hovering when appropriate
d3.select(this).classed('hover', function () {
return allowConnection();
});
})
.on('mouseout.connection', function () {
// remove all hover related classes
d3.select(this).classed('hover connectable-destination', false);
});
},
deactivate: function (components) {
components
.classed('connectable', false)
.on('mouseenter.connectable', null)
.on('mouseleave.connectable', null)
.on('mouseover.connectable', null)
.on('mouseout.connectable', null);
}
};
}());

View File

@ -843,7 +843,6 @@ nf.ConnectionConfiguration = (function () {
if (validateSettings()) {
var connectionEntity = {
'revision': nf.Client.getRevision(),
'component': {
'name': connectionName,
'source': {
@ -873,9 +872,6 @@ nf.ConnectionConfiguration = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// add the connection
nf.Graph.add({
'connections': [response]
@ -926,8 +922,9 @@ nf.ConnectionConfiguration = (function () {
var prioritizers = $('#prioritizer-selected').sortable('toArray');
if (validateSettings()) {
var d = nf.Connection.get(connectionId);
var connectionEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(d),
'component': {
'id': connectionId,
'name': connectionName,
@ -953,9 +950,6 @@ nf.ConnectionConfiguration = (function () {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// update this connection
nf.Connection.set(response);

View File

@ -247,9 +247,6 @@ nf.Connection = (function () {
.attr({
'class': 'connection-path',
'pointer-events': 'none'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// path to show when selection
@ -260,7 +257,7 @@ nf.Connection = (function () {
});
// path to make selection easier
var selectableConnection = connection.append('path')
connection.append('path')
.attr({
'class': 'connection-path-selectable',
'pointer-events': 'stroke'
@ -270,49 +267,6 @@ nf.Connection = (function () {
nf.Selectable.select(d3.select(this.parentNode));
})
.call(nf.ContextMenu.activate);
// only support adding bend points when appropriate
selectableConnection.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).on('dblclick', function (d) {
var position = d3.mouse(this.parentNode);
// find where to put this bend point
var bendIndex = getNearestSegment({
'x': position[0],
'y': position[1]
}, d);
// copy the original to restore if necessary
var bends = d.component.bends.slice();
// add it to the collection of points
bends.splice(bendIndex, 0, {
'x': position[0],
'y': position[1]
});
var connection = {
id: d.id,
bends: bends
};
// update the label index if necessary
var labelIndex = d.component.labelIndex;
if (bends.length === 1) {
connection.labelIndex = 0;
} else if (bendIndex <= labelIndex) {
connection.labelIndex = labelIndex + 1;
}
// save the new state
save(d, connection);
d3.event.stopPropagation();
});
// update connection which will establish appropriate start/end points among other things
connection.call(updateConnections, true, false);
};
// determines whether the specified connection contains an unsupported relationship
@ -333,13 +287,25 @@ nf.Connection = (function () {
};
// updates the specified connections
var updateConnections = function (updated, updatePath, updateLabel) {
var updateConnections = function (updated, options) {
if (updated.empty()) {
return;
}
var updatePath = true;
var updateLabel = true;
var transition = false;
// extract the options if specified
if (nf.Common.isDefinedAndNotNull(options)) {
updatePath = nf.Common.isDefinedAndNotNull(options.updatePath) ? options.updatePath : updatePath;
updateLabel = nf.Common.isDefinedAndNotNull(options.updateLabel) ? options.updateLabel : updateLabel;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
if (updatePath === true) {
updated.classed('grouped', function (d) {
updated
.classed('grouped', function (d) {
var grouped = false;
if (d.accessPolicy.canRead) {
@ -363,6 +329,55 @@ nf.Connection = (function () {
return ghost;
});
// update connection path
updated.select('path.connection-path')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// update connection behavior
updated.select('path.connection-path-selectable')
.on('dblclick', function (d) {
if (d.accessPolicy.canWrite && d.accessPolicy.canRead) {
var position = d3.mouse(this.parentNode);
// find where to put this bend point
var bendIndex = getNearestSegment({
'x': position[0],
'y': position[1]
}, d);
// copy the original to restore if necessary
var bends = d.component.bends.slice();
// add it to the collection of points
bends.splice(bendIndex, 0, {
'x': position[0],
'y': position[1]
});
var connection = {
id: d.id,
bends: bends
};
// update the label index if necessary
var labelIndex = d.component.labelIndex;
if (bends.length === 1) {
connection.labelIndex = 0;
} else if (bendIndex <= labelIndex) {
connection.labelIndex = labelIndex + 1;
}
// save the new state
save(d, connection);
d3.event.stopPropagation();
} else {
return null;
}
});
}
updated.each(function (d) {
@ -442,7 +457,7 @@ nf.Connection = (function () {
d.end = end;
// update the connection paths
connection.select('path.connection-path')
nf.CanvasUtils.transition(connection.select('path.connection-path'), transition)
.attr({
'd': function () {
var datum = [d.start].concat(d.bends, [d.end]);
@ -463,14 +478,14 @@ nf.Connection = (function () {
return 'url(#' + marker + ')';
}
});
connection.select('path.connection-selection-path')
nf.CanvasUtils.transition(connection.select('path.connection-selection-path'), transition)
.attr({
'd': function () {
var datum = [d.start].concat(d.bends, [d.end]);
return lineGenerator(datum);
}
});
connection.select('path.connection-path-selectable')
nf.CanvasUtils.transition(connection.select('path.connection-path-selectable'), transition)
.attr({
'd': function () {
var datum = [d.start].concat(d.bends, [d.end]);
@ -482,13 +497,17 @@ nf.Connection = (function () {
// bends
// -----
var startpoints = connection.selectAll('rect.startpoint');
var endpoints = connection.selectAll('rect.endpoint');
var midpoints = connection.selectAll('rect.midpoint');
if (d.accessPolicy.canWrite) {
// ------------------
// bends - startpoint
// ------------------
var startpoints = connection.selectAll('rect.startpoint').data([d.start]);
startpoints = startpoints.data([d.start]);
// create a point for the start
startpoints.enter().append('rect')
@ -505,9 +524,10 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate);
// update the start point
startpoints.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
nf.CanvasUtils.transition(startpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
// remove old items
startpoints.exit().remove();
@ -516,7 +536,7 @@ nf.Connection = (function () {
// bends - endpoint
// ----------------
var endpoints = connection.selectAll('rect.endpoint').data([d.end]);
var endpoints = endpoints.data([d.end]);
// create a point for the end
endpoints.enter().append('rect')
@ -534,9 +554,10 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate);
// update the end point
endpoints.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
nf.CanvasUtils.transition(endpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
// remove old items
endpoints.exit().remove();
@ -545,7 +566,7 @@ nf.Connection = (function () {
// bends - midpoints
// -----------------
var midpoints = connection.selectAll('rect.midpoint').data(d.bends);
var midpoints = midpoints.data(d.bends);
// create a point for the end
midpoints.enter().append('rect')
@ -560,9 +581,12 @@ nf.Connection = (function () {
// stop even propagation
d3.event.stopPropagation();
var connection = d3.select(this.parentNode);
var connectionData = connection.datum();
// if this is a self loop prevent removing the last two bends
var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d);
var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d);
var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(connectionData);
var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(connectionData);
if (sourceComponentId === destinationComponentId && d.component.bends.length <= 2) {
nf.Dialog.showOkDialog({
dialogContent: 'Looping connections must have at least two bend points.',
@ -575,7 +599,7 @@ nf.Connection = (function () {
var bendIndex = -1;
// create a new array of bends without the selected one
$.each(d.component.bends, function (i, bend) {
$.each(connectionData.component.bends, function (i, bend) {
if (p.x !== bend.x && p.y !== bend.y) {
newBends.push(bend);
} else {
@ -588,12 +612,12 @@ nf.Connection = (function () {
}
var connection = {
id: d.id,
id: connectionData.id,
bends: newBends
};
// update the label index if necessary
var labelIndex = d.component.labelIndex;
var labelIndex = connectionData.component.labelIndex;
if (newBends.length <= 1) {
connection.labelIndex = 0;
} else if (bendIndex <= labelIndex) {
@ -601,7 +625,7 @@ nf.Connection = (function () {
}
// save the updated connection
save(d, connection);
save(connectionData, connection);
})
.on('mousedown.selection', function () {
// select the connection when clicking the label
@ -610,12 +634,18 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate);
// update the midpoints
midpoints.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
nf.CanvasUtils.transition(midpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
});
// remove old items
midpoints.exit().remove();
} else {
// remove the start, mid, and end points
startpoints.remove();
endpoints.remove();
midpoints.remove();
}
}
@ -648,9 +678,6 @@ nf.Connection = (function () {
'x': 0,
'y': 0,
'filter': 'url(#component-drop-shadow)'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// processor border
@ -660,9 +687,6 @@ nf.Connection = (function () {
'width': dimensions.width,
'fill': 'transparent',
'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
}
@ -1061,10 +1085,16 @@ nf.Connection = (function () {
connectionLabelContainer.select('rect.body')
.attr('height', function () {
return (rowHeight * labelCount);
})
.classed('unauthorized', function () {
return d.accessPolicy.canRead === false;
});
connectionLabelContainer.select('rect.border')
.attr('height', function () {
return (rowHeight * labelCount);
})
.classed('unauthorized', function () {
return d.accessPolicy.canRead === false;
});
// update the coloring of the backgrounds
@ -1111,7 +1141,7 @@ nf.Connection = (function () {
}
// update the position of the label if possible
connection.select('g.connection-label-container')
nf.CanvasUtils.transition(connection.select('g.connection-label-container'), transition)
.attr('transform', function () {
var label = d3.select(this).select('rect.body');
var position = getLabelPosition(label);
@ -1133,21 +1163,13 @@ nf.Connection = (function () {
// queued count value
updated.select('text.queued tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.queued, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.queued, ' ');
});
// queued size value
updated.select('text.queued tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.queued, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.queued, ' ');
});
};
@ -1159,10 +1181,8 @@ nf.Connection = (function () {
* @param {type} connection
*/
var save = function (d, connection) {
var revision = nf.Client.getRevision();
var entity = {
'revision': revision,
'revision': nf.Client.getRevision(d),
'component': connection
};
@ -1173,9 +1193,6 @@ nf.Connection = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// request was successful, update the entry
nf.Connection.set(response);
}).fail(function (xhr, status, error) {
@ -1238,7 +1255,10 @@ nf.Connection = (function () {
d.y = d3.event.y;
// redraw this connection
d3.select(this.parentNode).call(updateConnections, true, false);
d3.select(this.parentNode).call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
})
.on('dragend', function () {
var connection = d3.select(this.parentNode);
@ -1270,7 +1290,10 @@ nf.Connection = (function () {
});
// refresh the connection
connection.call(updateConnections, true, false);
connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
});
}
}
@ -1298,7 +1321,10 @@ nf.Connection = (function () {
});
// redraw this connection
d3.select(this.parentNode).call(updateConnections, true, false);
d3.select(this.parentNode).call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
})
.on('dragend', function (d) {
// indicate that dragging as stopped
@ -1314,7 +1340,10 @@ nf.Connection = (function () {
// resets the connection if we're not over a new destination
if (destination.empty()) {
connection.call(updateConnections, true, false);
connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
} else {
// prompt for the new port if appropriate
if (nf.CanvasUtils.isProcessGroup(destination) || nf.CanvasUtils.isRemoteProcessGroup(destination)) {
@ -1324,7 +1353,10 @@ nf.Connection = (function () {
nf.CanvasUtils.reloadConnectionSourceAndDestination(null, previousDestinationId);
}).fail(function () {
// reset the connection
connection.call(updateConnections, true, false);
connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
});
} else {
// get the destination details
@ -1332,7 +1364,7 @@ nf.Connection = (function () {
var destinationType = nf.CanvasUtils.getConnectableTypeForDestination(destination);
var connectionEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(connectionData),
'component': {
'id': connectionData.id,
'destination': {
@ -1372,9 +1404,6 @@ nf.Connection = (function () {
}).done(function (response) {
var updatedConnectionData = response.component;
// update the revision
nf.Client.setRevision(response.revision);
// refresh to update the label
nf.Connection.set(response);
@ -1389,7 +1418,10 @@ nf.Connection = (function () {
});
// reset the connection
connection.call(updateConnections, true, false);
connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
} else {
nf.Common.handleAjaxError(xhr, status, error);
}
@ -1442,9 +1474,9 @@ nf.Connection = (function () {
} else {
// update the position of the drag selection
drag.attr('x', function (d) {
d.x += d3.event.dx;
return d.x;
})
d.x += d3.event.dx;
return d.x;
})
.attr('y', function (d) {
d.y += d3.event.dy;
return d.y;
@ -1480,7 +1512,10 @@ nf.Connection = (function () {
d.labelIndex = closestBendIndex;
// refresh the connection
d3.select(this.parentNode).call(updateConnections, true, false);
d3.select(this.parentNode).call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
}
})
.on('dragend', function (d) {
@ -1508,7 +1543,10 @@ nf.Connection = (function () {
d.labelIndex = d.component.labelIndex;
// refresh the connection
connection.call(updateConnections, true, false);
connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
});
}
}
@ -1519,18 +1557,21 @@ nf.Connection = (function () {
},
/**
* Populates the graph with the specified connections.
* Adds the specified connection entity.
*
* @argument {object | array} connectionEntities The connections to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param connectionEntities The connection
* @param options Configuration options
*/
add: function (connectionEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (connectionEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (connectionEntity) {
// add the connection
connectionMap.set(connectionEntity.id, $.extend({
type: 'Connection',
type: 'Connection'
}, connectionEntity));
};
@ -1539,12 +1580,61 @@ nf.Connection = (function () {
$.each(connectionEntities, function (_, connectionEntity) {
add(connectionEntity);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(connectionEntities)) {
add(connectionEntities);
}
// apply the selection and handle new connections
var selection = select();
selection.enter().call(renderConnections, selectAll);
selection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
},
/**
* Populates the graph with the specified connections.
*
* @argument {object | array} connectionEntities The connections to add
* @argument {object} options Configuration options
*/
set: function (connectionEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (connectionEntity) {
// add the connection
connectionMap.set(connectionEntity.id, $.extend({
type: 'Connection'
}, connectionEntity));
};
// determine how to handle the specified connection
if ($.isArray(connectionEntities)) {
$.each(connectionMap.keys(), function (_, key) {
connectionMap.remove(key);
});
$.each(connectionEntities, function (_, connectionEntity) {
set(connectionEntity);
});
} else if (nf.Common.isDefinedAndNotNull(connectionEntities)) {
set(connectionEntities);
}
// apply the selection and handle all new connection
select().enter().call(renderConnections, selectAll);
var selection = select();
selection.enter().call(renderConnections, selectAll);
selection.call(updateConnections, {
'updatePath': true,
'updateLabel': true,
'transition': transition
});
selection.exit().call(removeConnections);
},
/**
@ -1554,33 +1644,6 @@ nf.Connection = (function () {
d3.selectAll('g.connection').call(sort);
},
/**
* Sets the value of the specified connection.
*
* @param {type} connectionEntities
*/
set: function (connectionEntities) {
var set = function (connectionEntity) {
if (connectionMap.has(connectionEntity.id)) {
// update the current entry
var connectionEntry = connectionMap.get(connectionEntity.id);
$.extend(connectionEntry, connectionEntity);
// update the connection in the UI
d3.select('#id-' + connectionEntity.id).call(updateConnections, true, true);
}
};
// determine how to handle the specified connection
if ($.isArray(connectionEntities)) {
$.each(connectionEntities, function (_, connectionEntity) {
set(connectionEntity);
});
} else {
set(connectionEntities);
}
},
/**
* Sets the connection status using the specified status.
*
@ -1610,9 +1673,15 @@ nf.Connection = (function () {
*/
refresh: function (connectionId) {
if (nf.Common.isDefinedAndNotNull(connectionId)) {
d3.select('#id-' + connectionId).call(updateConnections, true, true);
d3.select('#id-' + connectionId).call(updateConnections, {
'updatePath': true,
'updateLabel': true
});
} else {
d3.selectAll('g.connection').call(updateConnections, true, true);
d3.selectAll('g.connection').call(updateConnections, {
'updatePath': true,
'updateLabel': true
});
}
},
@ -1620,7 +1689,10 @@ nf.Connection = (function () {
* Refreshes the components necessary after a pan event.
*/
pan: function () {
d3.selectAll('g.connection.entering, g.connection.leaving').call(updateConnections, false, true);
d3.selectAll('g.connection.entering, g.connection.leaving').call(updateConnections, {
'updatePath': false,
'updateLabel': true
});
},
/**

View File

@ -464,7 +464,7 @@ nf.ContextMenu = (function () {
// defines the available actions and the conditions which they apply
var actions = [
{condition: emptySelection, menuItem: {img: 'images/iconRefresh.png', text: 'Refresh status', action: 'reloadStatus'}},
{condition: emptySelection, menuItem: {img: 'images/iconRefresh.png', text: 'Refresh', action: 'reload'}},
{condition: isNotRootGroup, menuItem: {img: 'images/iconGoTo.png', text: 'Leave group', action: 'leaveGroup'}},
{condition: isConfigurable, menuItem: {img: 'images/iconConfigure.png', text: 'Configure', action: 'showConfiguration'}},
{condition: hasDetails, menuItem: {img: 'images/iconConfigure.png', text: 'View configuration', action: 'showDetails'}},

View File

@ -175,7 +175,8 @@ nf.ControllerService = (function () {
*/
var reloadControllerServiceReferences = function (controllerService) {
// reload all dependent processors if they are currently visible
$.each(controllerService.referencingComponents, function (_, reference) {
$.each(controllerService.referencingComponents, function (_, referencingComponentEntity) {
var reference = referencingComponentEntity.controllerServiceReferencingComponent;
if (reference.referenceType === 'Processor') {
// reload the processor on the canvas if appropriate
if (nf.Canvas.getGroupId() === reference.groupId) {
@ -381,7 +382,8 @@ nf.ControllerService = (function () {
var processors = $('<ul class="referencing-component-listing clear"></ul>');
var services = $('<ul class="referencing-component-listing clear"></ul>');
var tasks = $('<ul class="referencing-component-listing clear"></ul>');
$.each(referencingComponents, function (_, referencingComponent) {
$.each(referencingComponents, function (_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
referencingComponentIds.push(referencingComponent.id);
if (referencingComponent.referenceType === 'Processor') {
@ -580,7 +582,8 @@ nf.ControllerService = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
nf.Client.setRevision(response.revision);
// TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError);
// wait until the polling of each service finished
@ -627,7 +630,8 @@ nf.ControllerService = (function () {
ids.add(controllerService.id);
var checkReferencingServices = function (referencingComponents) {
$.each(referencingComponents, function (_, referencingComponent) {
$.each(referencingComponents, function (_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') {
// add the id
ids.add(referencingComponent.id);
@ -668,7 +672,8 @@ nf.ControllerService = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
nf.Client.setRevision(response.revision);
// TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError);
// wait unil the polling of each service finished
@ -785,7 +790,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents;
var stillRunning = false;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') {
if (referencingComponent.state === 'RUNNING' || referencingComponent.activeThreadCount > 0) {
stillRunning = true;
@ -809,7 +815,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') {
referencingSchedulableComponents.push(referencingComponent.id);
}
@ -831,7 +838,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents;
var notEnabled = false;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') {
if (referencingComponent.state !== 'ENABLING' && referencingComponent.state !== 'ENABLED') {
notEnabled = true;
@ -852,7 +860,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') {
referencingSchedulableComponents.push(referencingComponent.id);
}
@ -874,7 +883,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents;
var notDisabled = false;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') {
if (referencingComponent.state !== 'DISABLED') {
notDisabled = true;
@ -895,7 +905,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) {
$.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') {
referencingSchedulableComponents.push(referencingComponent.id);
}
@ -928,7 +939,8 @@ nf.ControllerService = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
nf.Client.setRevision(response.revision);
// TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError);
// wait unil the polling of each service finished
@ -1311,8 +1323,8 @@ nf.ControllerService = (function () {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// reload all previously referenced controller services
$.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
@ -1436,6 +1448,7 @@ nf.ControllerService = (function () {
// initialize the property table
$('#controller-service-properties').propertytable({
readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
@ -1583,6 +1596,7 @@ nf.ControllerService = (function () {
// initialize the property table
$('#controller-service-properties').propertytable('destroy').propertytable({
readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
@ -1888,7 +1902,8 @@ nf.ControllerService = (function () {
}),
dataType: 'json'
}).done(function (response) {
nf.Client.setRevision(response.revision);
// TODO
// nf.Client.setRevision(response.revision);
// remove the service
var controllerServiceGrid = $('#controller-services-table').data('gridInstance');

View File

@ -49,7 +49,7 @@ nf.Draggable = (function () {
// build the entity
var entity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(d),
'component': {
'id': d.id,
'position': newPosition
@ -65,9 +65,6 @@ nf.Draggable = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// update the component
nf[d.type].set(response);
@ -106,7 +103,7 @@ nf.Draggable = (function () {
});
var entity = {
'revision': revision,
'revision': nf.Client.getRevision(d),
'component': {
id: d.id,
bends: newBends
@ -122,9 +119,6 @@ nf.Draggable = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// update the component
nf.Connection.set(response);
@ -189,9 +183,6 @@ nf.Draggable = (function () {
$.each(componentConnections, function (_, connection) {
connections.add(connection.id);
});
// refresh the component
nf[component.type].position(component.id);
}
});
@ -315,6 +306,15 @@ nf.Draggable = (function () {
*/
activate: function (components) {
components.classed('moveable', true).call(drag);
},
/**
* Deactivates the drag behavior for the components in the specified selection.
*
* @param {selection} components
*/
deactivate: function (components) {
components.classed('moveable', false).on('.drag', null);
}
};
}());

View File

@ -84,8 +84,6 @@ nf.Funnel = (function () {
},
'fill': 'transparent',
'stroke': 'transparent'
}).classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// funnel body
@ -102,9 +100,6 @@ nf.Funnel = (function () {
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// funnel icon
@ -118,13 +113,6 @@ nf.Funnel = (function () {
// always support selection
funnel.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
// only support dragging and connecting when appropriate
funnel.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate).call(nf.Connectable.activate);
return funnel;
};
/**
@ -133,6 +121,28 @@ nf.Funnel = (function () {
* @param {selection} updated The funnels to be updated
*/
var updateFunnels = function (updated) {
if (updated.empty()) {
return;
}
// funnel border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// funnel body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
updated.each(function () {
var funnel = d3.select(this);
// update the component behavior as appropriate
nf.CanvasUtils.editable(funnel);
});
};
/**
@ -160,13 +170,16 @@ nf.Funnel = (function () {
},
/**
* Populates the graph with the specified funnels.
* Adds the specified funnel entity.
*
* @argument {object | array} funnelEntities The funnels to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param funnelEntities The funnel
* @param options Configuration options
*/
add: function (funnelEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (funnelEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (funnelEntity) {
// add the funnel
@ -181,12 +194,55 @@ nf.Funnel = (function () {
$.each(funnelEntities, function (_, funnelEntity) {
add(funnelEntity);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(funnelEntities)) {
add(funnelEntities);
}
// apply the selection and handle new funnels
var selection = select();
selection.enter().call(renderFunnels, selectAll);
selection.call(updateFunnels);
},
/**
* Populates the graph with the specified funnels.
*
* @argument {object | array} funnelEntities The funnels to add
* @argument {object} options Configuration options
*/
set: function (funnelEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (funnelEntity) {
// add the funnel
funnelMap.set(funnelEntity.id, $.extend({
type: 'Funnel',
dimensions: dimensions
}, funnelEntity));
};
// determine how to handle the specified funnel status
if ($.isArray(funnelEntities)) {
$.each(funnelMap.keys(), function (_, key) {
funnelMap.remove(key);
});
$.each(funnelEntities, function (_, funnelEntity) {
set(funnelEntity);
});
} else if (nf.Common.isDefinedAndNotNull(funnelEntities)) {
set(funnelEntities);
}
// apply the selection and handle all new processors
select().enter().call(renderFunnels, selectAll);
var selection = select();
selection.enter().call(renderFunnels, selectAll);
selection.call(updateFunnels).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeFunnels);
},
/**
@ -244,35 +300,6 @@ nf.Funnel = (function () {
d3.select('#id-' + id).call(nf.CanvasUtils.position);
},
/**
* Sets the specified funnel(s). If the is an array, it
* will set each funnel. If it is not an array, it will
* attempt to set the specified funnel.
*
* @param {object | array} funnelEntities
*/
set: function (funnelEntities) {
var set = function (funnelEntity) {
if (funnelMap.has(funnelEntity.id)) {
// update the current entry
var funnelEntry = funnelMap.get(funnelEntity.id);
$.extend(funnelEntry, funnelEntity);
// update the connection in the UI
d3.select('#id-' + funnelEntity.id).call(updateFunnels);
}
};
// determine how to handle the specified funnel status
if ($.isArray(funnelEntities)) {
$.each(funnelEntities, function (_, funnelEntity) {
set(funnelEntity);
});
} else {
set(funnelEntities);
}
},
/**
* Removes the specified funnel.
*

View File

@ -58,15 +58,18 @@ nf.Graph = (function () {
// load the graph
return nf.CanvasUtils.enterGroup(nf.Canvas.getGroupId());
},
/**
* Populates the graph with the resources defined in the response.
*
*
* @argument {object} processGroupContents The contents of the process group
* @argument {boolean} selectAll Whether or not to select the new contents
*/
add: function (processGroupContents, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (processGroupContents, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
// if we are going to select the new components, deselect the previous selection
if (selectAll) {
@ -77,28 +80,49 @@ nf.Graph = (function () {
var ports = combinePorts(processGroupContents);
// add the components to the responsible object
if (!nf.Common.isEmpty(processGroupContents.labels)) {
nf.Label.add(processGroupContents.labels, selectAll);
nf.Label.add(processGroupContents.labels, options);
nf.Funnel.add(processGroupContents.funnels, options);
nf.RemoteProcessGroup.add(processGroupContents.remoteProcessGroups, options);
nf.Port.add(ports, options);
nf.ProcessGroup.add(processGroupContents.processGroups, options);
nf.Processor.add(processGroupContents.processors, options);
nf.Connection.add(processGroupContents.connections, options);
// inform Angular app if the selection is changing
if (selectAll) {
nf.ng.Bridge.digest();
}
if (!nf.Common.isEmpty(processGroupContents.funnels)) {
nf.Funnel.add(processGroupContents.funnels, selectAll);
},
/**
* Populates the graph with the resources defined in the response.
*
* @argument {object} processGroupContents The contents of the process group
* @argument {object} options Configuration options
*/
set: function (processGroupContents, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
if (!nf.Common.isEmpty(processGroupContents.remoteProcessGroups)) {
nf.RemoteProcessGroup.add(processGroupContents.remoteProcessGroups, selectAll);
}
if (!nf.Common.isEmpty(ports)) {
nf.Port.add(ports, selectAll);
}
if (!nf.Common.isEmpty(processGroupContents.processGroups)) {
nf.ProcessGroup.add(processGroupContents.processGroups, selectAll);
}
if (!nf.Common.isEmpty(processGroupContents.processors)) {
nf.Processor.add(processGroupContents.processors, selectAll);
}
if (!nf.Common.isEmpty(processGroupContents.connections)) {
nf.Connection.add(processGroupContents.connections, selectAll);
// if we are going to select the new components, deselect the previous selection
if (selectAll) {
nf.CanvasUtils.getSelection().classed('selected', false);
}
// merge the ports together
var ports = combinePorts(processGroupContents);
// add the components to the responsible object
nf.Label.set(processGroupContents.labels, options);
nf.Funnel.set(processGroupContents.funnels, options);
nf.RemoteProcessGroup.set(processGroupContents.remoteProcessGroups, options);
nf.Port.set(ports, options);
nf.ProcessGroup.set(processGroupContents.processGroups, options);
nf.Processor.set(processGroupContents.processors, options);
nf.Connection.set(processGroupContents.connections, options);
// inform Angular app if the selection is changing
if (selectAll) {
nf.ng.Bridge.digest();
@ -120,39 +144,6 @@ nf.Graph = (function () {
};
},
/**
* Sets the components contained within the specified process group.
*
* @param {type} processGroupContents
*/
set: function (processGroupContents) {
// merge the ports together
var ports = combinePorts(processGroupContents);
// set the components
if (!nf.Common.isEmpty(processGroupContents.labels)) {
nf.Label.set(processGroupContents.labels);
}
if (!nf.Common.isEmpty(processGroupContents.funnels)) {
nf.Funnel.set(processGroupContents.funnels);
}
if (!nf.Common.isEmpty(ports)) {
nf.Port.set(ports);
}
if (!nf.Common.isEmpty(processGroupContents.remoteProcessGroups)) {
nf.RemoteProcessGroup.set(processGroupContents.remoteProcessGroups);
}
if (!nf.Common.isEmpty(processGroupContents.processGroups)) {
nf.ProcessGroup.set(processGroupContents.processGroups);
}
if (!nf.Common.isEmpty(processGroupContents.processors)) {
nf.Processor.set(processGroupContents.processors);
}
if (!nf.Common.isEmpty(processGroupContents.connections)) {
nf.Connection.set(processGroupContents.connections);
}
},
/**
* Populates the status for the components specified. This will update the content
* of the existing components on the graph and will not cause them to be repainted.

View File

@ -42,7 +42,7 @@ nf.LabelConfiguration = (function () {
// build the label entity
var labelEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(labelData),
'component': {
'id': labelId,
'label': labelValue,
@ -60,9 +60,6 @@ nf.LabelConfiguration = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// get the label out of the response
nf.Label.set(response);
}).fail(nf.Common.handleAjaxError);

View File

@ -60,7 +60,7 @@ nf.Label = (function () {
/**
* Renders the labels in the specified selection.
*
*
* @param {selection} entered The selection of labels to be rendered
* @param {boolean} selected Whether the label should be selected
*/
@ -70,57 +70,47 @@ nf.Label = (function () {
}
var label = entered.append('g')
.attr({
'id': function (d) {
return 'id-' + d.id;
},
'class': 'label component'
})
.classed('selected', selected)
.call(nf.CanvasUtils.position);
.attr({
'id': function (d) {
return 'id-' + d.id;
},
'class': 'label component'
})
.classed('selected', selected)
.call(nf.CanvasUtils.position);
// label border
label.append('rect')
.attr({
'class': 'border',
'fill': 'transparent',
'stroke-opacity': 0.8,
'stroke-width': 1
});
.attr({
'class': 'border',
'fill': 'transparent',
'stroke': 'transparent'
});
// label
label.append('rect')
.attr({
'class': 'body',
'fill-opacity': 0.8,
'stroke-opacity': 0.8,
'stroke-width': 0
});
.attr({
'class': 'body',
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
});
// label value
label.append('text')
.attr({
'xml:space': 'preserve',
'font-weight': 'bold',
'fill': 'black',
'class': 'label-value'
});
.attr({
'xml:space': 'preserve',
'font-weight': 'bold',
'fill': 'black',
'class': 'label-value'
});
// always support selecting
label.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
// only support dragging when appropriate
label.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate);
// call update to trigger some rendering
label.call(updateLabels);
};
/**
* Updates the labels in the specified selection.
*
*
* @param {selection} updated The labels to be updated
*/
var updateLabels = function (updated) {
@ -130,60 +120,59 @@ nf.Label = (function () {
// update the border using the configured color
updated.select('rect.border')
.attr({
'stroke': function (d) {
var color = nf.Label.defaultColor();
if (d.accessPolicy.canRead) {
// use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
}
return color;
},
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
}
});
.attr({
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
}
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// update the body fill using the configured color
updated.select('rect.body')
.attr({
'fill': function (d) {
var color = nf.Label.defaultColor();
.attr({
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
}
})
.style('fill', function (d) {
if (!d.accessPolicy.canRead) {
return null;
}
if (d.accessPolicy.canRead) {
// use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
}
var color = nf.Label.defaultColor();
return color;
},
'width': function (d) {
return d.dimensions.width;
},
'height': function (d) {
return d.dimensions.height;
}
});
// use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
return color;
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// go through each label being updated
updated.each(function (d) {
var updatedLabel = d3.select(this);
var label = d3.select(this);
// update the component behavior as appropriate
nf.CanvasUtils.editable(label);
// update the label
var labelText = label.select('text.label-value');
var labelPoint = label.selectAll('rect.labelpoint');
if (d.accessPolicy.canRead) {
// update the label
var label = updatedLabel.select('text.label-value');
// udpate the font size
label.attr('font-size', function () {
labelText.attr('font-size', function () {
var fontSize = '12px';
// use the specified color if appropriate
@ -195,7 +184,7 @@ nf.Label = (function () {
});
// remove the previous label value
label.selectAll('tspan').remove();
labelText.selectAll('tspan').remove();
// parse the lines in this label
var lines = [];
@ -207,12 +196,12 @@ nf.Label = (function () {
// add label value
$.each(lines, function (i, line) {
label.append('tspan')
.attr('x', '0.4em')
.attr('dy', '1.2em')
.text(function () {
return line;
});
labelText.append('tspan')
.attr('x', '0.4em')
.attr('dy', '1.2em')
.text(function () {
return line;
});
});
@ -224,16 +213,16 @@ nf.Label = (function () {
var pointData = [
{x: d.dimensions.width, y: d.dimensions.height}
];
var points = updatedLabel.selectAll('rect.labelpoint').data(pointData);
var points = labelPoint.data(pointData);
// create a point for the end
points.enter().append('rect')
.attr({
'class': 'labelpoint',
'width': 10,
'height': 10
})
.call(labelPointDrag);
.attr({
'class': 'labelpoint',
'width': 10,
'height': 10
})
.call(labelPointDrag);
// update the midpoints
points.attr('transform', function (p) {
@ -243,13 +232,19 @@ nf.Label = (function () {
// remove old items
points.exit().remove();
}
} else {
// remove the previous label value
labelText.selectAll('tspan').remove();
// remove the label points
labelPoint.remove()
}
});
};
/**
* Removes the labels in the specified selection.
*
*
* @param {selection} removed The labels to be removed
*/
var removeLabels = function (removed) {
@ -261,7 +256,7 @@ nf.Label = (function () {
width: dimensions.width,
height: dimensions.height
},
/**
* Initializes of the Processor handler.
*/
@ -270,103 +265,103 @@ nf.Label = (function () {
// create the label container
labelContainer = d3.select('#canvas').append('g')
.attr({
'pointer-events': 'all',
'class': 'labels'
});
.attr({
'pointer-events': 'all',
'class': 'labels'
});
// handle bend point drag events
labelPointDrag = d3.behavior.drag()
.on('dragstart', function () {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var label = d3.select(this.parentNode);
var labelData = label.datum();
.on('dragstart', function () {
// stop further propagation
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var label = d3.select(this.parentNode);
var labelData = label.datum();
// update the dimensions and ensure they are still within bounds
labelData.dimensions.width = Math.max(MIN_WIDTH, d3.event.x);
labelData.dimensions.height = Math.max(MIN_HEIGHT, d3.event.y);
// update the dimensions and ensure they are still within bounds
labelData.dimensions.width = Math.max(MIN_WIDTH, d3.event.x);
labelData.dimensions.height = Math.max(MIN_HEIGHT, d3.event.y);
// redraw this connection
updateLabels(label);
})
.on('dragend', function () {
var label = d3.select(this.parentNode);
var labelData = label.datum();
// redraw this connection
updateLabels(label);
})
.on('dragend', function () {
var label = d3.select(this.parentNode);
var labelData = label.datum();
// determine if the width has changed
var different = false;
if (nf.Common.isDefinedAndNotNull(labelData.component.width) || labelData.dimensions.width !== labelData.component.width) {
different = true;
// determine if the width has changed
var different = false;
if (nf.Common.isDefinedAndNotNull(labelData.component.width) || labelData.dimensions.width !== labelData.component.width) {
different = true;
}
// determine if the height has changed
if (!different && nf.Common.isDefinedAndNotNull(labelData.component.height) || labelData.dimensions.height !== labelData.component.height) {
different = true;
}
// only save the updated bends if necessary
if (different) {
var labelEntity = {
'revision': nf.Client.getRevision(labelData),
'component': {
'id': labelData.id,
'width': labelData.dimensions.width,
'height': labelData.dimensions.height
}
}
// determine if the height has changed
if (!different && nf.Common.isDefinedAndNotNull(labelData.component.height) || labelData.dimensions.height !== labelData.component.height) {
different = true;
}
// only save the updated bends if necessary
if (different) {
var labelEntity = {
'revision': nf.Client.getRevision(),
'component': {
'id': labelData.id,
'width': labelData.dimensions.width,
'height': labelData.dimensions.height
}
$.ajax({
type: 'PUT',
url: labelData.component.uri,
data: JSON.stringify(labelEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// request was successful, update the entry
nf.Label.set(response);
}).fail(function () {
// determine the previous width
var width = dimensions.width;
if (nf.Common.isDefinedAndNotNull(labelData.component.width)) {
width = labelData.component.width;
}
$.ajax({
type: 'PUT',
url: labelData.component.uri,
data: JSON.stringify(labelEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// determine the previous height
var height = dimensions.height;
if (nf.Common.isDefinedAndNotNull(labelData.component.height)) {
height = labelData.component.height;
}
// request was successful, update the entry
nf.Label.set(response);
}).fail(function () {
// determine the previous width
var width = dimensions.width;
if (nf.Common.isDefinedAndNotNull(labelData.component.width)) {
width = labelData.component.width;
}
// restore the previous dimensions
labelData.dimensions = {
width: width,
height: height
};
// determine the previous height
var height = dimensions.height;
if (nf.Common.isDefinedAndNotNull(labelData.component.height)) {
height = labelData.component.height;
}
// refresh the label
label.call(updateLabels);
});
}
// restore the previous dimensions
labelData.dimensions = {
width: width,
height: height
};
// refresh the label
label.call(updateLabels);
});
}
// stop further propagation
d3.event.sourceEvent.stopPropagation();
});
// stop further propagation
d3.event.sourceEvent.stopPropagation();
});
},
/**
* Populates the graph with the specified labels.
*
* @argument {object | array} labelEntities The labels to add
* @argument {boolean} selectAll Whether or not to select the new contents
* Adds the specified label entity.
*
* @param labelEntities The label
* @param options Configuration options
*/
add: function (labelEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (labelEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (labelEntity) {
// add the label
@ -380,18 +375,60 @@ nf.Label = (function () {
$.each(labelEntities, function (_, labelEntity) {
add(labelEntity);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(labelEntities)) {
add(labelEntities);
}
// apply the selection and handle all new labels
select().enter().call(renderLabels, selectAll);
// apply the selection and handle new labels
var selection = select();
selection.enter().call(renderLabels, selectAll);
selection.call(updateLabels);
},
/**
* Populates the graph with the specified labels.
*
* @argument {object | array} labelEntities The labels to add
* @argument {object} options Configuration options
*/
set: function (labelEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (labelEntity) {
// add the label
labelMap.set(labelEntity.id, $.extend({
type: 'Label'
}, labelEntity));
};
// determine how to handle the specified label status
if ($.isArray(labelEntities)) {
$.each(labelMap.keys(), function (_, key) {
labelMap.remove(key);
});
$.each(labelEntities, function (_, labelEntity) {
set(labelEntity);
});
} else if (nf.Common.isDefinedAndNotNull(labelEntities)) {
set(labelEntities);
}
// apply the selection and handle all new labels
var selection = select();
selection.enter().call(renderLabels, selectAll);
selection.call(updateLabels).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeLabels);
},
/**
* If the label id is specified it is returned. If no label id
* specified, all labels are returned.
*
*
* @param {string} id
*/
get: function (id) {
@ -401,11 +438,11 @@ nf.Label = (function () {
return labelMap.get(id);
}
},
/**
* If the label id is specified it is refresh according to the current
* If the label id is specified it is refresh according to the current
* state. If not label id is specified, all labels are refreshed.
*
*
* @param {string} id Optional
*/
refresh: function (id) {
@ -415,11 +452,11 @@ nf.Label = (function () {
d3.selectAll('g.label').call(updateLabels);
}
},
/**
* Reloads the label state from the server and refreshes the UI.
* If the label is currently unknown, this function just returns.
*
*
* @param {object} label The label to reload
*/
reload: function (label) {
@ -433,48 +470,19 @@ nf.Label = (function () {
});
}
},
/**
* Positions the component.
*
*
* @param {string} id The id
*/
position: function (id) {
d3.select('#id-' + id).call(nf.CanvasUtils.position);
},
/**
* Sets the specified label(s). If the is an array, it
* will set each label. If it is not an array, it will
* attempt to set the specified label.
*
* @param {object | array} labelEntities
*/
set: function (labelEntities) {
var set = function (labelEntity) {
if (labelMap.has(labelEntity.id)) {
// update the current entry
var labelEntry = labelMap.get(labelEntity.id);
$.extend(labelEntry, labelEntity);
// update the connection in the UI
d3.select('#id-' + labelEntry.id).call(updateLabels);
}
};
// determine how to handle the specified label status
if ($.isArray(labelEntities)) {
$.each(labelEntities, function (_, label) {
set(label);
});
} else {
set(labelEntities);
}
},
/**
* Removes the specified label.
*
*
* @param {array|string} labels The label id(s)
*/
remove: function (labels) {
@ -489,14 +497,14 @@ nf.Label = (function () {
// apply the selection and handle all removed labels
select().exit().call(removeLabels);
},
/**
* Removes all label.
*/
removeAll: function () {
nf.Label.remove(labelMap.keys());
},
/**
* Returns the default color that should be used when drawing a label.
*/

View File

@ -55,7 +55,7 @@ nf.PortConfiguration = (function () {
// build the port entity
var portEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(portData),
'component': port
};
@ -67,9 +67,6 @@ nf.PortConfiguration = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// refresh the port component
nf.Port.set(response);

View File

@ -95,9 +95,6 @@ nf.Port = (function () {
},
'fill': 'transparent',
'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// port body
@ -112,9 +109,6 @@ nf.Port = (function () {
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
var offset = 0;
@ -167,9 +161,6 @@ nf.Port = (function () {
port.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate).call(nf.Connectable.activate);
// call update to trigger some rendering
port.call(updatePorts);
};
/**
@ -182,10 +173,25 @@ nf.Port = (function () {
return;
}
// port border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// port body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
updated.each(function (portData) {
var port = d3.select(this);
var details = port.select('g.port-details');
// update the component behavior as appropriate
nf.CanvasUtils.editable(port);
// if this process group is visible, render everything
if (port.classed('visible')) {
if (details.empty()) {
@ -277,6 +283,9 @@ nf.Port = (function () {
}).append('title').text(function (d) {
return d.component.name;
});
} else {
// clear the port name
port.select('text.port-name').text(null);
}
// populate the stats
@ -321,14 +330,14 @@ nf.Port = (function () {
.attr({
'fill': function (d) {
var fill = '#728e9b';
if (d.status.runStatus === 'Invalid') {
if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
fill = '#ba554a';
}
return fill;
},
'font-family': function (d) {
var family = 'FontAwesome';
if (d.status.runStatus === 'Disabled') {
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
family = 'flowfont';
}
return family;
@ -336,13 +345,13 @@ nf.Port = (function () {
})
.text(function (d) {
var img = '';
if (d.status.runStatus === 'Disabled') {
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
img = '\ue802';
} else if (d.status.runStatus === 'Invalid') {
} else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
img = '\uf071';
} else if (d.status.runStatus === 'Running') {
} else if (d.status.aggregateSnapshot.runStatus === 'Running') {
img = '\uf04b';
} else if (d.status.runStatus === 'Stopped') {
} else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
img = '\uf04d';
}
return img;
@ -378,7 +387,7 @@ nf.Port = (function () {
updated.select('text.port-transmission-icon')
.attr({
'font-family': function (d) {
if (d.status.transmitting === true) {
if (d.status.aggregateSnapshot.transmitting === true) {
return 'FontAwesome';
} else {
return 'flowfont';
@ -386,7 +395,7 @@ nf.Port = (function () {
}
})
.text(function (d) {
if (d.status.transmitting === true) {
if (d.status.aggregateSnapshot.transmitting === true) {
return '\uf140';
} else {
return '\ue80a';
@ -410,7 +419,7 @@ nf.Port = (function () {
// ---------
port.select('rect.bulletin-background').classed('has-bulletins', function () {
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins);
return !nf.Common.isEmpty(d.status.aggregateSnapshot.bulletins);
});
nf.CanvasUtils.bulletins(port, d, function () {
@ -461,13 +470,16 @@ nf.Port = (function () {
},
/**
* Populates the graph with the specified ports.
* Adds the specified port entity.
*
* @argument {object | array} portNodes The ports to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param portEntities The port
* @param options Configuration options
*/
add: function (portEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (portEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
// determine the appropriate dimensions for this port
var dimensions = portDimensions;
@ -491,12 +503,64 @@ nf.Port = (function () {
$.each(portEntities, function (_, portNode) {
add(portNode);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(portEntities)) {
add(portEntities);
}
// apply the selection and handle new ports
var selection = select();
selection.enter().call(renderPorts, selectAll);
selection.call(updatePorts);
},
/**
* Populates the graph with the specified ports.
*
* @argument {object | array} portNodes The ports to add
* @argument {object} options Configuration options
*/
set: function (portEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
// determine the appropriate dimensions for this port
var dimensions = portDimensions;
if (nf.Canvas.getParentGroupId() === null) {
dimensions = remotePortDimensions;
}
var set = function (portEntity) {
// add the port
portMap.set(portEntity.id, $.extend({
type: 'Port',
dimensions: dimensions,
status: {
activeThreadCount: 0
}
}, portEntity));
};
// determine how to handle the specified port status
if ($.isArray(portEntities)) {
$.each(portMap.keys(), function (_, key) {
portMap.remove(key);
});
$.each(portEntities, function (_, portNode) {
set(portNode);
});
} else if (nf.Common.isDefinedAndNotNull(portEntities)) {
set(portEntities);
}
// apply the selection and handle all new ports
select().enter().call(renderPorts, selectAll);
var selection = select();
selection.enter().call(renderPorts, selectAll);
selection.call(updatePorts).call(nf.CanvasUtils.position, transition);
selection.exit().call(removePorts);
},
/**
@ -565,35 +629,6 @@ nf.Port = (function () {
d3.select('#id-' + id).call(nf.CanvasUtils.position);
},
/**
* Sets the specified port(s). If the is an array, it
* will set each port. If it is not an array, it will
* attempt to set the specified port.
*
* @param {object | array} portEntities
*/
set: function (portEntities) {
var set = function (portEntity) {
if (portMap.has(portEntity.id)) {
// update the current entry
var portEntry = portMap.get(portEntity.id);
$.extend(portEntry, portEntity);
// update the connection in the UI
d3.select('#id-' + portEntry.id).call(updatePorts);
}
};
// determine how to handle the specified ports
if ($.isArray(portEntities)) {
$.each(portEntities, function (_, port) {
set(port);
});
} else {
set(portEntities);
}
},
/**
* Sets the port status using the specified status.
*

View File

@ -28,15 +28,13 @@ nf.ProcessGroupConfiguration = (function () {
buttonText: 'Apply',
handler: {
click: function () {
var revision = nf.Client.getRevision();
// get the process group data to reference the uri
var processGroupId = $('#process-group-id').text();
var processGroupData = d3.select('#id-' + processGroupId).datum();
// build the entity
var entity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(processGroupData),
'component': {
'id': processGroupId,
'name': $('#process-group-name').val(),
@ -52,16 +50,11 @@ nf.ProcessGroupConfiguration = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// refresh the process group
nf.ProcessGroup.set(response);
// refresh the process group
nf.ProcessGroup.set(response);
// close the details panel
$('#process-group-configuration').modal('hide');
}
// close the details panel
$('#process-group-configuration').modal('hide');
}).fail(function (xhr, status, error) {
// close the details panel
$('#process-group-configuration').modal('hide');

View File

@ -101,9 +101,6 @@ nf.ProcessGroup = (function () {
},
'fill': 'transparent',
'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// process group body
@ -118,9 +115,6 @@ nf.ProcessGroup = (function () {
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// process group name background
@ -198,9 +192,6 @@ nf.ProcessGroup = (function () {
})
.call(nf.Draggable.activate)
.call(nf.Connectable.activate);
// call update to trigger some rendering
processGroup.call(updateProcessGroups);
};
// attempt of space between component count and icon for process group contents
@ -216,10 +207,25 @@ nf.ProcessGroup = (function () {
return;
}
// process group border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// process group body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
updated.each(function (processGroupData) {
var processGroup = d3.select(this);
var details = processGroup.select('g.process-group-details');
// update the component behavior as appropriate
nf.CanvasUtils.editable(processGroup);
// if this processor is visible, render everything
if (processGroup.classed('visible')) {
if (details.empty()) {
@ -244,106 +250,103 @@ nf.ProcessGroup = (function () {
// contents
// --------
if (processGroupData.accessPolicy.canRead) {
// transmitting icon
details.append('text')
.attr({
'x': 10,
'y': 49,
'class': 'process-group-transmitting process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf140');
// transmitting icon
details.append('text')
.attr({
'x': 10,
'y': 49,
'class': 'process-group-transmitting process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf140');
// transmitting count
details.append('text')
.attr({
'x': 28,
'y': 49,
'class': 'process-group-transmitting-count process-group-contents-count'
});
// transmitting count
details.append('text')
.attr({
'x': 28,
'y': 49,
'class': 'process-group-transmitting-count process-group-contents-count'
});
// not transmitting icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-not-transmitting process-group-contents-icon',
'font-family': 'flowfont'
})
.text('\ue80a');
// not transmitting icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-not-transmitting process-group-contents-icon',
'font-family': 'flowfont'
})
.text('\ue80a');
// not transmitting count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-not-transmitting-count process-group-contents-count'
});
// not transmitting count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-not-transmitting-count process-group-contents-count'
});
// running icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-running process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf04b');
// running icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-running process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf04b');
// running count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-running-count process-group-contents-count'
});
// running count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-running-count process-group-contents-count'
});
// stopped icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-stopped process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf04d');
// stopped icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-stopped process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf04d');
// stopped count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-stopped-count process-group-contents-count'
});
// stopped count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-stopped-count process-group-contents-count'
});
// invalid icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-invalid process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf071');
// invalid icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-invalid process-group-contents-icon',
'font-family': 'FontAwesome'
})
.text('\uf071');
// invalid count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-invalid-count process-group-contents-count'
});
// invalid count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-invalid-count process-group-contents-count'
});
// disabled icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-disabled process-group-contents-icon',
'font-family': 'flowfont'
})
.text('\ue802');
// disabled icon
details.append('text')
.attr({
'y': 49,
'class': 'process-group-disabled process-group-contents-icon',
'font-family': 'flowfont'
})
.text('\ue802');
// disabled count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-disabled-count process-group-contents-count'
});
}
// disabled count
details.append('text')
.attr({
'y': 49,
'class': 'process-group-disabled-count process-group-contents-count'
});
// ----------------
// stats background
@ -537,6 +540,12 @@ nf.ProcessGroup = (function () {
'class': 'size'
});
// in
inText.append('tspan')
.attr({
'class': 'ports'
});
// read/write value
processGroupStatsValue.append('text')
.attr({
@ -556,14 +565,20 @@ nf.ProcessGroup = (function () {
'y': 60,
'class': 'process-group-out stats-value'
});
// out ports
outText.append('tspan')
.attr({
'class': 'ports'
});
// in count
// out count
outText.append('tspan')
.attr({
'class': 'count'
});
// in size
// out size
outText.append('tspan')
.attr({
'class': 'size'
@ -669,92 +684,91 @@ nf.ProcessGroup = (function () {
.text('\uf24a');
}
// update transmitting
var transmittingCount = details.select('text.process-group-transmitting-count')
.text(function (d) {
return d.activeRemotePortCount;
});
// update not transmitting
var notTransmitting = details.select('text.process-group-not-transmitting')
.attr('x', function () {
var transmittingX = parseInt(transmittingCount.attr('x'), 10);
return transmittingX + transmittingCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var notTransmittingCount = details.select('text.process-group-not-transmitting-count')
.attr('x', function () {
var notTransmittingCountX = parseInt(notTransmitting.attr('x'), 10);
return notTransmittingCountX + notTransmitting.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.inactiveRemotePortCount;
});
// update running
var running = details.select('text.process-group-running')
.attr('x', function () {
var notTransmittingX = parseInt(notTransmittingCount.attr('x'), 10);
return notTransmittingX + notTransmittingCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var runningCount = details.select('text.process-group-running-count')
.attr('x', function () {
var runningCountX = parseInt(running.attr('x'), 10);
return runningCountX + running.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.runningCount;
});
// update stopped
var stopped = details.select('text.process-group-stopped')
.attr('x', function () {
var runningX = parseInt(runningCount.attr('x'), 10);
return runningX + runningCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var stoppedCount = details.select('text.process-group-stopped-count')
.attr('x', function () {
var stoppedCountX = parseInt(stopped.attr('x'), 10);
return stoppedCountX + stopped.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.stoppedCount;
});
// update invalid
var invalid = details.select('text.process-group-invalid')
.attr('x', function () {
var stoppedX = parseInt(stoppedCount.attr('x'), 10);
return stoppedX + stoppedCount.node().getComputedTextLength() + CONTENTS_SPACER;
})
.classed('has-validation-errors', function (d) {
return d.accessPolicy.canRead && d.component.invalidCount > 0;
});
var invalidCount = details.select('text.process-group-invalid-count')
.attr('x', function () {
var invalidCountX = parseInt(invalid.attr('x'), 10);
return invalidCountX + invalid.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.invalidCount;
});
// update disabled
var disabled = details.select('text.process-group-disabled')
.attr('x', function () {
var invalidX = parseInt(invalidCount.attr('x'), 10);
return invalidX + invalidCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
details.select('text.process-group-disabled-count')
.attr('x', function () {
var disabledCountX = parseInt(disabled.attr('x'), 10);
return disabledCountX + disabled.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.disabledCount;
});
if (processGroupData.accessPolicy.canRead) {
// update transmitting
var transmittingCount = details.select('text.process-group-transmitting-count')
.text(function (d) {
return d.component.activeRemotePortCount;
});
// update not transmitting
var notTransmitting = details.select('text.process-group-not-transmitting')
.attr('x', function () {
var transmittingX = parseInt(transmittingCount.attr('x'), 10);
return transmittingX + transmittingCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var notTransmittingCount = details.select('text.process-group-not-transmitting-count')
.attr('x', function () {
var notTransmittingCountX = parseInt(notTransmitting.attr('x'), 10);
return notTransmittingCountX + notTransmitting.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.component.inactiveRemotePortCount;
});
// update running
var running = details.select('text.process-group-running')
.attr('x', function () {
var notTransmittingX = parseInt(notTransmittingCount.attr('x'), 10);
return notTransmittingX + notTransmittingCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var runningCount = details.select('text.process-group-running-count')
.attr('x', function () {
var runningCountX = parseInt(running.attr('x'), 10);
return runningCountX + running.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.component.runningCount;
});
// update stopped
var stopped = details.select('text.process-group-stopped')
.attr('x', function () {
var runningX = parseInt(runningCount.attr('x'), 10);
return runningX + runningCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
var stoppedCount = details.select('text.process-group-stopped-count')
.attr('x', function () {
var stoppedCountX = parseInt(stopped.attr('x'), 10);
return stoppedCountX + stopped.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.component.stoppedCount;
});
// update invalid
var invalid = details.select('text.process-group-invalid')
.attr('x', function () {
var stoppedX = parseInt(stoppedCount.attr('x'), 10);
return stoppedX + stoppedCount.node().getComputedTextLength() + CONTENTS_SPACER;
})
.classed('has-validation-errors', function (d) {
return d.accessPolicy.canRead && d.component.invalidCount > 0;
});
var invalidCount = details.select('text.process-group-invalid-count')
.attr('x', function () {
var invalidCountX = parseInt(invalid.attr('x'), 10);
return invalidCountX + invalid.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.component.invalidCount;
});
// update disabled
var disabled = details.select('text.process-group-disabled')
.attr('x', function () {
var invalidX = parseInt(invalidCount.attr('x'), 10);
return invalidX + invalidCount.node().getComputedTextLength() + CONTENTS_SPACER;
});
details.select('text.process-group-disabled-count')
.attr('x', function () {
var disabledCountX = parseInt(disabled.attr('x'), 10);
return disabledCountX + disabled.node().getComputedTextLength() + CONTENTS_SPACER;
})
.text(function (d) {
return d.component.disabledCount;
});
// update the process group comments
details.select('text.process-group-comments')
.each(function (d) {
@ -784,6 +798,12 @@ nf.ProcessGroup = (function () {
}).append('title').text(function (d) {
return d.component.name;
});
} else {
// clear the process group comments
details.select('text.process-group-comments').text(null);
// clear the process group name
processGroup.select('text.process-group-name').text(null);
}
// hide the preview
@ -832,71 +852,55 @@ nf.ProcessGroup = (function () {
// queued count value
updated.select('text.process-group-queued tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.queued, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.queued, ' ');
});
// queued size value
updated.select('text.process-group-queued tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.queued, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.queued, ' ');
});
// in count value
updated.select('text.process-group-in tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.input, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
});
// in size value
updated.select('text.process-group-in tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.input, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
});
// in ports value
updated.select('text.process-group-in tspan.ports')
.text(function (d) {
return ' ' + String.fromCharCode(8594) + ' ' + d.inputPortCount;
});
// read/write value
updated.select('text.process-group-read-write')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return d.status.read + ' / ' + d.status.written;
} else {
return '- / -';
}
return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
});
// out ports value
updated.select('text.process-group-out tspan.ports')
.text(function (d) {
return d.outputPortCount + ' ' + String.fromCharCode(8594) + ' ';
});
// out count value
updated.select('text.process-group-out tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.output, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
});
// out size value
updated.select('text.process-group-out tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.output, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
});
updated.each(function (d) {
@ -916,7 +920,7 @@ nf.ProcessGroup = (function () {
// ---------
processGroup.select('rect.bulletin-background').classed('has-bulletins', function () {
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins);
return !nf.Common.isEmpty(d.status.aggregateSnapshot.bulletins);
});
nf.CanvasUtils.bulletins(processGroup, d, function () {
@ -966,13 +970,16 @@ nf.ProcessGroup = (function () {
},
/**
* Populates the graph with the specified process groups.
* Adds the specified process group entity.
*
* @argument {object | array} processGroupEntities The process groups to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param processGroupEntities The process group
* @param options Configuration options
*/
add: function (processGroupEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (processGroupEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (processGroupEntity) {
// add the process group
@ -987,12 +994,55 @@ nf.ProcessGroup = (function () {
$.each(processGroupEntities, function (_, processGroupEntity) {
add(processGroupEntity);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(processGroupEntities)) {
add(processGroupEntities);
}
// apply the selection and handle new process groups
var selection = select();
selection.enter().call(renderProcessGroups, selectAll);
selection.call(updateProcessGroups);
},
/**
* Populates the graph with the specified process groups.
*
* @argument {object | array} processGroupEntities The process groups to add
* @argument {object} options Configuration options
*/
set: function (processGroupEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (processGroupEntity) {
// add the process group
processGroupMap.set(processGroupEntity.id, $.extend({
type: 'ProcessGroup',
dimensions: dimensions
}, processGroupEntity));
};
// determine how to handle the specified process groups
if ($.isArray(processGroupEntities)) {
$.each(processGroupMap.keys(), function (_, key) {
processGroupMap.remove(key);
});
$.each(processGroupEntities, function (_, processGroupEntity) {
set(processGroupEntity);
});
} else if (nf.Common.isDefinedAndNotNull(processGroupEntities)) {
set(processGroupEntities);
}
// apply the selection and handle all new process group
select().enter().call(renderProcessGroups, selectAll);
var selection = select();
selection.enter().call(renderProcessGroups, selectAll);
selection.call(updateProcessGroups).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeProcessGroups);
},
/**
@ -1057,35 +1107,6 @@ nf.ProcessGroup = (function () {
d3.select('#id-' + id).call(nf.CanvasUtils.position);
},
/**
* Sets the specified process group(s). If the is an array, it
* will set each process group. If it is not an array, it will
* attempt to set the specified process group.
*
* @param {object | array} processGroupEntities
*/
set: function (processGroupEntities) {
var set = function (processGroupEntity) {
if (processGroupMap.has(processGroupEntity.id)) {
// update the current entry
var processGroupEntry = processGroupMap.get(processGroupEntity.id);
$.extend(processGroupEntry, processGroupEntity);
// update the process group in the UI
d3.select('#id-' + processGroupEntry.id).call(updateProcessGroups);
}
};
// determine how to handle the specified process group
if ($.isArray(processGroupEntities)) {
$.each(processGroupEntities, function (_, processGroupEntity) {
set(processGroupEntity);
});
} else {
set(processGroupEntities);
}
},
/**
* Sets the process group status using the specified status.
*

View File

@ -302,7 +302,6 @@ nf.ProcessorConfiguration = (function () {
// create the processor entity
var processorEntity = {};
processorEntity['revision'] = nf.Client.getRevision();
processorEntity['component'] = processorDto;
// return the marshaled details
@ -428,6 +427,10 @@ nf.ProcessorConfiguration = (function () {
// ensure details are valid as far as we can tell
if (validateDetails(updatedProcessor)) {
// set the revision
var d = nf.Processor.get(processor.id);
updatedProcessor['revision'] = nf.Client.getRevision(d);
// update the selected component
return $.ajax({
type: 'PUT',
@ -436,11 +439,6 @@ nf.ProcessorConfiguration = (function () {
dataType: 'json',
processData: false,
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
}
}).fail(handleProcessorConfigurationError);
} else {
return $.Deferred(function (deferred) {
@ -543,6 +541,7 @@ nf.ProcessorConfiguration = (function () {
// initialize the property table
$('#processor-properties').propertytable({
readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-processor-property-container',
descriptorDeferred: function(propertyName) {
var processor = $('#processor-configuration').data('processorDetails');

View File

@ -80,9 +80,6 @@ nf.Processor = (function () {
},
'fill': 'transparent',
'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// processor body
@ -97,9 +94,6 @@ nf.Processor = (function () {
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// processor name
@ -134,14 +128,6 @@ nf.Processor = (function () {
// make processors selectable
processor.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
// only activate dragging and connecting if appropriate
processor.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate).call(nf.Connectable.activate);
// call update to trigger some rendering
processor.call(updateProcessors);
};
/**
@ -154,10 +140,25 @@ nf.Processor = (function () {
return;
}
// processor border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// processor body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
updated.each(function (processorData) {
var processor = d3.select(this);
var details = processor.select('g.processor-canvas-details');
// update the component behavior as appropriate
nf.CanvasUtils.editable(processor);
// if this processor is visible, render everything
if (processor.classed('visible')) {
if (details.empty()) {
@ -171,28 +172,15 @@ nf.Processor = (function () {
'y': 20
});
if (processorData.accessPolicy.canRead) {
// processor type
details.append('text')
.attr({
'class': 'processor-type',
'x': 62,
'y': 35,
'width': 246,
'height': 16
})
.each(function (d) {
var processorType = d3.select(this);
// reset the processor type to handle any previous state
processorType.text(null).selectAll('title').remove();
// apply ellipsis to the processor type as necessary
nf.CanvasUtils.ellipsis(processorType, nf.Common.substringAfterLast(d.component.type, '.'));
}).append('title').text(function (d) {
return nf.Common.substringAfterLast(d.component.type, '.');
// processor type
details.append('text')
.attr({
'class': 'processor-type',
'x': 62,
'y': 35,
'width': 246,
'height': 16
});
}
// -----
// stats
@ -473,7 +461,7 @@ nf.Processor = (function () {
'width': 24,
'height': 24
});
// bulletin icon
details.append('text')
.attr({
@ -500,6 +488,26 @@ nf.Processor = (function () {
}).append('title').text(function (d) {
return d.component.name;
});
// update the processor type
processor.select('text.processor-type')
.each(function (d) {
var processorType = d3.select(this);
// reset the processor type to handle any previous state
processorType.text(null).selectAll('title').remove();
// apply ellipsis to the processor type as necessary
nf.CanvasUtils.ellipsis(processorType, nf.Common.substringAfterLast(d.component.type, '.'));
}).append('title').text(function (d) {
return nf.Common.substringAfterLast(d.component.type, '.');
});
} else {
// clear the processor name
processor.select('text.processor-name').text(null);
// clear the processor type
processor.select('text.processor-type').text(null);
}
// hide the preview
@ -533,7 +541,7 @@ nf.Processor = (function () {
}
}
});
// ---------------
// processor color
// ---------------
@ -541,13 +549,16 @@ nf.Processor = (function () {
// update the processor color
updated.select('rect.body')
.style('fill', function (d) {
if (!d.accessPolicy.canRead) {
return null;
}
// get the default color
var color = nf.Processor.defaultColor();
if (d.accessPolicy.canRead) {
// use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
// use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color'];
}
return color;
@ -569,14 +580,14 @@ nf.Processor = (function () {
.attr({
'fill': function (d) {
var fill = '#728e9b';
if (d.status && d.status.runStatus === 'Invalid') {
if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
fill = '#ba554a';
}
return fill;
},
'font-family': function (d) {
var family = 'FontAwesome';
if (d.status && d.status.runStatus === 'Disabled') {
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
family = 'flowfont';
}
return family;
@ -584,13 +595,13 @@ nf.Processor = (function () {
})
.text(function (d) {
var img = '';
if (d.status && d.status.runStatus === 'Disabled') {
if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
img = '\ue802';
} else if (d.status && d.status.runStatus === 'Invalid') {
} else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
img = '\uf071';
} else if (d.status && d.status.runStatus === 'Running') {
} else if (d.status.aggregateSnapshot.runStatus === 'Running') {
img = '\uf04b';
} else if (d.status && d.status.runStatus === 'Stopped') {
} else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
img = '\uf04d';
}
return img;
@ -626,61 +637,37 @@ nf.Processor = (function () {
// in count value
updated.select('text.processor-in tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.input, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
});
// in size value
updated.select('text.processor-in tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.input, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
});
// read/write value
updated.select('text.processor-read-write')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return d.status.read + ' / ' + d.status.written;
} else {
return '- / -';
}
return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
});
// out count value
updated.select('text.processor-out tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return nf.Common.substringBeforeFirst(d.status.output, ' ');
} else {
return '-';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
});
// out size value
updated.select('text.processor-out tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return ' ' + nf.Common.substringAfterFirst(d.status.output, ' ');
} else {
return ' (-)';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
});
// tasks/time value
updated.select('text.processor-tasks-time')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return d.status.tasks + ' / ' + d.status.tasksDuration;
} else {
return '- / -';
}
return d.status.aggregateSnapshot.tasks + ' / ' + d.status.aggregateSnapshot.tasksDuration;
});
updated.each(function (d) {
@ -697,7 +684,7 @@ nf.Processor = (function () {
// ---------
processor.select('rect.bulletin-background').classed('has-bulletins', function () {
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins);
return !nf.Common.isEmpty(d.status.aggregateSnapshot.bulletins);
});
nf.CanvasUtils.bulletins(processor, d, function () {
@ -748,13 +735,16 @@ nf.Processor = (function () {
},
/**
* Populates the graph with the specified processors.
* Adds the specified processor entity.
*
* @argument {object | array} processorEntities The processors to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param processorEntities The processor
* @param options Configuration options
*/
add: function (processorNodeEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (processorEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (processorEntity) {
// add the processor
@ -765,16 +755,59 @@ nf.Processor = (function () {
};
// determine how to handle the specified processor
if ($.isArray(processorNodeEntities)) {
$.each(processorNodeEntities, function (_, processorEntity) {
if ($.isArray(processorEntities)) {
$.each(processorEntities, function (_, processorEntity) {
add(processorEntity);
});
} else {
add(processorNodeEntities);
} else if (nf.Common.isDefinedAndNotNull(processorEntities)) {
add(processorEntities);
}
// apply the selection and handle new processor
var selection = select();
selection.enter().call(renderProcessors, selectAll);
selection.call(updateProcessors);
},
/**
* Populates the graph with the specified processors.
*
* @argument {object | array} processorEntities The processors to add
* @argument {object} options Configuration options
*/
set: function (processorEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (processorEntity) {
// add the processor
processorMap.set(processorEntity.id, $.extend({
type: 'Processor',
dimensions: dimensions
}, processorEntity));
};
// determine how to handle the specified processor
if ($.isArray(processorEntities)) {
$.each(processorMap.keys(), function (_, key) {
processorMap.remove(key);
});
$.each(processorEntities, function (_, processorEntity) {
set(processorEntity);
});
} else if (nf.Common.isDefinedAndNotNull(processorEntities)) {
set(processorEntities);
}
// apply the selection and handle all new processors
select().enter().call(renderProcessors, selectAll);
var selection = select();
selection.enter().call(renderProcessors, selectAll);
selection.call(updateProcessors).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeProcessors);
},
/**
@ -839,35 +872,6 @@ nf.Processor = (function () {
}
},
/**
* Sets the specified processor(s). If the is an array, it
* will set each processor. If it is not an array, it will
* attempt to set the specified processor.
*
* @param {object | array} processorEntities
*/
set: function (processorEntities) {
var set = function (processorEntity) {
if (processorMap.has(processorEntity.id)) {
// update the current entry
var processorEntry = processorMap.get(processorEntity.id);
$.extend(processorEntry, processorEntity);
// update the processor in the UI
d3.select('#id-' + processorEntry.id).call(updateProcessors);
}
};
// determine how to handle the specified processor
if ($.isArray(processorEntities)) {
$.each(processorEntities, function (_, processorEntity) {
set(processorEntity);
});
} else {
set(processorEntities);
}
},
/**
* Removes the specified processor.
*

View File

@ -32,7 +32,7 @@ nf.RemoteProcessGroupConfiguration = (function () {
// create the remote process group details
var remoteProcessGroupEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(remoteProcessGroupData),
'component': {
id: remoteProcessGroupId,
communicationsTimeout: $('#remote-process-group-timeout').val(),
@ -48,9 +48,6 @@ nf.RemoteProcessGroupConfiguration = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// refresh the remote process group component
nf.RemoteProcessGroup.set(response);

View File

@ -40,7 +40,7 @@ nf.RemoteProcessGroupPorts = (function () {
// create the remote process group details
var remoteProcessGroupPortEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(remoteProcessGroupData),
'remoteProcessGroupPort': {
id: remotePortId,
useCompression: $('#remote-port-use-compression').hasClass('checkbox-checked'),
@ -62,8 +62,8 @@ nf.RemoteProcessGroupPorts = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// get the response
var remotePort = response.remoteProcessGroupPort;
@ -256,7 +256,7 @@ nf.RemoteProcessGroupPorts = (function () {
// create the remote process group details
var remoteProcessGroupPortEntity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision(remoteProcessGroupData),
'remoteProcessGroupPort': {
id: port.id,
transmitting: isTransmitting
@ -277,8 +277,8 @@ nf.RemoteProcessGroupPorts = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// get the response
var remotePort = response.remoteProcessGroupPort;

View File

@ -101,9 +101,6 @@ nf.RemoteProcessGroup = (function () {
},
'fill': 'transparent',
'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// remote process group body
@ -118,9 +115,6 @@ nf.RemoteProcessGroup = (function () {
},
'filter': 'url(#component-drop-shadow)',
'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// remote process group name background
@ -156,14 +150,6 @@ nf.RemoteProcessGroup = (function () {
// always support selection
remoteProcessGroup.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
// only support dragging and connecting when appropriate
remoteProcessGroup.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate).call(nf.Connectable.activate);
// call update to trigger some rendering
remoteProcessGroup.call(updateRemoteProcessGroups);
};
// attempt of space between component count and icon for process group contents
@ -179,10 +165,25 @@ nf.RemoteProcessGroup = (function () {
return;
}
// remote process group border authorization
updated.select('rect.border')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
// remote process group body authorization
updated.select('rect.body')
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
});
updated.each(function (remoteProcessGroupData) {
var remoteProcessGroup = d3.select(this);
var details = remoteProcessGroup.select('g.remote-process-group-details');
// update the component behavior as appropriate
nf.CanvasUtils.editable(remoteProcessGroup);
// if this processor is visible, render everything
if (remoteProcessGroup.classed('visible')) {
if (details.empty()) {
@ -223,28 +224,15 @@ nf.RemoteProcessGroup = (function () {
'y': 48
});
if (remoteProcessGroupData.accessPolicy.canRead) {
// remote process group uri
details.append('text')
.attr({
'x': 30,
'y': 48,
'width': 305,
'height': 12,
'class': 'remote-process-group-uri'
})
.each(function (d) {
var remoteProcessGroupUri = d3.select(this);
// reset the remote process group name to handle any previous state
remoteProcessGroupUri.text(null).selectAll('title').remove();
// apply ellipsis to the remote process group name as necessary
nf.CanvasUtils.ellipsis(remoteProcessGroupUri, d.component.targetUri);
}).append('title').text(function (d) {
return d.component.name;
// remote process group uri
details.append('text')
.attr({
'x': 30,
'y': 48,
'width': 305,
'height': 12,
'class': 'remote-process-group-uri'
});
}
// ----------------
// stats background
@ -336,8 +324,8 @@ nf.RemoteProcessGroup = (function () {
'transform': 'translate(95, 75)'
});
// queued value
remoteProcessGroupStatsValue.append('text')
// sent value
var sentText = remoteProcessGroupStatsValue.append('text')
.attr({
'width': 180,
'height': 10,
@ -346,8 +334,26 @@ nf.RemoteProcessGroup = (function () {
'class': 'remote-process-group-sent stats-value'
});
// sent count
sentText.append('tspan')
.attr({
'class': 'count'
});
// sent size
sentText.append('tspan')
.attr({
'class': 'size'
});
// sent ports
sentText.append('tspan')
.attr({
'class': 'ports'
});
// received value
remoteProcessGroupStatsValue.append('text')
var receivedText = remoteProcessGroupStatsValue.append('text')
.attr({
'width': 180,
'height': 10,
@ -356,6 +362,24 @@ nf.RemoteProcessGroup = (function () {
'class': 'remote-process-group-received stats-value'
});
// received ports
receivedText.append('tspan')
.attr({
'class': 'ports'
});
// received count
receivedText.append('tspan')
.attr({
'class': 'count'
});
// received size
receivedText.append('tspan')
.attr({
'class': 'size'
});
// stats value container
var processGroupStatsInfo = details.append('g')
.attr({
@ -470,6 +494,20 @@ nf.RemoteProcessGroup = (function () {
}
if (remoteProcessGroupData.accessPolicy.canRead) {
// remote process group uri
details.select('text.remote-process-group-uri')
.each(function (d) {
var remoteProcessGroupUri = d3.select(this);
// reset the remote process group name to handle any previous state
remoteProcessGroupUri.text(null).selectAll('title').remove();
// apply ellipsis to the remote process group name as necessary
nf.CanvasUtils.ellipsis(remoteProcessGroupUri, d.component.targetUri);
}).append('title').text(function (d) {
return d.component.name;
});
// update the process groups transmission status
details.select('text.remote-process-group-transmission-secure')
.text(function (d) {
@ -505,98 +543,6 @@ nf.RemoteProcessGroup = (function () {
nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
});
// ----------------------
// update the input ports
// ----------------------
// input port count
details.select('text.remote-process-group-input-port-count')
.text(function (d) {
return d.component.inputPortCount;
});
// get the input port container to help right align
var inputContainer = details.select('rect.remote-process-group-input-container');
// update input not transmitting
var inputNotTransmittingCount = details.select('text.remote-process-group-input-not-transmitting-count')
.text(function (d) {
return d.component.inactiveRemoteInputPortCount;
})
.attr('x', function () {
var containerX = parseInt(inputContainer.attr('x'), 10);
var containerWidth = parseInt(inputContainer.attr('width'), 10);
return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
});
var inputNotTransmitting = details.select('image.remote-process-group-input-not-transmitting')
.attr('x', function () {
var inputNotTransmittingCountX = parseInt(inputNotTransmittingCount.attr('x'), 10);
var width = parseInt(d3.select(this).attr('width'), 10);
return inputNotTransmittingCountX - width - CONTENTS_SPACER;
});
// update input transmitting
var inputTransmittingCount = details.select('text.remote-process-group-input-transmitting-count')
.text(function (d) {
return d.component.activeRemoteInputPortCount;
})
.attr('x', function () {
var inputNotTransmittingX = parseInt(inputNotTransmitting.attr('x'), 10);
return inputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
});
details.select('image.remote-process-group-input-transmitting')
.attr('x', function () {
var inputTransmittingCountX = parseInt(inputTransmittingCount.attr('x'), 10);
var width = parseInt(d3.select(this).attr('width'), 10);
return inputTransmittingCountX - width - CONTENTS_SPACER;
});
// -----------------------
// update the output ports
// -----------------------
// output port count
details.select('text.remote-process-group-output-port-count')
.text(function (d) {
return d.component.outputPortCount;
});
// get the output port container to help right align
var outputContainer = details.select('rect.remote-process-group-output-container');
// update input not transmitting
var outputNotTransmittingCount = details.select('text.remote-process-group-output-not-transmitting-count')
.text(function (d) {
return d.component.inactiveRemoteOutputPortCount;
})
.attr('x', function () {
var containerX = parseInt(outputContainer.attr('x'), 10);
var containerWidth = parseInt(outputContainer.attr('width'), 10);
return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
});
var outputNotTransmitting = details.select('image.remote-process-group-output-not-transmitting')
.attr('x', function () {
var outputNotTransmittingCountX = parseInt(outputNotTransmittingCount.attr('x'), 10);
var width = parseInt(d3.select(this).attr('width'), 10);
return outputNotTransmittingCountX - width - CONTENTS_SPACER;
});
// update output transmitting
var outputTransmittingCount = details.select('text.remote-process-group-output-transmitting-count')
.text(function (d) {
return d.component.activeRemoteOutputPortCount;
})
.attr('x', function () {
var outputNotTransmittingX = parseInt(outputNotTransmitting.attr('x'), 10);
return outputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
});
details.select('image.remote-process-group-output-transmitting')
.attr('x', function () {
var outputTransmittingCountX = parseInt(outputTransmittingCount.attr('x'), 10);
var width = parseInt(d3.select(this).attr('width'), 10);
return outputTransmittingCountX - width - CONTENTS_SPACER;
});
// ---------------
// update comments
// ---------------
@ -643,6 +589,21 @@ nf.RemoteProcessGroup = (function () {
}).append('title').text(function (d) {
return d.component.name;
});
} else {
// clear the target uri
details.select('text.remote-process-group-uri').text(null);
// clear the transmission secure icon
details.select('text.remote-process-group-transmission-secure').text(null);
// clear the process group comments
details.select('text.remote-process-group-comments').text(null);
// clear the last refresh
details.select('text.remote-process-group-last-refresh').text(null);
// clear the name
remoteProcessGroup.select('text.remote-process-group-name').text(null);
}
// show the preview
@ -688,24 +649,40 @@ nf.RemoteProcessGroup = (function () {
return;
}
// sent value
updated.select('text.remote-process-group-sent')
// sent count value
updated.select('text.remote-process-group-sent tspan.count')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return d.status.sent;
} else {
return '- / -';
}
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.sent, ' ');
});
// received value
updated.select('text.remote-process-group-received')
// sent size value
updated.select('text.remote-process-group-sent tspan.size')
.text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) {
return d.status.received;
} else {
return '- / -';
}
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.sent, ' ');
});
// sent ports value
updated.select('text.remote-process-group-sent tspan.ports')
.text(function (d) {
return ' ' + String.fromCharCode(8594) + ' ' + d.inputPortCount;
});
// received ports value
updated.select('text.remote-process-group-received tspan.ports')
.text(function (d) {
return d.inputPortCount + ' ' + String.fromCharCode(8594) + ' ';
});
// received count value
updated.select('text.remote-process-group-received tspan.count')
.text(function (d) {
return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.sent, ' ');
});
// received size value
updated.select('text.remote-process-group-received tspan.size')
.text(function (d) {
return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.sent, ' ');
});
// --------------------
@ -717,7 +694,7 @@ nf.RemoteProcessGroup = (function () {
updated.select('text.remote-process-group-transmission-status')
.text(function (d) {
var icon = '';
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues)) {
if (!nf.Common.isEmpty(d.status.aggregateSnapshot.authorizationIssues)) {
icon = '\uf071';
} else if (d.accessPolicy.canRead) {
if (d.component.transmitting === true) {
@ -730,7 +707,7 @@ nf.RemoteProcessGroup = (function () {
})
.attr('font-family', function (d) {
var family = '';
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues) || (d.accessPolicy.canRead && d.component.transmitting)) {
if (!nf.Common.isEmpty(d.status.aggregateSnapshot.authorizationIssues) || (d.accessPolicy.canRead && d.component.transmitting)) {
family = 'FontAwesome';
} else {
family = 'flowfont';
@ -738,7 +715,7 @@ nf.RemoteProcessGroup = (function () {
return family;
})
.classed('has-authorization-errors', function (d) {
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues);
return !nf.Common.isEmpty(d.status.aggregateSnapshot.authorizationIssues);
})
.each(function (d) {
// remove the existing tip if necessary
@ -748,14 +725,14 @@ nf.RemoteProcessGroup = (function () {
}
// if there are validation errors generate a tooltip
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues)) {
if (!nf.Common.isEmpty(d.status.aggregateSnapshot.authorizationIssues)) {
tip = d3.select('#remote-process-group-tooltips').append('div')
.attr('id', function () {
return 'authorization-issues-' + d.id;
})
.attr('class', 'tooltip nifi-tooltip')
.html(function () {
var list = nf.Common.formatUnorderedList(d.status.authorizationIssues);
var list = nf.Common.formatUnorderedList(d.status.aggregateSnapshot.authorizationIssues);
if (list === null || list.length === 0) {
return '';
} else {
@ -785,7 +762,7 @@ nf.RemoteProcessGroup = (function () {
// ---------
remoteProcessGroup.select('rect.bulletin-background').classed('has-bulletins', function () {
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins);
return !nf.Common.isEmpty(d.status.aggregateSnapshot.bulletins);
});
nf.CanvasUtils.bulletins(remoteProcessGroup, d, function () {
@ -837,13 +814,16 @@ nf.RemoteProcessGroup = (function () {
},
/**
* Populates the graph with the specified remote process groups.
* Adds the specified remote process group entity.
*
* @argument {object | array} remoteProcessGroupEntities The remote process groups to add
* @argument {boolean} selectAll Whether or not to select the new contents
* @param remoteProcessGroupEntities The remote process group
* @param options Configuration options
*/
add: function (remoteProcessGroupEntities, selectAll) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
add: function (remoteProcessGroupEntities, options) {
var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (remoteProcessGroupEntity) {
// add the remote process group
@ -858,12 +838,55 @@ nf.RemoteProcessGroup = (function () {
$.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
add(remoteProcessGroupEntity);
});
} else {
} else if (nf.Common.isDefinedAndNotNull(remoteProcessGroupEntities)) {
add(remoteProcessGroupEntities);
}
// apply the selection and handle new remote process groups
var selection = select();
selection.enter().call(renderRemoteProcessGroups, selectAll);
selection.call(updateRemoteProcessGroups);
},
/**
* Populates the graph with the specified remote process groups.
*
* @argument {object | array} remoteProcessGroupEntities The remote process groups to add
* @argument {object} options Configuration options
*/
set: function (remoteProcessGroupEntities, options) {
var selectAll = false;
var transition = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition;
}
var set = function (remoteProcessGroupEntity) {
// add the remote process group
remoteProcessGroupMap.set(remoteProcessGroupEntity.id, $.extend({
type: 'RemoteProcessGroup',
dimensions: dimensions
}, remoteProcessGroupEntity));
};
// determine how to handle the specified remote process groups
if ($.isArray(remoteProcessGroupEntities)) {
$.each(remoteProcessGroupMap.keys(), function (_, key) {
remoteProcessGroupMap.remove(key);
});
$.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
set(remoteProcessGroupEntity);
});
} else if (nf.Common.isDefinedAndNotNull(remoteProcessGroupEntities)) {
set(remoteProcessGroupEntities);
}
// apply the selection and handle all new remote process groups
select().enter().call(renderRemoteProcessGroups, selectAll);
var selection = select();
selection.enter().call(renderRemoteProcessGroups, selectAll);
selection.call(updateRemoteProcessGroups).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeRemoteProcessGroups);
},
/**
@ -934,35 +957,6 @@ nf.RemoteProcessGroup = (function () {
d3.select('#id-' + id).call(nf.CanvasUtils.position);
},
/**
* Sets the specified remote process group(s). If the is an array, it
* will set each remote process group. If it is not an array, it will
* attempt to set the specified remote process group.
*
* @param {object | array} remoteProcessGroupEntities
*/
set: function (remoteProcessGroupEntities) {
var set = function (remoteProcessGroupEntity) {
if (remoteProcessGroupMap.has(remoteProcessGroupEntity.id)) {
// update the current entry
var remoteProcessGroupEntry = remoteProcessGroupMap.get(remoteProcessGroupEntity.id);
$.extend(remoteProcessGroupEntry, remoteProcessGroupEntity);
// update the remote process group in the UI
d3.select('#id-' + remoteProcessGroupEntry.id).call(updateRemoteProcessGroups);
}
};
// determine how to handle the specified remote process group
if ($.isArray(remoteProcessGroupEntities)) {
$.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
set(remoteProcessGroupEntity);
});
} else {
set(remoteProcessGroupEntities);
}
},
/**
* Sets the remote process group status using the specified status.
*

View File

@ -204,8 +204,8 @@ nf.ReportingTask = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// update the task
renderReportingTask(response.reportingTask);
@ -265,8 +265,8 @@ nf.ReportingTask = (function () {
contentType: 'application/json'
}).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.reportingTask)) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
}
}).fail(handleReportingTaskConfigurationError);
} else {
@ -355,6 +355,7 @@ nf.ReportingTask = (function () {
// initialize the property table
$('#reporting-task-properties').propertytable({
readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-reporting-task-property-container',
descriptorDeferred: getReportingTaskPropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
@ -376,6 +377,7 @@ nf.ReportingTask = (function () {
// initialize the property table
$('#reporting-task-properties').propertytable('destroy').propertytable({
readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-reporting-task-property-container',
descriptorDeferred: getReportingTaskPropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty
@ -722,8 +724,8 @@ nf.ReportingTask = (function () {
}),
dataType: 'json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// remove the task
var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance');

View File

@ -56,20 +56,12 @@ nf.Settings = (function () {
// register the click listener for the archive link
$('#archive-flow-link').click(function () {
var revision = nf.Client.getRevision();
$.ajax({
type: 'POST',
url: config.urls.controllerArchive,
data: {
version: revision.version,
clientId: revision.clientId
},
dataType: 'json'
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// show the result dialog
nf.Dialog.showOkDialog({
dialogContent: 'A new flow archive was successfully created.',
@ -83,7 +75,9 @@ nf.Settings = (function () {
// marshal the configuration details
var configuration = marshalConfiguration();
var entity = {
'revision': nf.Client.getRevision(),
'revision': nf.Client.getRevision({
'version': 0
}),
'config': configuration
};
@ -95,15 +89,12 @@ nf.Settings = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// TODO - update the revision
// nf.Client.setRevision(response.revision);
// update the displayed name
document.title = response.config.name;
// set the data flow title and close the shell
nf.Canvas.reload();
// close the settings dialog
nf.Dialog.showOkDialog({
dialogContent: 'Settings successfully applied.',
@ -308,7 +299,6 @@ nf.Settings = (function () {
// build the controller service entity
var controllerServiceEntity = {
'revision': nf.Client.getRevision(),
'controllerService': {
'type': controllerServiceType
}
@ -322,9 +312,6 @@ nf.Settings = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// add the item
var controllerService = response.controllerService;
var controllerServicesGrid = $('#controller-services-table').data('gridInstance');
@ -763,7 +750,9 @@ nf.Settings = (function () {
} else if (target.hasClass('delete-controller-service')) {
nf.ControllerService.remove(controllerService);
} else if (target.hasClass('view-state-controller-service')) {
nf.ComponentState.showState(controllerService, controllerService.state === 'DISABLED');
nf.ComponentState.showState(controllerService, {
'version': 0
}, controllerService.state === 'DISABLED');
}
} else if (controllerServicesGrid.getColumns()[args.cell].id === 'moreDetails') {
if (target.hasClass('view-controller-service')) {
@ -1041,7 +1030,6 @@ nf.Settings = (function () {
// build the reporting task entity
var reportingTaskEntity = {
'revision': nf.Client.getRevision(),
'reportingTask': {
'type': reportingTaskType
}
@ -1055,9 +1043,6 @@ nf.Settings = (function () {
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// add the item
var reportingTask = response.reportingTask;
var reportingTaskGrid = $('#reporting-tasks-table').data('gridInstance');
@ -1419,7 +1404,9 @@ nf.Settings = (function () {
nf.ReportingTask.remove(reportingTask);
} else if (target.hasClass('view-state-reporting-task')) {
var canClear = reportingTask.state === 'STOPPED' && reportingTask.activeThreadCount === 0;
nf.ComponentState.showState(reportingTask, canClear);
nf.ComponentState.showState(reportingTask, {
'version': 0
}, canClear);
}
} else if (reportingTasksGrid.getColumns()[args.cell].id === 'moreDetails') {
if (target.hasClass('view-reporting-task')) {
@ -1692,7 +1679,7 @@ nf.Settings = (function () {
/**
* Loads the settings.
*/
loadSettings: function (reloadStatus) {
loadSettings: function () {
var settings = $.ajax({
type: 'GET',
url: config.urls.controllerConfig,
@ -1726,12 +1713,7 @@ nf.Settings = (function () {
var reportingTasks = loadReportingTasks();
// return a deferred for all parts of the settings
return $.when(settings, controllerServices, reportingTasks).done(function () {
// always reload the status, unless the flag is specifically set to false
if (reloadStatus !== false) {
nf.Canvas.reloadStatus();
}
}).fail(nf.Common.handleAjaxError);
return $.when(settings, controllerServices, reportingTasks).fail(nf.Common.handleAjaxError);
},
/**

View File

@ -36,14 +36,14 @@ nf.Snippet = (function () {
var snippet = {
parentGroupId: nf.Canvas.getGroupId(),
linked: nf.Common.isDefinedAndNotNull(linked) ? linked : false,
processors: [],
funnels: [],
inputPorts: [],
outputPorts: [],
remoteProcessGroups: [],
processGroups: [],
connections: [],
labels: []
processors: {},
funnels: {},
inputPorts: {},
outputPorts: {},
remoteProcessGroups: {},
processGroups: {},
connections: {},
labels: {}
};
// go through each component and identify its type
@ -51,21 +51,21 @@ nf.Snippet = (function () {
var selected = d3.select(this);
if (nf.CanvasUtils.isProcessor(selected)) {
snippet.processors.push(d.id);
snippet.processors[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isFunnel(selected)) {
snippet.funnels.push(d.id);
snippet.funnels[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isLabel(selected)) {
snippet.labels.push(d.id);
snippet.labels[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isInputPort(selected)) {
snippet.inputPorts.push(d.id);
snippet.inputPorts[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isOutputPort(selected)) {
snippet.outputPorts.push(d.id);
snippet.outputPorts[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isProcessGroup(selected)) {
snippet.processGroups.push(d.id);
snippet.processGroups[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isRemoteProcessGroup(selected)) {
snippet.remoteProcessGroups.push(d.id);
snippet.remoteProcessGroups[d.id] = nf.Client.getRevision(selected.datum());
} else if (nf.CanvasUtils.isConnection(selected)) {
snippet.connections.push(d.id);
snippet.connections[d.id] = nf.Client.getRevision(selected.datum());
}
});
@ -79,7 +79,6 @@ nf.Snippet = (function () {
*/
create: function (snippet) {
var snippetEntity = {
'revision': nf.Client.getRevision(),
'snippet': snippet
};
@ -89,9 +88,6 @@ nf.Snippet = (function () {
data: JSON.stringify(snippetEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
},
@ -103,7 +99,6 @@ nf.Snippet = (function () {
*/
copy: function (snippetId, origin) {
var copySnippetRequestEntity = {
'revision': nf.Client.getRevision(),
'snippetId': snippetId,
'originX': origin.x,
'originY': origin.y
@ -115,108 +110,93 @@ nf.Snippet = (function () {
data: JSON.stringify(copySnippetRequestEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
},
/**
* Removes the specified snippet.
*
* @argument {string} snippetId The snippet id
* @argument {string} snippetEntity The snippet entity
*/
remove: function (snippetId) {
var revision = nf.Client.getRevision();
remove: function (snippetEntity) {
var revision = nf.Client.getRevision(snippetEntity);
return $.ajax({
type: 'DELETE',
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetId) + '?' + $.param({
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetEntity.id) + '?' + $.param({
version: revision.version,
clientId: revision.clientId
})
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
},
/**
* Moves the snippet into the specified group.
*
* @argument {string} snippetId The snippet id
* @argument {object} snippetEntity The snippet entity
* @argument {string} newGroupId The new group id
*/
move: function (snippetId, newGroupId) {
var snippetEntity = {
'revision': nf.Client.getRevision(),
move: function (snippetEntity, newGroupId) {
var moveSnippetEntity = {
'revision': nf.Client.getRevision(snippetEntity),
'snippet': {
'id': snippetId,
'id': snippetEntity.id,
'parentGroupId': newGroupId
}
};
return $.ajax({
type: 'PUT',
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetId),
data: JSON.stringify(snippetEntity),
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetEntity.id),
data: JSON.stringify(moveSnippetEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
},
/**
* Unlinks the snippet from the actual data flow.
*
* @argument {string} snippetId The snippet id
* @argument {object} snippetEntity The snippet enmtity
*/
unlink: function (snippetId) {
var snippetEntity = {
'revision': nf.Client.getRevision(),
unlink: function (snippetEntity) {
var unlinkSnippetEntity = {
'revision': nf.Client.getRevision(snippetEntity),
'snippet': {
'id': snippetId,
'id': snippetEntity.id,
'linked': false
}
};
return $.ajax({
type: 'PUT',
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetId),
data: JSON.stringify(snippetEntity),
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetEntity.id),
data: JSON.stringify(unlinkSnippetEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
},
/**
* Links the snippet from the actual data flow.
*
* @argument {string} snippetId The snippet id
* @argument {object} snippetEntity The snippet entity
*/
link: function (snippetId) {
var snippetEntity = {
'revision': nf.Client.getRevision(),
link: function (snippetEntity) {
var linkSnippetEntity = {
'revision': nf.Client.getRevision(snippetEntity),
'snippet': {
'id': snippetId,
'id': snippetEntity.id,
'linked': true
}
};
return $.ajax({
type: 'PUT',
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetId),
data: JSON.stringify(snippetEntity),
url: config.urls.processGroups + '/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/snippets/' + encodeURIComponent(snippetEntity.id),
data: JSON.stringify(linkSnippetEntity),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
});
}
};

View File

@ -17,43 +17,34 @@
/* global nf */
nf.Client = {};
nf.Client.version = -1;
nf.Client.clientId = null;
/**
* Gets the current revision.
*/
nf.Client.getRevision = function () {
nf.Client = (function() {
var clientId = null;
return {
version: nf.Client.version,
clientId: nf.Client.clientId
};
};
/**
* Initializes the client.
*
* @returns deferred
*/
init: function () {
return $.ajax({
type: 'GET',
url: '../nifi-api/flow/client-id',
}).done(function (cid) {
clientId = cid;
});
},
/**
* Sets the current revision.
*
* @argument {integer} revision The revision
*/
nf.Client.setRevision = function (revision) {
// ensure a value was returned
if (nf.Common.isDefinedAndNotNull(revision.version)) {
if (nf.Common.isDefinedAndNotNull(nf.Client.version)) {
// if the client version was already set, ensure
// the new value is greater
if (revision.version > nf.Client.version) {
nf.Client.version = revision.version;
}
} else {
// otherwise just set the value
nf.Client.version = revision.version;
/**
* Builds the revision fof the specified component
* @param d The component
* @returns The revision
*/
getRevision: function (d) {
return {
'clientId': clientId,
'version': d.revision.version
};
}
}
// ensure a value was returned
if (nf.Common.isDefinedAndNotNull(revision.clientId)) {
nf.Client.clientId = revision.clientId;
}
};
};
}());

View File

@ -415,8 +415,7 @@ nf.Common = (function () {
nf.ContextMenu.hide();
// shut off the auto refresh
nf.Canvas.stopRevisionPolling();
nf.Canvas.stopStatusPolling();
nf.Canvas.stopPolling();
}
},