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; package org.apache.nifi.web.api.dto.flow;
import com.wordnik.swagger.annotations.ApiModelProperty; 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.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Date;
/** /**
* The NiFi flow starting at a given Process Group. * The NiFi flow starting at a given Process Group.
@ -31,6 +34,7 @@ public class ProcessGroupFlowDTO {
private String parentGroupId; private String parentGroupId;
private FlowBreadcrumbDTO breadcrumb; private FlowBreadcrumbDTO breadcrumb;
private FlowDTO flow; private FlowDTO flow;
private Date lastRefreshed;
/** /**
* @return contents of this process group. This field will be populated if the request is marked verbose * @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; 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 com.wordnik.swagger.annotations.ApiModelProperty;
import org.apache.nifi.web.api.dto.ConnectionDTO; import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.PositionDTO; import org.apache.nifi.web.api.dto.PositionDTO;
import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import java.util.List; import java.util.List;
@ -30,6 +31,7 @@ import java.util.List;
public class ConnectionEntity extends ComponentEntity { public class ConnectionEntity extends ComponentEntity {
private ConnectionDTO component; private ConnectionDTO component;
private ConnectionStatusDTO status;
private List<PositionDTO> bends; private List<PositionDTO> bends;
private Integer labelIndex; private Integer labelIndex;
private String sourceId; private String sourceId;
@ -48,6 +50,20 @@ public class ConnectionEntity extends ComponentEntity {
this.component = component; 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 * @return position of the bend points on this connection
*/ */

View File

@ -16,7 +16,9 @@
*/ */
package org.apache.nifi.web.api.entity; 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.PortDTO;
import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
@ -27,6 +29,7 @@ import javax.xml.bind.annotation.XmlRootElement;
public class PortEntity extends ComponentEntity { public class PortEntity extends ComponentEntity {
private PortDTO component; private PortDTO component;
private PortStatusDTO status;
private String portType; private String portType;
/** /**
@ -40,6 +43,20 @@ public class PortEntity extends ComponentEntity {
this.component = component; 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() { public String getPortType() {
return portType; return portType;
} }

View File

@ -17,7 +17,10 @@
package org.apache.nifi.web.api.entity; package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement; 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.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. * 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 { public class ProcessGroupEntity extends ComponentEntity {
private ProcessGroupDTO component; 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. * The ProcessGroupDTO that is being serialized.
@ -40,4 +54,129 @@ public class ProcessGroupEntity extends ComponentEntity {
this.component = component; 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; package org.apache.nifi.web.api.entity;
import javax.xml.bind.annotation.XmlRootElement; 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.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. * 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 { public class RemoteProcessGroupEntity extends ComponentEntity {
private RemoteProcessGroupDTO component; private RemoteProcessGroupDTO component;
private RemoteProcessGroupStatusDTO status;
private Integer inputPortCount;
private Integer outputPortCount;
/** /**
* The RemoteProcessGroupDTO that is being serialized. * The RemoteProcessGroupDTO that is being serialized.
@ -40,4 +47,45 @@ public class RemoteProcessGroupEntity extends ComponentEntity {
this.component = component; 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; 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.ScheduledState;
import org.apache.nifi.controller.repository.claim.ContentDirection; import org.apache.nifi.controller.repository.claim.ContentDirection;
import org.apache.nifi.controller.service.ControllerServiceState; 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.RemoteProcessGroupPortDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO; import org.apache.nifi.web.api.dto.ReportingTaskDTO;
import org.apache.nifi.web.api.dto.ResourceDTO; 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.SnippetDTO;
import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO; import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
import org.apache.nifi.web.api.dto.TemplateDTO; 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.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.SnippetEntity; import org.apache.nifi.web.api.entity.SnippetEntity;
import java.util.Date;
import java.util.List;
import java.util.Set;
/** /**
* Defines the NiFiServiceFacade interface. * Defines the NiFiServiceFacade interface.
*/ */
@ -214,10 +213,9 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new archive of the flow configuration. * Creates a new archive of the flow configuration.
* *
* @param revision Revision to compare with current base revision
* @return snapshot * @return snapshot
*/ */
ProcessGroupEntity createArchive(Revision revision); ProcessGroupEntity createArchive();
/** /**
* Sets the annotation data for a processor. * Sets the annotation data for a processor.
@ -297,13 +295,6 @@ public interface NiFiServiceFacade {
*/ */
Set<DocumentedTypeDTO> getWorkQueuePrioritizerTypes(); Set<DocumentedTypeDTO> getWorkQueuePrioritizerTypes();
/**
* Returns the current revision.
*
* @return revision
*/
RevisionDTO getRevision();
// ---------------------------------------- // ----------------------------------------
// Template methods // Template methods
// ---------------------------------------- // ----------------------------------------
@ -328,14 +319,13 @@ public interface NiFiServiceFacade {
/** /**
* Instantiate the corresponding template. * Instantiate the corresponding template.
* *
* @param revision revision
* @param groupId group id * @param groupId group id
* @param templateId template id * @param templateId template id
* @param originX x * @param originX x
* @param originY y * @param originY y
* @return snapshot * @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. * Gets the template with the specified id.
@ -373,12 +363,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new Processor. * Creates a new Processor.
* *
* @param revision Revision to compare with current base revision
* @param groupId Group id * @param groupId Group id
* @param processorDTO The processor DTO * @param processorDTO The processor DTO
* @return The new 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. * Gets the Processor transfer object for the specified id.
@ -492,12 +481,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new Relationship target. * Creates a new Relationship target.
* *
* @param revision Revision to compare with current base revision
* @param groupId group * @param groupId group
* @param connectionDTO The Connection DTO * @param connectionDTO The Connection DTO
* @return 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. * Determines if this connection can be listed.
@ -618,12 +606,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new input port. * 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 groupId The id of the group this port should be create in
* @param inputPortDTO The input PortDTO * @param inputPortDTO The input PortDTO
* @return snapshot * @return snapshot
*/ */
PortEntity createInputPort(Revision revision, String groupId, PortDTO inputPortDTO); PortEntity createInputPort(String groupId, PortDTO inputPortDTO);
/** /**
* Gets an input port. * Gets an input port.
@ -687,12 +674,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new output port. * 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 groupId The id of the group this port should be create in
* @param outputPortDTO The output PortDTO * @param outputPortDTO The output PortDTO
* @return snapshot * @return snapshot
*/ */
PortEntity createOutputPort(Revision revision, String groupId, PortDTO outputPortDTO); PortEntity createOutputPort( String groupId, PortDTO outputPortDTO);
/** /**
* Gets an output port. * Gets an output port.
@ -769,11 +755,10 @@ public interface NiFiServiceFacade {
* Creates a new process group. * Creates a new process group.
* *
* @param parentGroupId The id of the parent group * @param parentGroupId The id of the parent group
* @param revision Revision to compare with current base revision
* @param processGroupDTO The ProcessGroupDTO * @param processGroupDTO The ProcessGroupDTO
* @return snapshot * @return snapshot
*/ */
ProcessGroupEntity createProcessGroup(String parentGroupId, Revision revision, ProcessGroupDTO processGroupDTO); ProcessGroupEntity createProcessGroup(String parentGroupId, ProcessGroupDTO processGroupDTO);
/** /**
* Returns the process group. * Returns the process group.
@ -829,12 +814,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new remote process group. * Creates a new remote process group.
* *
* @param revision Revision to compare with current base revision
* @param groupId The id of the parent group * @param groupId The id of the parent group
* @param remoteProcessGroupDTO The RemoteProcessGroupDTO * @param remoteProcessGroupDTO The RemoteProcessGroupDTO
* @return snapshot * @return snapshot
*/ */
RemoteProcessGroupEntity createRemoteProcessGroup(Revision revision, String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO); RemoteProcessGroupEntity createRemoteProcessGroup(String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO);
/** /**
* Gets a remote process group. * Gets a remote process group.
@ -942,12 +926,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a funnel. * Creates a funnel.
* *
* @param revision Revision to compare with current base revision
* @param groupId group * @param groupId group
* @param funnelDTO funnel * @param funnelDTO funnel
* @return The funnel DTO * @return The funnel DTO
*/ */
FunnelEntity createFunnel(Revision revision, String groupId, FunnelDTO funnelDTO); FunnelEntity createFunnel(String groupId, FunnelDTO funnelDTO);
/** /**
* Gets the specified funnel. * Gets the specified funnel.
@ -1072,12 +1055,11 @@ public interface NiFiServiceFacade {
/** /**
* Creates a label. * Creates a label.
* *
* @param revision Revision to compare with current base revision
* @param groupId group * @param groupId group
* @param labelDTO The label DTO * @param labelDTO The label DTO
* @return 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. * Gets the specified label.
@ -1320,23 +1302,21 @@ public interface NiFiServiceFacade {
/** /**
* Creates a new snippet based off the existing snippet. * Creates a new snippet based off the existing snippet.
* *
* @param revision revision
* @param groupId group id * @param groupId group id
* @param snippetId snippet id * @param snippetId snippet id
* @param originX x * @param originX x
* @param originY y * @param originY y
* @return snapshot * @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. * Creates a new snippet.
* *
* @param revision revision
* @param snippet snippet * @param snippet snippet
* @return snapshot * @return snapshot
*/ */
ConfigurationSnapshot<SnippetDTO> createSnippet(Revision revision, SnippetDTO snippet); SnippetEntity createSnippet(SnippetDTO snippet);
/** /**
* Gets the specified snippet. * Gets the specified snippet.
@ -1344,7 +1324,7 @@ public interface NiFiServiceFacade {
* @param snippetId id * @param snippetId id
* @return snippet * @return snippet
*/ */
SnippetDTO getSnippet(String snippetId); SnippetEntity getSnippet(String snippetId);
/** /**
* Determines if this snippet can be updated. * Determines if this snippet can be updated.
@ -1360,7 +1340,7 @@ public interface NiFiServiceFacade {
* @param snippetDto snippet * @param snippetDto snippet
* @return snapshot * @return snapshot
*/ */
ConfigurationSnapshot<SnippetDTO> updateSnippet(Revision revision, SnippetDTO snippetDto); UpdateResult<SnippetEntity> updateSnippet(Revision revision, SnippetDTO snippetDto);
/** /**
* Determines if this snippet can be removed. * 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. * 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 httpServletRequest request
* @param revisionEntity The revision is used to verify the client is working with the latest version of the flow.
* @return A processGroupEntity. * @return A processGroupEntity.
*/ */
@POST @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.") @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( public Response createArchive(@Context HttpServletRequest httpServletRequest) {
@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.");
}
// replicate if cluster manager // replicate if cluster manager
if (properties.isClusterManager()) { if (properties.isClusterManager()) {
@ -154,8 +143,7 @@ public class ControllerResource extends ApplicationResource {
} }
// create the archive // create the archive
final RevisionDTO requestRevision = revisionEntity.getRevision(); final ProcessGroupEntity entity = serviceFacade.createArchive();
final ProcessGroupEntity entity = serviceFacade.createArchive(new Revision(requestRevision.getVersion(), requestRevision.getClientId()));
// generate the response // generate the response
URI uri = URI.create(generateResourceUri("controller", "archive")); 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.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils; 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.NodeResponse;
import org.apache.nifi.cluster.manager.exception.UnknownNodeException; import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
import org.apache.nifi.cluster.manager.impl.WebClusterManager; 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.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.nio.charset.StandardCharsets;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID;
/** /**
* RESTful endpoint for managing a Flow. * RESTful endpoint for managing a Flow.
@ -208,10 +212,9 @@ public class FlowResource extends ApplicationResource {
@Consumes(MediaType.WILDCARD) @Consumes(MediaType.WILDCARD)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("process-groups/{id}") @Path("process-groups/{id}")
// TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
@ApiOperation( @ApiOperation(
value = "Gets a process group", value = "Gets a process group",
response = ProcessGroupEntity.class, response = ProcessGroupFlowEntity.class,
authorizations = { authorizations = {
@Authorization(value = "Read Only", type = "ROLE_MONITOR"), @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
@Authorization(value = "Data Flow Manager", type = "ROLE_DFM"), @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@ -268,6 +271,43 @@ public class FlowResource extends ApplicationResource {
return clusterContext(generateOkResponse(processGroupEntity)).build(); 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 // search
// ------ // ------
@ -319,59 +359,6 @@ public class FlowResource extends ApplicationResource {
return clusterContext(noCache(Response.ok(entity))).build(); 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. * Retrieves the status for this NiFi.
* *

View File

@ -16,44 +16,19 @@
*/ */
package org.apache.nifi.web.api; package org.apache.nifi.web.api;
import java.io.InputStream; import com.sun.jersey.api.core.ResourceContext;
import java.net.URI; import com.sun.jersey.multipart.FormDataParam;
import java.net.URISyntaxException; import com.wordnik.swagger.annotations.Api;
import java.nio.charset.StandardCharsets; import com.wordnik.swagger.annotations.ApiOperation;
import java.util.Date; import com.wordnik.swagger.annotations.ApiParam;
import java.util.HashMap; import com.wordnik.swagger.annotations.ApiResponse;
import java.util.Map; import com.wordnik.swagger.annotations.ApiResponses;
import java.util.Set; import com.wordnik.swagger.annotations.Authorization;
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 org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.cluster.context.ClusterContext; import org.apache.nifi.cluster.context.ClusterContext;
import org.apache.nifi.cluster.context.ClusterContextThreadLocal; import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
import org.apache.nifi.cluster.manager.impl.WebClusterManager; import org.apache.nifi.cluster.manager.impl.WebClusterManager;
import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.ConfigurationSnapshot;
import org.apache.nifi.web.NiFiServiceFacade; import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.Revision; import org.apache.nifi.web.Revision;
import org.apache.nifi.web.UpdateResult; import org.apache.nifi.web.UpdateResult;
@ -96,14 +71,36 @@ import org.apache.nifi.web.util.Availability;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.sun.jersey.api.core.ResourceContext; import javax.servlet.http.HttpServletRequest;
import com.sun.jersey.multipart.FormDataParam; import javax.ws.rs.Consumes;
import com.wordnik.swagger.annotations.Api; import javax.ws.rs.DELETE;
import com.wordnik.swagger.annotations.ApiOperation; import javax.ws.rs.DefaultValue;
import com.wordnik.swagger.annotations.ApiParam; import javax.ws.rs.GET;
import com.wordnik.swagger.annotations.ApiResponse; import javax.ws.rs.HttpMethod;
import com.wordnik.swagger.annotations.ApiResponses; import javax.ws.rs.POST;
import com.wordnik.swagger.annotations.Authorization; 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. * RESTful endpoint for managing a Group.
@ -207,6 +204,19 @@ public class ProcessGroupResource extends ApplicationResource {
return flow; 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. * 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."); 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) { if (processGroupEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Process group ID cannot be specified."); throw new IllegalArgumentException("Process group ID cannot be specified.");
} }
@ -506,8 +512,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the process group contents // create the process group contents
final RevisionDTO revision = processGroupEntity.getRevision(); final ProcessGroupEntity entity = serviceFacade.createProcessGroup(groupId, processGroupEntity.getComponent());
final ProcessGroupEntity entity = serviceFacade.createProcessGroup(groupId, new Revision(revision.getVersion(), revision.getClientId()), processGroupEntity.getComponent());
populateRemainingProcessGroupEntityContent(entity); populateRemainingProcessGroupEntityContent(entity);
// generate a 201 created response // generate a 201 created response
@ -623,10 +628,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Processor details must be specified."); throw new IllegalArgumentException("Processor details must be specified.");
} }
if (processorEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (processorEntity.getComponent().getId() != null) { if (processorEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Processor ID cannot be specified."); throw new IllegalArgumentException("Processor ID cannot be specified.");
} }
@ -660,8 +661,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the new processor // create the new processor
final RevisionDTO revision = processorEntity.getRevision(); final ProcessorEntity entity = serviceFacade.createProcessor(groupId, processorEntity.getComponent());
final ProcessorEntity entity = serviceFacade.createProcessor(new Revision(revision.getVersion(), revision.getClientId()), groupId, processorEntity.getComponent());
processorResource.populateRemainingProcessorEntityContent(entity); processorResource.populateRemainingProcessorEntityContent(entity);
// generate a 201 created response // generate a 201 created response
@ -770,10 +770,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Port details must be specified."); throw new IllegalArgumentException("Port details must be specified.");
} }
if (portEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (portEntity.getComponent().getId() != null) { if (portEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Input port ID cannot be specified."); 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 // create the input port and generate the json
final RevisionDTO revision = portEntity.getRevision(); final PortEntity entity = serviceFacade.createInputPort(groupId, portEntity.getComponent());
final PortEntity entity = serviceFacade.createInputPort(new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
inputPortResource.populateRemainingInputPortEntityContent(entity); inputPortResource.populateRemainingInputPortEntityContent(entity);
// build the response // build the response
@ -910,10 +905,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Port details must be specified."); throw new IllegalArgumentException("Port details must be specified.");
} }
if (portEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (portEntity.getComponent().getId() != null) { if (portEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Output port ID cannot be specified."); 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 // create the output port and generate the json
final RevisionDTO revision = portEntity.getRevision(); final PortEntity entity = serviceFacade.createOutputPort(groupId, portEntity.getComponent());
final PortEntity entity = serviceFacade.createOutputPort(
new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
outputPortResource.populateRemainingOutputPortEntityContent(entity); outputPortResource.populateRemainingOutputPortEntityContent(entity);
// build the response // build the response
@ -1052,10 +1041,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Funnel details must be specified."); throw new IllegalArgumentException("Funnel details must be specified.");
} }
if (funnelEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (funnelEntity.getComponent().getId() != null) { if (funnelEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Funnel ID cannot be specified."); throw new IllegalArgumentException("Funnel ID cannot be specified.");
} }
@ -1085,8 +1070,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the funnel and generate the json // create the funnel and generate the json
final RevisionDTO revision = funnelEntity.getRevision(); final FunnelEntity entity = serviceFacade.createFunnel(groupId, funnelEntity.getComponent());
final FunnelEntity entity = serviceFacade.createFunnel(new Revision(revision.getVersion(), revision.getClientId()), groupId, funnelEntity.getComponent());
funnelResource.populateRemainingFunnelEntityContent(entity); funnelResource.populateRemainingFunnelEntityContent(entity);
// build the response // build the response
@ -1193,10 +1177,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Label details must be specified."); throw new IllegalArgumentException("Label details must be specified.");
} }
if (labelEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (labelEntity.getComponent().getId() != null) { if (labelEntity.getComponent().getId() != null) {
throw new IllegalArgumentException("Label ID cannot be specified."); throw new IllegalArgumentException("Label ID cannot be specified.");
} }
@ -1226,9 +1206,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the label and generate the json // create the label and generate the json
final RevisionDTO revision = labelEntity.getRevision(); final LabelEntity entity = serviceFacade.createLabel(groupId, labelEntity.getComponent());
final LabelEntity entity = serviceFacade.createLabel(
new Revision(revision.getVersion(), revision.getClientId()), groupId, labelEntity.getComponent());
labelResource.populateRemainingLabelEntityContent(entity); labelResource.populateRemainingLabelEntityContent(entity);
// build the response // build the response
@ -1335,10 +1313,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Remote process group details must be specified."); 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(); final RemoteProcessGroupDTO requestProcessGroupDTO = remoteProcessGroupEntity.getComponent();
if (requestProcessGroupDTO.getId() != null) { if (requestProcessGroupDTO.getId() != null) {
@ -1400,8 +1374,7 @@ public class ProcessGroupResource extends ApplicationResource {
requestProcessGroupDTO.setTargetUri(controllerUri); requestProcessGroupDTO.setTargetUri(controllerUri);
// create the remote process group // create the remote process group
final RevisionDTO revision = remoteProcessGroupEntity.getRevision(); final RemoteProcessGroupEntity entity = serviceFacade.createRemoteProcessGroup(groupId, requestProcessGroupDTO);
final RemoteProcessGroupEntity entity = serviceFacade.createRemoteProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), groupId, requestProcessGroupDTO);
remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntityContent(entity); remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntityContent(entity);
return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build(); 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."); 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())) { 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", 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)); connectionEntity.getComponent().getParentGroupId(), groupId));
@ -1559,8 +1528,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the new relationship target // create the new relationship target
final RevisionDTO revision = connectionEntity.getRevision(); final ConnectionEntity entity = serviceFacade.createConnection(groupId, connection);
final ConnectionEntity entity = serviceFacade.createConnection(new Revision(revision.getVersion(), revision.getClientId()), groupId, connection);
connectionResource.populateRemainingConnectionEntityContent(entity); connectionResource.populateRemainingConnectionEntityContent(entity);
// extract the href and build the response // extract the href and build the response
@ -1670,10 +1638,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Snippet details must be specified."); throw new IllegalArgumentException("Snippet details must be specified.");
} }
if (snippetEntity.getRevision() == null) {
throw new IllegalArgumentException("Revision must be specified.");
}
if (snippetEntity.getSnippet().getId() != null) { if (snippetEntity.getSnippet().getId() != null) {
throw new IllegalArgumentException("Snippet ID cannot be specified."); throw new IllegalArgumentException("Snippet ID cannot be specified.");
} }
@ -1708,24 +1672,11 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the snippet // create the snippet
final RevisionDTO revision = snippetEntity.getRevision(); final SnippetEntity entity = serviceFacade.createSnippet(snippetEntity.getSnippet());
final ConfigurationSnapshot<SnippetDTO> response = serviceFacade.createSnippet(new Revision(revision.getVersion(), revision.getClientId()), snippetEntity.getSnippet()); populateRemainingSnippetEntityContent(entity);
// 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));
// build the response // 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 // get the snippet
final SnippetDTO snippet = serviceFacade.getSnippet(id); final SnippetEntity entity = serviceFacade.getSnippet(id);
populateRemainingSnippetEntityContent(entity);
// create the revision
final RevisionDTO revision = new RevisionDTO();
// create the response entity
final SnippetEntity entity = new SnippetEntity();
entity.setRevision(revision);
entity.setSnippet(populateRemainingSnippetContent(snippet));
return clusterContext(generateOkResponse(entity)).build(); return clusterContext(generateOkResponse(entity)).build();
} }
@ -1856,32 +1800,25 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// handle expects request (usually from the cluster manager) // handle expects request (usually from the cluster manager)
final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER); final Revision revision = getRevision(snippetEntity, id);
if (expects != null) { final boolean validationPhase = isValidationPhase(httpServletRequest);
if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) {
serviceFacade.claimRevision(revision);
}
if (validationPhase) {
serviceFacade.verifyUpdateSnippet(requestSnippetDTO); serviceFacade.verifyUpdateSnippet(requestSnippetDTO);
return generateContinueResponse().build(); return generateContinueResponse().build();
} }
// update the snippet // update the snippet
final RevisionDTO revision = snippetEntity.getRevision(); final UpdateResult<SnippetEntity> updateResult = serviceFacade.updateSnippet(revision, snippetEntity.getSnippet());
final ConfigurationSnapshot<SnippetDTO> controllerResponse = serviceFacade.updateSnippet(
new Revision(revision.getVersion(), revision.getClientId()), snippetEntity.getSnippet());
// get the results // get the results
final SnippetDTO snippet = controllerResponse.getConfiguration(); final SnippetEntity entity = updateResult.getResult();
populateRemainingSnippetEntityContent(entity);
// get the updated revision if (updateResult.isNew()) {
final RevisionDTO updatedRevision = new RevisionDTO(); return clusterContext(generateCreatedResponse(URI.create(entity.getSnippet().getUri()), entity)).build();
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();
} else { } else {
return clusterContext(generateOkResponse(entity)).build(); 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.") @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, @Context HttpServletRequest httpServletRequest,
@ApiParam( @ApiParam(
value = "The revision is used to verify the client is working with the latest version of the flow.", 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(); 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) // handle expects request (usually from the cluster manager)
final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER); final boolean validationPhase = isValidationPhase(httpServletRequest);
if (expects != null) {
// 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); serviceFacade.verifyDeleteSnippet(id);
return generateContinueResponse().build(); return generateContinueResponse().build();
} }
// determine the specified version
Long clientVersion = null;
if (version != null) {
clientVersion = version.getLong();
}
// delete the specified snippet // 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(); return clusterContext(generateOkResponse(snippetEntity)).build();
} }
@ -2032,9 +1971,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// copy the specified snippet // copy the specified snippet
final RevisionDTO requestRevision = copySnippetEntity.getRevision();
final FlowEntity flowEntity = serviceFacade.copySnippet( final FlowEntity flowEntity = serviceFacade.copySnippet(
new Revision(requestRevision.getVersion(), requestRevision.getClientId()),
groupId, copySnippetEntity.getSnippetId(), copySnippetEntity.getOriginX(), copySnippetEntity.getOriginY()); groupId, copySnippetEntity.getSnippetId(), copySnippetEntity.getOriginX(), copySnippetEntity.getOriginY());
// get the snippet // get the snippet
@ -2118,9 +2055,7 @@ public class ProcessGroupResource extends ApplicationResource {
} }
// create the template and generate the json // create the template and generate the json
final RevisionDTO requestRevision = instantiateTemplateRequestEntity.getRevision(); final FlowEntity entity = serviceFacade.createTemplateInstance(groupId, instantiateTemplateRequestEntity.getOriginX(),
final FlowEntity entity = serviceFacade.createTemplateInstance(
new Revision(requestRevision.getVersion(), requestRevision.getClientId()), groupId, instantiateTemplateRequestEntity.getOriginX(),
instantiateTemplateRequestEntity.getOriginY(), instantiateTemplateRequestEntity.getTemplateId()); instantiateTemplateRequestEntity.getOriginY(), instantiateTemplateRequestEntity.getTemplateId());
final FlowDTO flowSnippet = entity.getFlow(); final FlowDTO flowSnippet = entity.getFlow();
@ -2473,10 +2408,6 @@ public class ProcessGroupResource extends ApplicationResource {
throw new IllegalArgumentException("Controller service details must be specified."); 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) { if (controllerServiceEntity.getControllerService().getId() != null) {
throw new IllegalArgumentException("Controller service ID cannot be specified."); throw new IllegalArgumentException("Controller service ID cannot be specified.");
} }

View File

@ -16,30 +16,6 @@
*/ */
package org.apache.nifi.web.api.dto; 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.Action;
import org.apache.nifi.action.component.details.ComponentDetails; import org.apache.nifi.action.component.details.ComponentDetails;
import org.apache.nifi.action.component.details.ExtensionDetails; 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.RemoteGroupPort;
import org.apache.nifi.remote.RootGroupPort; import org.apache.nifi.remote.RootGroupPort;
import org.apache.nifi.reporting.Bulletin; import org.apache.nifi.reporting.Bulletin;
import org.apache.nifi.reporting.BulletinRepository;
import org.apache.nifi.reporting.ReportingTask; import org.apache.nifi.reporting.ReportingTask;
import org.apache.nifi.scheduling.SchedulingStrategy; import org.apache.nifi.scheduling.SchedulingStrategy;
import org.apache.nifi.util.FormatUtils; 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.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; 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 { public final class DtoFactory {
@ -664,9 +665,6 @@ public final class DtoFactory {
if (funnel == null) { if (funnel == null) {
return null; return null;
} }
if (!funnel.isAuthorized(authorizer, RequestAction.READ)) {
return null;
}
final FunnelDTO dto = new FunnelDTO(); final FunnelDTO dto = new FunnelDTO();
dto.setId(funnel.getIdentifier()); dto.setId(funnel.getIdentifier());
@ -766,7 +764,7 @@ public final class DtoFactory {
return dto; return dto;
} }
public ProcessGroupStatusDTO createProcessGroupStatusDto(final BulletinRepository bulletinRepository, final ProcessGroupStatus processGroupStatus) { public ProcessGroupStatusDTO createConciseProcessGroupStatusDto(final ProcessGroupStatus processGroupStatus) {
final ProcessGroupStatusDTO processGroupStatusDto = new ProcessGroupStatusDTO(); final ProcessGroupStatusDTO processGroupStatusDto = new ProcessGroupStatusDTO();
processGroupStatusDto.setId(processGroupStatus.getId()); processGroupStatusDto.setId(processGroupStatus.getId());
processGroupStatusDto.setName(processGroupStatus.getName()); processGroupStatusDto.setName(processGroupStatus.getName());
@ -794,6 +792,12 @@ public final class DtoFactory {
snapshot.setBytesReceived(processGroupStatus.getBytesReceived()); snapshot.setBytesReceived(processGroupStatus.getBytesReceived());
snapshot.setActiveThreadCount(processGroupStatus.getActiveThreadCount()); snapshot.setActiveThreadCount(processGroupStatus.getActiveThreadCount());
StatusMerger.updatePrettyPrintedFields(snapshot); StatusMerger.updatePrettyPrintedFields(snapshot);
return processGroupStatusDto;
}
public ProcessGroupStatusDTO createProcessGroupStatusDto(final ProcessGroupStatus processGroupStatus) {
final ProcessGroupStatusDTO processGroupStatusDto = createConciseProcessGroupStatusDto(processGroupStatus);
final ProcessGroupStatusSnapshotDTO snapshot = processGroupStatusDto.getAggregateSnapshot();
// processor status // processor status
final Collection<ProcessorStatusSnapshotDTO> processorStatDtoCollection = new ArrayList<>(); final Collection<ProcessorStatusSnapshotDTO> processorStatDtoCollection = new ArrayList<>();
@ -823,7 +827,7 @@ public final class DtoFactory {
final Collection<ProcessGroupStatus> childProcessGroupStatusCollection = processGroupStatus.getProcessGroupStatus(); final Collection<ProcessGroupStatus> childProcessGroupStatusCollection = processGroupStatus.getProcessGroupStatus();
if (childProcessGroupStatusCollection != null) { if (childProcessGroupStatusCollection != null) {
for (final ProcessGroupStatus childProcessGroupStatus : childProcessGroupStatusCollection) { for (final ProcessGroupStatus childProcessGroupStatus : childProcessGroupStatusCollection) {
final ProcessGroupStatusDTO childProcessGroupStatusDto = createProcessGroupStatusDto(bulletinRepository, childProcessGroupStatus); final ProcessGroupStatusDTO childProcessGroupStatusDto = createProcessGroupStatusDto(childProcessGroupStatus);
childProcessGroupStatusDtoCollection.add(childProcessGroupStatusDto.getAggregateSnapshot()); childProcessGroupStatusDtoCollection.add(childProcessGroupStatusDto.getAggregateSnapshot());
} }
} }
@ -1504,11 +1508,12 @@ public final class DtoFactory {
return createProcessGroupDto(group, false); 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(); final ProcessGroupFlowDTO dto = new ProcessGroupFlowDTO();
dto.setId(group.getIdentifier()); dto.setId(group.getIdentifier());
dto.setLastRefreshed(new Date());
dto.setBreadcrumb(createBreadcrumbDto(group)); dto.setBreadcrumb(createBreadcrumbDto(group));
dto.setFlow(createFlowDto(group)); dto.setFlow(createFlowDto(group, groupStatus, revisionManager));
final ProcessGroup parent = group.getParent(); final ProcessGroup parent = group.getParent();
if (parent != null) { if (parent != null) {
@ -1518,7 +1523,7 @@ public final class DtoFactory {
return dto; 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) { if (snippet == null) {
return null; return null;
} }
@ -1526,96 +1531,172 @@ public final class DtoFactory {
final FlowDTO flow = new FlowDTO(); final FlowDTO flow = new FlowDTO();
for (final ConnectionDTO connection : snippet.getConnections()) { for (final ConnectionDTO connection : snippet.getConnections()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connection.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getConnection(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()) { 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()) { for (final FunnelDTO funnel : snippet.getFunnels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getFunnel(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()) { for (final PortDTO inputPort : snippet.getInputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getInputPort(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()) { for (final PortDTO outputPort : snippet.getOutputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getOutputPort(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()) { for (final LabelDTO label : snippet.getLabels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getLabel(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()) { for (final ProcessGroupDTO processGroup : snippet.getProcessGroups()) {
// clear the contents as we only return a single level/group at a time // clear the contents as we only return a single level/group at a time
processGroup.setContents(null); processGroup.setContents(null);
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processGroup.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessGroup(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()) { for (final ProcessorDTO processor : snippet.getProcessors()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(processor.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessor(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()) { for (final RemoteProcessGroupDTO remoteProcessGroup : snippet.getRemoteProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(remoteProcessGroup.getId()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getRemoteProcessGroup(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; 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(); final FlowDTO dto = new FlowDTO();
for (final ProcessorNode procNode : group.getProcessors()) { for (final ProcessorNode procNode : group.getProcessors()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(procNode.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(procNode); 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()) { for (final Connection connNode : group.getConnections()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(connNode.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(connNode); 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()) { for (final Label label : group.getLabels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(label.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(label); 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()) { for (final Funnel funnel : group.getFunnels()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(funnel.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(funnel); 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()) { for (final ProcessGroup childGroup : group.getProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(childGroup.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(childGroup); 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()) { for (final RemoteProcessGroup rpg : group.getRemoteProcessGroups()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(rpg.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(rpg); 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()) { for (final Port inputPort : group.getInputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(inputPort.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(inputPort); 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()) { for (final Port outputPort : group.getOutputPorts()) {
final RevisionDTO revision = createRevisionDTO(revisionManager.getRevision(outputPort.getIdentifier()));
final AccessPolicyDTO accessPolicy = createAccessPolicyDto(outputPort); 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 // TODO - controller services once they are accessible from the group
@ -2741,10 +2822,10 @@ public final class DtoFactory {
return revisionDTO; return revisionDTO;
} }
public RevisionDTO createRevisionDTO(final Long version, final String clientId) { public RevisionDTO createRevisionDTO(final Revision revision) {
final RevisionDTO dto = new RevisionDTO(); final RevisionDTO dto = new RevisionDTO();
dto.setVersion(version); dto.setVersion(revision.getVersion());
dto.setClientId(clientId); dto.setClientId(revision.getClientId());
return dto; return dto;
} }

View File

@ -16,6 +16,11 @@
*/ */
package org.apache.nifi.web.api.dto; 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.ConnectionEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceEntity;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; 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 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(); final ProcessorEntity entity = new ProcessorEntity();
entity.setRevision(revision); entity.setRevision(revision);
if (dto != null) { if (dto != null) {
entity.setAccessPolicy(accessPolicy); entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId()); entity.setId(dto.getId());
entity.setPosition(dto.getPosition()); entity.setPosition(dto.getPosition());
if (accessPolicy != null && accessPolicy.getCanRead()) { if (accessPolicy != null && accessPolicy.getCanRead()) {
@ -45,11 +51,12 @@ public final class EntityFactory {
return entity; 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(); final PortEntity entity = new PortEntity();
entity.setRevision(revision); entity.setRevision(revision);
if (dto != null) { if (dto != null) {
entity.setAccessPolicy(accessPolicy); entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId()); entity.setId(dto.getId());
entity.setPosition(dto.getPosition()); entity.setPosition(dto.getPosition());
entity.setPortType(dto.getType()); entity.setPortType(dto.getType());
@ -60,13 +67,22 @@ public final class EntityFactory {
return entity; 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(); final ProcessGroupEntity entity = new ProcessGroupEntity();
entity.setRevision(revision); entity.setRevision(revision);
if (dto != null) { if (dto != null) {
entity.setAccessPolicy(accessPolicy); entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId()); entity.setId(dto.getId());
entity.setPosition(dto.getPosition()); 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()) { if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto); entity.setComponent(dto);
} }
@ -108,11 +124,12 @@ public final class EntityFactory {
return entity; 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(); final ConnectionEntity entity = new ConnectionEntity();
entity.setRevision(revision); entity.setRevision(revision);
if (dto != null) { if (dto != null) {
entity.setAccessPolicy(accessPolicy); entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId()); entity.setId(dto.getId());
entity.setPosition(dto.getPosition()); entity.setPosition(dto.getPosition());
entity.setBends(dto.getBends()); entity.setBends(dto.getBends());
@ -142,13 +159,18 @@ public final class EntityFactory {
return entity; 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(); final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
entity.setRevision(revision); entity.setRevision(revision);
if (dto != null) { if (dto != null) {
entity.setAccessPolicy(accessPolicy); entity.setAccessPolicy(accessPolicy);
entity.setStatus(status);
entity.setId(dto.getId()); entity.setId(dto.getId());
entity.setPosition(dto.getPosition()); entity.setPosition(dto.getPosition());
entity.setInputPortCount(dto.getInputPortCount());
entity.setOutputPortCount(dto.getOutputPortCount());
if (accessPolicy != null && accessPolicy.getCanRead()) { if (accessPolicy != null && accessPolicy.getCanRead()) {
entity.setComponent(dto); 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.provenance.lineage.LineageRequestDTO.LineageRequestType;
import org.apache.nifi.web.api.dto.search.ComponentSearchResultDTO; 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.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.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.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.security.ProxiedEntitiesUtils; import org.apache.nifi.web.security.ProxiedEntitiesUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -494,12 +489,12 @@ public class ControllerFacade implements Authorizable {
* @param groupId group id * @param groupId group id
* @return the status for the specified process group * @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); final ProcessGroupStatus processGroupStatus = flowController.getGroupStatus(groupId);
if (processGroupStatus == null) { if (processGroupStatus == null) {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId)); 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 * @param processorId processor id
* @return the status for the specified processor * @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 ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final ProcessorNode processor = root.findProcessor(processorId); 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)); throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
} }
for (final ProcessorStatus processorStatus : processGroupStatus.getProcessorStatus()) { final ProcessorStatus status = processGroupStatus.getProcessorStatus().stream().filter(processorStatus -> processorId.equals(processorStatus.getId())).findFirst().orElse(null);
if (processorId.equals(processorStatus.getId())) { if (status == null) {
return dtoFactory.createProcessorStatusDto(processorStatus); 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 * @param connectionId connection id
* @return the status for the specified connection * @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 ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Connection connection = root.findConnection(connectionId); 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)); throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
} }
for (final ConnectionStatus connectionStatus : processGroupStatus.getConnectionStatus()) { final ConnectionStatus status = processGroupStatus.getConnectionStatus().stream().filter(connectionStatus -> connectionId.equals(connectionStatus.getId())).findFirst().orElse(null);
if (connectionId.equals(connectionStatus.getId())) { if (status == null) {
return dtoFactory.createConnectionStatusDto(connectionStatus); 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 * @param portId input port id
* @return the status for the specified input port * @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 ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Port port = root.findInputPort(portId); 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)); throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
} }
for (final PortStatus portStatus : processGroupStatus.getInputPortStatus()) { final PortStatus status = processGroupStatus.getInputPortStatus().stream().filter(portStatus -> portId.equals(portStatus.getId())).findFirst().orElse(null);
if (portId.equals(portStatus.getId())) { if (status == null) {
return dtoFactory.createPortStatusDto(portStatus); 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 * @param portId output port id
* @return the status for the specified output port * @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 ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final Port port = root.findOutputPort(portId); 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)); throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
} }
for (final PortStatus portStatus : processGroupStatus.getOutputPortStatus()) { final PortStatus status = processGroupStatus.getOutputPortStatus().stream().filter(portStatus -> portId.equals(portStatus.getId())).findFirst().orElse(null);
if (portId.equals(portStatus.getId())) { if (status == null) {
return dtoFactory.createPortStatusDto(portStatus); 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 * @param remoteProcessGroupId remote process group id
* @return the status for the specified remote process group * @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 ProcessGroup root = flowController.getGroup(flowController.getRootGroupId());
final RemoteProcessGroup remoteProcessGroup = root.findRemoteProcessGroup(remoteProcessGroupId); final RemoteProcessGroup remoteProcessGroup = root.findRemoteProcessGroup(remoteProcessGroupId);
@ -640,18 +631,17 @@ public class ControllerFacade implements Authorizable {
} }
final String groupId = remoteProcessGroup.getProcessGroup().getIdentifier(); final String groupId = remoteProcessGroup.getProcessGroup().getIdentifier();
final ProcessGroupStatus processGroupStatus = flowController.getGroupStatus(groupId); final ProcessGroupStatus groupStatus = flowController.getGroupStatus(groupId);
if (processGroupStatus == null) { if (groupStatus == null) {
throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId)); throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId));
} }
for (final RemoteProcessGroupStatus remoteProcessGroupStatus : processGroupStatus.getRemoteProcessGroupStatus()) { final RemoteProcessGroupStatus status = groupStatus.getRemoteProcessGroupStatus().stream().filter(rpgStatus -> remoteProcessGroupId.equals(rpgStatus.getId())).findFirst().orElse(null);
if (remoteProcessGroupId.equals(remoteProcessGroupStatus.getId())) { if (status == null) {
return dtoFactory.createRemoteProcessGroupStatusDto(remoteProcessGroupStatus); 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 { #current-user {
font-family: 'Roboto+Slab'; font-family: 'Roboto Slab';
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
font-size: 12px; font-size: 12px;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -60,18 +60,12 @@ nf.Actions = (function () {
* @param {object} entity * @param {object} entity
*/ */
var updateResource = function (uri, entity) { var updateResource = function (uri, entity) {
// add the revision
entity['revision'] = nf.Client.getRevision();
return $.ajax({ return $.ajax({
type: 'PUT', type: 'PUT',
url: uri, url: uri,
data: JSON.stringify(entity), data: JSON.stringify(entity),
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
}).fail(function (xhr, status, error) { }).fail(function (xhr, status, error) {
if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) { if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
nf.Dialog.showOkDialog({ nf.Dialog.showOkDialog({
@ -404,6 +398,7 @@ nf.Actions = (function () {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': d.id, 'id': d.id,
'state': 'STOPPED' 'state': 'STOPPED'
@ -446,6 +441,7 @@ nf.Actions = (function () {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': d.id, 'id': d.id,
'state': 'DISABLED' 'state': 'DISABLED'
@ -528,6 +524,7 @@ nf.Actions = (function () {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': component 'component': component
}; };
@ -602,6 +599,7 @@ nf.Actions = (function () {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': component 'component': component
}; };
@ -644,6 +642,7 @@ nf.Actions = (function () {
componentsToEnable.each(function (d) { componentsToEnable.each(function (d) {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': d.id, 'id': d.id,
'transmitting': true 'transmitting': true
@ -671,6 +670,7 @@ nf.Actions = (function () {
componentsToDisable.each(function (d) { componentsToDisable.each(function (d) {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': d.id, 'id': d.id,
'transmitting': false 'transmitting': false
@ -772,8 +772,10 @@ nf.Actions = (function () {
/** /**
* Reloads the status for the entire canvas (components and flow.) * Reloads the status for the entire canvas (components and flow.)
*/ */
reloadStatus: function () { reload: function () {
nf.Canvas.reloadStatus(); nf.Canvas.reload({
'transition': true
});
}, },
/** /**
@ -790,7 +792,7 @@ nf.Actions = (function () {
} else { } else {
if (selection.size() === 1) { if (selection.size() === 1) {
var selectionData = selection.datum(); var selectionData = selection.datum();
var revision = nf.Client.getRevision(); var revision = nf.Client.getRevision(selectionData);
$.ajax({ $.ajax({
type: 'DELETE', type: 'DELETE',
@ -800,9 +802,6 @@ nf.Actions = (function () {
}), }),
dataType: 'json' dataType: 'json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// remove the component/connection in question // remove the component/connection in question
nf[selectionData.type].remove(selectionData.id); nf[selectionData.type].remove(selectionData.id);
@ -828,11 +827,9 @@ nf.Actions = (function () {
} else { } else {
// create a snippet for the specified component and link to the data flow // create a snippet for the specified component and link to the data flow
var snippetDetails = nf.Snippet.marshal(selection, true); var snippetDetails = nf.Snippet.marshal(selection, true);
nf.Snippet.create(snippetDetails).done(function (response) { nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
var snippet = response.snippet;
// remove the snippet, effectively removing the components // remove the snippet, effectively removing the components
nf.Snippet.remove(snippet.id).done(function () { nf.Snippet.remove(snippetEntity).done(function () {
var components = d3.map(); var components = d3.map();
// add the id to the type's array // add the id to the type's array
@ -876,11 +873,11 @@ nf.Actions = (function () {
// inform Angular app values have changed // inform Angular app values have changed
nf.ng.Bridge.digest(); nf.ng.Bridge.digest();
}).fail(function (xhr, status, error) { }).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 // unlink and remove just the snippet - if unlinking fails
// just ignore // just ignore
nf.Snippet.unlink(snippet.id).done(function () { nf.Snippet.unlink(snippetEntity).done(function (unlinkedSnippetEntity) {
nf.Snippet.remove(snippet.id); nf.Snippet.remove(unlinkedSnippetEntity);
}); });
nf.Common.handleAjaxError(xhr, status, error); nf.Common.handleAjaxError(xhr, status, error);
@ -1092,7 +1089,7 @@ nf.Actions = (function () {
var processor = selection.datum(); var processor = selection.datum();
// view the state for the selected processor // 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); var snippetDetails = nf.Snippet.marshal(selection, false);
// create the snippet // create the snippet
nf.Snippet.create(snippetDetails).done(function (response) { nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
var snippet = response.snippet;
var createSnippetEntity = { var createSnippetEntity = {
'name': templateName, 'name': templateName,
'description': templateDescription, 'description': templateDescription,
'snippetId': snippet.id 'snippetId': snippetEntity.id
}; };
// create the template // create the template
@ -1251,7 +1247,7 @@ nf.Actions = (function () {
}); });
}).always(function () { }).always(function () {
// remove the snippet // remove the snippet
nf.Snippet.remove(snippet.id); nf.Snippet.remove(snippetEntity);
// clear the template dialog fields // clear the template dialog fields
$('#new-template-name').val(''); $('#new-template-name').val('');
@ -1327,9 +1323,7 @@ nf.Actions = (function () {
}; };
// create a snippet from the details // create a snippet from the details
nf.Snippet.create(data['snippet']).done(function (createResponse) { nf.Snippet.create(data['snippet']).done(function (snippetEntity) {
var snippet = createResponse.snippet;
// determine the origin of the bounding box of the copy // determine the origin of the bounding box of the copy
var origin = pasteLocation; var origin = pasteLocation;
var snippetOrigin = data['origin']; var snippetOrigin = data['origin'];
@ -1342,7 +1336,7 @@ nf.Actions = (function () {
} }
// copy the snippet to the new location // 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; var snippetFlow = copyResponse.flow;
// update the graph accordingly // update the graph accordingly
@ -1355,7 +1349,7 @@ nf.Actions = (function () {
nf.Birdseye.refresh(); nf.Birdseye.refresh();
// remove the original snippet // remove the original snippet
nf.Snippet.remove(snippet.id).fail(reject); nf.Snippet.remove(snippetEntity).fail(reject);
}).fail(function () { }).fail(function () {
// an error occured while performing the copy operation, reload the // an error occured while performing the copy operation, reload the
// graph in case it was a partial success // graph in case it was a partial success
@ -1414,7 +1408,7 @@ nf.Actions = (function () {
// build the connection entity // build the connection entity
var connectionEntity = { var connectionEntity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(connection),
'component': { 'component': {
'id': connection.id, 'id': connection.id,
'zIndex': zIndex 'zIndex': zIndex
@ -1432,9 +1426,6 @@ nf.Actions = (function () {
// update the edge's zIndex // update the edge's zIndex
nf.Connection.set(response); nf.Connection.set(response);
nf.Connection.reorder(); 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 () { nf.CanvasUtils.eligibleForMove(components, groupId).done(function () {
// create a snippet for the specified components and link to the data flow // create a snippet for the specified components and link to the data flow
var snippetDetails = nf.Snippet.marshal(components, true); var snippetDetails = nf.Snippet.marshal(components, true);
nf.Snippet.create(snippetDetails).done(function (response) { nf.Snippet.create(snippetDetails).done(function (snippetEntity) {
var snippet = response.snippet;
// move the snippet into the target // 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(); var componentMap = d3.map();
// add the id to the type's array // add the id to the type's array
@ -90,8 +88,8 @@ nf.CanvasUtils = (function () {
}).always(function () { }).always(function () {
// unable to acutally move the components so attempt to // unable to acutally move the components so attempt to
// unlink and remove just the snippet // unlink and remove just the snippet
nf.Snippet.unlink(snippet.id).done(function () { nf.Snippet.unlink(snippetEntity).done(function (unlinkedSnippetEntity) {
nf.Snippet.remove(snippet.id); nf.Snippet.remove(unlinkedSnippetEntity);
}); });
}); });
}).fail(nf.Common.handleAjaxError).fail(function () { }).fail(nf.Common.handleAjaxError).fail(function () {
@ -200,7 +198,10 @@ nf.CanvasUtils = (function () {
var refreshGraph = $.Deferred(function (deferred) { var refreshGraph = $.Deferred(function (deferred) {
// load a different group if necessary // load a different group if necessary
if (groupId !== nf.Canvas.getGroupId()) { if (groupId !== nf.Canvas.getGroupId()) {
// set the new group id
nf.Canvas.setGroupId(groupId); nf.Canvas.setGroupId(groupId);
// reload
nf.Canvas.reload().done(function () { nf.Canvas.reload().done(function () {
deferred.resolve(); deferred.resolve();
}).fail(function () { }).fail(function () {
@ -259,18 +260,57 @@ nf.CanvasUtils = (function () {
nf.Canvas.View.translate([(center[0] - boundingBox.x) * scale, (center[1] - boundingBox.y) * scale]); 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. * Position the component accordingly.
* *
* @param {selection} updated * @param {selection} updated
*/ */
position: function (updated) { position: function (updated, transition) {
if (updated.empty()) { if (updated.empty()) {
return; return;
} }
// update the processors positioning return nf.CanvasUtils.transition(updated, transition)
updated.attr('transform', function (d) { .attr('transform', function (d) {
return 'translate(' + d.position.x + ', ' + d.position.y + ')'; return 'translate(' + d.position.x + ', ' + d.position.y + ')';
}); });
}, },
@ -458,7 +498,7 @@ nf.CanvasUtils = (function () {
} }
// if there are bulletins show them, otherwise hide // 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 // update the tooltip
selection.select('text.bulletin-icon') selection.select('text.bulletin-icon')
.each(function () { .each(function () {
@ -1135,9 +1175,6 @@ nf.CanvasUtils = (function () {
// set the new group id // set the new group id
nf.Canvas.setGroupId(groupId); nf.Canvas.setGroupId(groupId);
// clear the current components
nf.Graph.removeAll();
// reload the graph // reload the graph
return nf.Canvas.reload().done(function () { return nf.Canvas.reload().done(function () {
// attempt to restore the view // attempt to restore the view

View File

@ -108,8 +108,7 @@ nf.Canvas = (function () {
var MIN_SCALE = 0.2; var MIN_SCALE = 0.2;
var MIN_SCALE_TO_RENDER = 0.6; var MIN_SCALE_TO_RENDER = 0.6;
var revisionPolling = false; var polling = false;
var statusPolling = false;
var groupId = 'root'; var groupId = 'root';
var groupName = null; var groupName = null;
var parentGroupId = 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 * @argument {int} autoRefreshInterval The auto refresh interval
*/ */
var startRevisionPolling = function (autoRefreshInterval) { var startPolling = function (autoRefreshInterval) {
// set polling flag // set polling flag
revisionPolling = true; polling = true;
pollForRevision(autoRefreshInterval); poll(autoRefreshInterval);
}; };
/** /**
* Polls for the revision. * Register the pooler.
* *
* @argument {int} autoRefreshInterval The auto refresh interval * @argument {int} autoRefreshInterval The auto refresh interval
*/ */
var pollForRevision = function (autoRefreshInterval) { var poll = function (autoRefreshInterval) {
// ensure we're suppose to poll // ensure we're suppose to poll
if (revisionPolling) { if (polling) {
// 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) {
// reload the status // reload the status
nf.Canvas.reloadStatus().done(function () { nf.Canvas.reload({
'transition': true
}).done(function () {
// start the wait to poll again // start the wait to poll again
setTimeout(function () { setTimeout(function () {
pollForStatus(autoRefreshInterval); poll(autoRefreshInterval);
}, autoRefreshInterval * 1000); }, autoRefreshInterval * 1000);
}); });
} }
@ -195,50 +167,50 @@ nf.Canvas = (function () {
/** /**
* Checks the current revision against this version of the flow. * Checks the current revision against this version of the flow.
*/ */
var checkRevision = function () { // var checkRevision = function () {
// get the revision // // get the revision
return $.ajax({ // return $.ajax({
type: 'GET', // type: 'GET',
url: config.urls.revision, // url: config.urls.revision,
dataType: 'json' // dataType: 'json'
}).done(function (response) { // }).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.revision)) { // if (nf.Common.isDefinedAndNotNull(response.revision)) {
var revision = response.revision; // var revision = response.revision;
var currentRevision = nf.Client.getRevision(); // var currentRevision = nf.Client.getRevision();
//
// if there is a newer revision, there are outstanding // // if there is a newer revision, there are outstanding
// changes that need to be updated // // changes that need to be updated
if (revision.version > currentRevision.version && revision.clientId !== currentRevision.clientId) { // if (revision.version > currentRevision.version && revision.clientId !== currentRevision.clientId) {
var refreshContainer = $('#refresh-required-container'); // var refreshContainer = $('#refresh-required-container');
var settingsRefreshIcon = $('#settings-refresh-required-icon'); // var settingsRefreshIcon = $('#settings-refresh-required-icon');
//
// insert the refresh needed text in the canvas - if necessary // // insert the refresh needed text in the canvas - if necessary
if (!refreshContainer.is(':visible')) { // if (!refreshContainer.is(':visible')) {
$('#stats-last-refreshed').addClass('alert'); // $('#stats-last-refreshed').addClass('alert');
var refreshMessage = "This flow has been modified by '" + revision.lastModifier + "'. Please refresh."; // var refreshMessage = "This flow has been modified by '" + revision.lastModifier + "'. Please refresh.";
//
// update the tooltip // // update the tooltip
var refreshRequiredIcon = $('#refresh-required-icon'); // var refreshRequiredIcon = $('#refresh-required-icon');
if (refreshRequiredIcon.data('qtip')) { // if (refreshRequiredIcon.data('qtip')) {
refreshRequiredIcon.qtip('option', 'content.text', refreshMessage); // refreshRequiredIcon.qtip('option', 'content.text', refreshMessage);
} else { // } else {
refreshRequiredIcon.qtip($.extend({ // refreshRequiredIcon.qtip($.extend({
content: refreshMessage // content: refreshMessage
}, nf.CanvasUtils.config.systemTooltipConfig)); // }, nf.CanvasUtils.config.systemTooltipConfig));
} // }
//
refreshContainer.show(); // refreshContainer.show();
} // }
//
// insert the refresh needed text in the settings - if necessary // // insert the refresh needed text in the settings - if necessary
if (!settingsRefreshIcon.is(':visible')) { // if (!settingsRefreshIcon.is(':visible')) {
$('#settings-last-refreshed').addClass('alert'); // $('#settings-last-refreshed').addClass('alert');
settingsRefreshIcon.show(); // settingsRefreshIcon.show();
} // }
} // }
} // }
}).fail(nf.Common.handleAjaxError); // }).fail(nf.Common.handleAjaxError);
}; // };
/** /**
* Initializes the canvas. * Initializes the canvas.
@ -555,7 +527,7 @@ nf.Canvas = (function () {
if (isCtrl) { if (isCtrl) {
if (evt.keyCode === 82) { if (evt.keyCode === 82) {
// ctrl-r // ctrl-r
nf.Actions.reloadStatus(); nf.Actions.reload();
// default prevented in nf-universal-capture.js // default prevented in nf-universal-capture.js
} else if (evt.keyCode === 65) { } else if (evt.keyCode === 65) {
@ -631,8 +603,9 @@ nf.Canvas = (function () {
* Refreshes the graph. * Refreshes the graph.
* *
* @argument {string} processGroupId The process group id * @argument {string} processGroupId The process group id
* @argument {object} options Configuration options
*/ */
var reloadProcessGroup = function (processGroupId) { var reloadProcessGroup = function (processGroupId, options) {
// load the controller // load the controller
return $.ajax({ return $.ajax({
type: 'GET', type: 'GET',
@ -642,9 +615,6 @@ nf.Canvas = (function () {
}, },
dataType: 'json' dataType: 'json'
}).done(function (flowResponse) { }).done(function (flowResponse) {
// set the revision
nf.Client.setRevision(flowResponse.revision);
// get the controller and its contents // get the controller and its contents
var processGroupFlow = flowResponse.processGroupFlow; var processGroupFlow = flowResponse.processGroupFlow;
@ -654,6 +624,10 @@ nf.Canvas = (function () {
// update the breadcrumbs // update the breadcrumbs
nf.ng.Bridge.get('appCtrl.serviceProvider.breadcrumbsCtrl').resetBreadcrumbs(); 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').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 // set the parent id if applicable
if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) { if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) {
@ -662,57 +636,22 @@ nf.Canvas = (function () {
nf.Canvas.setParentGroupId(null); nf.Canvas.setParentGroupId(null);
} }
// since we're getting a new group, we want to clear it
nf.Graph.removeAll();
// refresh the graph // 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 // inform Angular app values have changed
nf.ng.Bridge.digest(); nf.ng.Bridge.digest();
}).fail(nf.Common.handleAjaxError); }).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 { return {
CANVAS_OFFSET: 0, CANVAS_OFFSET: 0,
@ -728,62 +667,32 @@ nf.Canvas = (function () {
$('#splash').fadeOut(); $('#splash').fadeOut();
}, },
/**
* Stop polling for revision.
*/
stopRevisionPolling: function () {
// set polling flag
revisionPolling = false;
},
/** /**
* Remove the status poller. * Remove the status poller.
*/ */
stopStatusPolling: function () { stopPolling: function () {
// set polling flag // set polling flag
statusPolling = false; polling = false;
}, },
/** /**
* Reloads the flow from the server based on the currently specified group id. * 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) { return $.Deferred(function (deferred) {
// hide the context menu // hide the context menu
nf.ContextMenu.hide(); nf.ContextMenu.hide();
// get the process group to refresh everything // 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 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 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) { $.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); deferred.resolve(processGroupResult);
}).fail(function () { }).fail(function () {
deferred.reject(); 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();
}).fail(function () {
deferred.reject();
});
}).promise(); }).promise();
}, },
@ -863,6 +772,9 @@ nf.Canvas = (function () {
}); });
}).promise(); }).promise();
userXhr.done(function () { userXhr.done(function () {
// load the client id
var clientXhr = nf.Client.init();
// get the controller config to register the status poller // get the controller config to register the status poller
var configXhr = $.ajax({ var configXhr = $.ajax({
type: 'GET', type: 'GET',
@ -889,7 +801,7 @@ nf.Canvas = (function () {
}).promise(); }).promise();
// ensure the config requests are loaded // 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]; var configResponse = configResult[0];
// calculate the canvas offset // calculate the canvas offset
@ -953,10 +865,9 @@ nf.Canvas = (function () {
// determine the split between the polling // determine the split between the polling
var pollingSplit = autoRefreshIntervalSeconds / 2; var pollingSplit = autoRefreshIntervalSeconds / 2;
// register the revision and status polling // register the polling
startRevisionPolling(autoRefreshIntervalSeconds);
setTimeout(function () { setTimeout(function () {
startStatusPolling(autoRefreshIntervalSeconds); startPolling(autoRefreshIntervalSeconds);
}, pollingSplit * 1000); }, pollingSplit * 1000);
// hide the splash screen // hide the splash screen

View File

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

View File

@ -197,6 +197,7 @@ nf.Connectable = (function () {
activate: function (components) { activate: function (components) {
components components
.classed('connectable', true)
.on('mouseenter.connectable', function (d) { .on('mouseenter.connectable', function (d) {
if (allowConnection()) { if (allowConnection()) {
var selection = d3.select(this); var selection = d3.select(this);
@ -245,6 +246,15 @@ nf.Connectable = (function () {
// remove all hover related classes // remove all hover related classes
d3.select(this).classed('hover connectable-destination', false); 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()) { if (validateSettings()) {
var connectionEntity = { var connectionEntity = {
'revision': nf.Client.getRevision(),
'component': { 'component': {
'name': connectionName, 'name': connectionName,
'source': { 'source': {
@ -873,9 +872,6 @@ nf.ConnectionConfiguration = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// add the connection // add the connection
nf.Graph.add({ nf.Graph.add({
'connections': [response] 'connections': [response]
@ -926,8 +922,9 @@ nf.ConnectionConfiguration = (function () {
var prioritizers = $('#prioritizer-selected').sortable('toArray'); var prioritizers = $('#prioritizer-selected').sortable('toArray');
if (validateSettings()) { if (validateSettings()) {
var d = nf.Connection.get(connectionId);
var connectionEntity = { var connectionEntity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': connectionId, 'id': connectionId,
'name': connectionName, 'name': connectionName,
@ -953,9 +950,6 @@ nf.ConnectionConfiguration = (function () {
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.component)) { if (nf.Common.isDefinedAndNotNull(response.component)) {
// update the revision
nf.Client.setRevision(response.revision);
// update this connection // update this connection
nf.Connection.set(response); nf.Connection.set(response);

View File

@ -247,9 +247,6 @@ nf.Connection = (function () {
.attr({ .attr({
'class': 'connection-path', 'class': 'connection-path',
'pointer-events': 'none' 'pointer-events': 'none'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// path to show when selection // path to show when selection
@ -260,7 +257,7 @@ nf.Connection = (function () {
}); });
// path to make selection easier // path to make selection easier
var selectableConnection = connection.append('path') connection.append('path')
.attr({ .attr({
'class': 'connection-path-selectable', 'class': 'connection-path-selectable',
'pointer-events': 'stroke' 'pointer-events': 'stroke'
@ -270,11 +267,79 @@ nf.Connection = (function () {
nf.Selectable.select(d3.select(this.parentNode)); nf.Selectable.select(d3.select(this.parentNode));
}) })
.call(nf.ContextMenu.activate); .call(nf.ContextMenu.activate);
};
// only support adding bend points when appropriate // determines whether the specified connection contains an unsupported relationship
selectableConnection.filter(function (d) { var hasUnavailableRelationship = function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead; var unavailable = false;
}).on('dblclick', function (d) {
// verify each selected relationship is still available
if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && nf.Common.isDefinedAndNotNull(d.component.availableRelationships)) {
$.each(d.component.selectedRelationships, function (_, selectedRelationship) {
if ($.inArray(selectedRelationship, d.component.availableRelationships) === -1) {
unavailable = true;
return false;
}
});
}
return unavailable;
};
// updates the specified connections
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) {
var grouped = false;
if (d.accessPolicy.canRead) {
// if there are more than one selected relationship, mark this as grouped
if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && d.component.selectedRelationships.length > 1) {
grouped = true;
}
}
return grouped;
})
.classed('ghost', function (d) {
var ghost = false;
if (d.accessPolicy.canRead) {
// if the connection has a relationship that is unavailable, mark it a ghost relationship
if (hasUnavailableRelationship(d)) {
ghost = true;
}
}
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); var position = d3.mouse(this.parentNode);
// find where to put this bend point // find where to put this bend point
@ -309,62 +374,12 @@ nf.Connection = (function () {
save(d, connection); save(d, connection);
d3.event.stopPropagation(); d3.event.stopPropagation();
}); } else {
return null;
// 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
var hasUnavailableRelationship = function (d) {
var unavailable = false;
// verify each selected relationship is still available
if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && nf.Common.isDefinedAndNotNull(d.component.availableRelationships)) {
$.each(d.component.selectedRelationships, function (_, selectedRelationship) {
if ($.inArray(selectedRelationship, d.component.availableRelationships) === -1) {
unavailable = true;
return false;
} }
}); });
} }
return unavailable;
};
// updates the specified connections
var updateConnections = function (updated, updatePath, updateLabel) {
if (updated.empty()) {
return;
}
if (updatePath === true) {
updated.classed('grouped', function (d) {
var grouped = false;
if (d.accessPolicy.canRead) {
// if there are more than one selected relationship, mark this as grouped
if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && d.component.selectedRelationships.length > 1) {
grouped = true;
}
}
return grouped;
})
.classed('ghost', function (d) {
var ghost = false;
if (d.accessPolicy.canRead) {
// if the connection has a relationship that is unavailable, mark it a ghost relationship
if (hasUnavailableRelationship(d)) {
ghost = true;
}
}
return ghost;
});
}
updated.each(function (d) { updated.each(function (d) {
var connection = d3.select(this); var connection = d3.select(this);
@ -442,7 +457,7 @@ nf.Connection = (function () {
d.end = end; d.end = end;
// update the connection paths // update the connection paths
connection.select('path.connection-path') nf.CanvasUtils.transition(connection.select('path.connection-path'), transition)
.attr({ .attr({
'd': function () { 'd': function () {
var datum = [d.start].concat(d.bends, [d.end]); var datum = [d.start].concat(d.bends, [d.end]);
@ -463,14 +478,14 @@ nf.Connection = (function () {
return 'url(#' + marker + ')'; return 'url(#' + marker + ')';
} }
}); });
connection.select('path.connection-selection-path') nf.CanvasUtils.transition(connection.select('path.connection-selection-path'), transition)
.attr({ .attr({
'd': function () { 'd': function () {
var datum = [d.start].concat(d.bends, [d.end]); var datum = [d.start].concat(d.bends, [d.end]);
return lineGenerator(datum); return lineGenerator(datum);
} }
}); });
connection.select('path.connection-path-selectable') nf.CanvasUtils.transition(connection.select('path.connection-path-selectable'), transition)
.attr({ .attr({
'd': function () { 'd': function () {
var datum = [d.start].concat(d.bends, [d.end]); var datum = [d.start].concat(d.bends, [d.end]);
@ -482,13 +497,17 @@ nf.Connection = (function () {
// bends // bends
// ----- // -----
var startpoints = connection.selectAll('rect.startpoint');
var endpoints = connection.selectAll('rect.endpoint');
var midpoints = connection.selectAll('rect.midpoint');
if (d.accessPolicy.canWrite) { if (d.accessPolicy.canWrite) {
// ------------------ // ------------------
// bends - startpoint // bends - startpoint
// ------------------ // ------------------
var startpoints = connection.selectAll('rect.startpoint').data([d.start]); startpoints = startpoints.data([d.start]);
// create a point for the start // create a point for the start
startpoints.enter().append('rect') startpoints.enter().append('rect')
@ -505,7 +524,8 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate); .call(nf.ContextMenu.activate);
// update the start point // update the start point
startpoints.attr('transform', function (p) { nf.CanvasUtils.transition(startpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
}); });
@ -516,7 +536,7 @@ nf.Connection = (function () {
// bends - endpoint // bends - endpoint
// ---------------- // ----------------
var endpoints = connection.selectAll('rect.endpoint').data([d.end]); var endpoints = endpoints.data([d.end]);
// create a point for the end // create a point for the end
endpoints.enter().append('rect') endpoints.enter().append('rect')
@ -534,7 +554,8 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate); .call(nf.ContextMenu.activate);
// update the end point // update the end point
endpoints.attr('transform', function (p) { nf.CanvasUtils.transition(endpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
}); });
@ -545,7 +566,7 @@ nf.Connection = (function () {
// bends - midpoints // bends - midpoints
// ----------------- // -----------------
var midpoints = connection.selectAll('rect.midpoint').data(d.bends); var midpoints = midpoints.data(d.bends);
// create a point for the end // create a point for the end
midpoints.enter().append('rect') midpoints.enter().append('rect')
@ -560,9 +581,12 @@ nf.Connection = (function () {
// stop even propagation // stop even propagation
d3.event.stopPropagation(); 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 // if this is a self loop prevent removing the last two bends
var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d); var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(connectionData);
var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d); var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(connectionData);
if (sourceComponentId === destinationComponentId && d.component.bends.length <= 2) { if (sourceComponentId === destinationComponentId && d.component.bends.length <= 2) {
nf.Dialog.showOkDialog({ nf.Dialog.showOkDialog({
dialogContent: 'Looping connections must have at least two bend points.', dialogContent: 'Looping connections must have at least two bend points.',
@ -575,7 +599,7 @@ nf.Connection = (function () {
var bendIndex = -1; var bendIndex = -1;
// create a new array of bends without the selected one // 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) { if (p.x !== bend.x && p.y !== bend.y) {
newBends.push(bend); newBends.push(bend);
} else { } else {
@ -588,12 +612,12 @@ nf.Connection = (function () {
} }
var connection = { var connection = {
id: d.id, id: connectionData.id,
bends: newBends bends: newBends
}; };
// update the label index if necessary // update the label index if necessary
var labelIndex = d.component.labelIndex; var labelIndex = connectionData.component.labelIndex;
if (newBends.length <= 1) { if (newBends.length <= 1) {
connection.labelIndex = 0; connection.labelIndex = 0;
} else if (bendIndex <= labelIndex) { } else if (bendIndex <= labelIndex) {
@ -601,7 +625,7 @@ nf.Connection = (function () {
} }
// save the updated connection // save the updated connection
save(d, connection); save(connectionData, connection);
}) })
.on('mousedown.selection', function () { .on('mousedown.selection', function () {
// select the connection when clicking the label // select the connection when clicking the label
@ -610,12 +634,18 @@ nf.Connection = (function () {
.call(nf.ContextMenu.activate); .call(nf.ContextMenu.activate);
// update the midpoints // update the midpoints
midpoints.attr('transform', function (p) { nf.CanvasUtils.transition(midpoints, transition)
.attr('transform', function (p) {
return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')'; return 'translate(' + (p.x - 4) + ', ' + (p.y - 4) + ')';
}); });
// remove old items // remove old items
midpoints.exit().remove(); 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, 'x': 0,
'y': 0, 'y': 0,
'filter': 'url(#component-drop-shadow)' 'filter': 'url(#component-drop-shadow)'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// processor border // processor border
@ -660,9 +687,6 @@ nf.Connection = (function () {
'width': dimensions.width, 'width': dimensions.width,
'fill': 'transparent', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
} }
@ -1061,10 +1085,16 @@ nf.Connection = (function () {
connectionLabelContainer.select('rect.body') connectionLabelContainer.select('rect.body')
.attr('height', function () { .attr('height', function () {
return (rowHeight * labelCount); return (rowHeight * labelCount);
})
.classed('unauthorized', function () {
return d.accessPolicy.canRead === false;
}); });
connectionLabelContainer.select('rect.border') connectionLabelContainer.select('rect.border')
.attr('height', function () { .attr('height', function () {
return (rowHeight * labelCount); return (rowHeight * labelCount);
})
.classed('unauthorized', function () {
return d.accessPolicy.canRead === false;
}); });
// update the coloring of the backgrounds // update the coloring of the backgrounds
@ -1111,7 +1141,7 @@ nf.Connection = (function () {
} }
// update the position of the label if possible // 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 () { .attr('transform', function () {
var label = d3.select(this).select('rect.body'); var label = d3.select(this).select('rect.body');
var position = getLabelPosition(label); var position = getLabelPosition(label);
@ -1133,21 +1163,13 @@ nf.Connection = (function () {
// queued count value // queued count value
updated.select('text.queued tspan.count') updated.select('text.queued tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.queued, ' ');
return nf.Common.substringBeforeFirst(d.status.queued, ' ');
} else {
return '-';
}
}); });
// queued size value // queued size value
updated.select('text.queued tspan.size') updated.select('text.queued tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.queued, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.queued, ' ');
} else {
return ' (-)';
}
}); });
}; };
@ -1159,10 +1181,8 @@ nf.Connection = (function () {
* @param {type} connection * @param {type} connection
*/ */
var save = function (d, connection) { var save = function (d, connection) {
var revision = nf.Client.getRevision();
var entity = { var entity = {
'revision': revision, 'revision': nf.Client.getRevision(d),
'component': connection 'component': connection
}; };
@ -1173,9 +1193,6 @@ nf.Connection = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// request was successful, update the entry // request was successful, update the entry
nf.Connection.set(response); nf.Connection.set(response);
}).fail(function (xhr, status, error) { }).fail(function (xhr, status, error) {
@ -1238,7 +1255,10 @@ nf.Connection = (function () {
d.y = d3.event.y; d.y = d3.event.y;
// redraw this connection // redraw this connection
d3.select(this.parentNode).call(updateConnections, true, false); d3.select(this.parentNode).call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
}) })
.on('dragend', function () { .on('dragend', function () {
var connection = d3.select(this.parentNode); var connection = d3.select(this.parentNode);
@ -1270,7 +1290,10 @@ nf.Connection = (function () {
}); });
// refresh the connection // 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 // 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) { .on('dragend', function (d) {
// indicate that dragging as stopped // indicate that dragging as stopped
@ -1314,7 +1340,10 @@ nf.Connection = (function () {
// resets the connection if we're not over a new destination // resets the connection if we're not over a new destination
if (destination.empty()) { if (destination.empty()) {
connection.call(updateConnections, true, false); connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
} else { } else {
// prompt for the new port if appropriate // prompt for the new port if appropriate
if (nf.CanvasUtils.isProcessGroup(destination) || nf.CanvasUtils.isRemoteProcessGroup(destination)) { if (nf.CanvasUtils.isProcessGroup(destination) || nf.CanvasUtils.isRemoteProcessGroup(destination)) {
@ -1324,7 +1353,10 @@ nf.Connection = (function () {
nf.CanvasUtils.reloadConnectionSourceAndDestination(null, previousDestinationId); nf.CanvasUtils.reloadConnectionSourceAndDestination(null, previousDestinationId);
}).fail(function () { }).fail(function () {
// reset the connection // reset the connection
connection.call(updateConnections, true, false); connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
}); });
} else { } else {
// get the destination details // get the destination details
@ -1332,7 +1364,7 @@ nf.Connection = (function () {
var destinationType = nf.CanvasUtils.getConnectableTypeForDestination(destination); var destinationType = nf.CanvasUtils.getConnectableTypeForDestination(destination);
var connectionEntity = { var connectionEntity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(connectionData),
'component': { 'component': {
'id': connectionData.id, 'id': connectionData.id,
'destination': { 'destination': {
@ -1372,9 +1404,6 @@ nf.Connection = (function () {
}).done(function (response) { }).done(function (response) {
var updatedConnectionData = response.component; var updatedConnectionData = response.component;
// update the revision
nf.Client.setRevision(response.revision);
// refresh to update the label // refresh to update the label
nf.Connection.set(response); nf.Connection.set(response);
@ -1389,7 +1418,10 @@ nf.Connection = (function () {
}); });
// reset the connection // reset the connection
connection.call(updateConnections, true, false); connection.call(updateConnections, {
'updatePath': true,
'updateLabel': false
});
} else { } else {
nf.Common.handleAjaxError(xhr, status, error); nf.Common.handleAjaxError(xhr, status, error);
} }
@ -1480,7 +1512,10 @@ nf.Connection = (function () {
d.labelIndex = closestBendIndex; d.labelIndex = closestBendIndex;
// refresh the connection // 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) { .on('dragend', function (d) {
@ -1508,7 +1543,10 @@ nf.Connection = (function () {
d.labelIndex = d.component.labelIndex; d.labelIndex = d.component.labelIndex;
// refresh the connection // 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 * @param connectionEntities The connection
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (connectionEntities, selectAll) { add: function (connectionEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (connectionEntity) { var add = function (connectionEntity) {
// add the connection // add the connection
connectionMap.set(connectionEntity.id, $.extend({ connectionMap.set(connectionEntity.id, $.extend({
type: 'Connection', type: 'Connection'
}, connectionEntity)); }, connectionEntity));
}; };
@ -1539,12 +1580,61 @@ nf.Connection = (function () {
$.each(connectionEntities, function (_, connectionEntity) { $.each(connectionEntities, function (_, connectionEntity) {
add(connectionEntity); add(connectionEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(connectionEntities)) {
add(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 // 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); 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. * Sets the connection status using the specified status.
* *
@ -1610,9 +1673,15 @@ nf.Connection = (function () {
*/ */
refresh: function (connectionId) { refresh: function (connectionId) {
if (nf.Common.isDefinedAndNotNull(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 { } 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. * Refreshes the components necessary after a pan event.
*/ */
pan: function () { 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 // defines the available actions and the conditions which they apply
var actions = [ 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: isNotRootGroup, menuItem: {img: 'images/iconGoTo.png', text: 'Leave group', action: 'leaveGroup'}},
{condition: isConfigurable, menuItem: {img: 'images/iconConfigure.png', text: 'Configure', action: 'showConfiguration'}}, {condition: isConfigurable, menuItem: {img: 'images/iconConfigure.png', text: 'Configure', action: 'showConfiguration'}},
{condition: hasDetails, menuItem: {img: 'images/iconConfigure.png', text: 'View configuration', action: 'showDetails'}}, {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) { var reloadControllerServiceReferences = function (controllerService) {
// reload all dependent processors if they are currently visible // 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') { if (reference.referenceType === 'Processor') {
// reload the processor on the canvas if appropriate // reload the processor on the canvas if appropriate
if (nf.Canvas.getGroupId() === reference.groupId) { if (nf.Canvas.getGroupId() === reference.groupId) {
@ -381,7 +382,8 @@ nf.ControllerService = (function () {
var processors = $('<ul class="referencing-component-listing clear"></ul>'); var processors = $('<ul class="referencing-component-listing clear"></ul>');
var services = $('<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>'); 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); referencingComponentIds.push(referencingComponent.id);
if (referencingComponent.referenceType === 'Processor') { if (referencingComponent.referenceType === 'Processor') {
@ -580,7 +582,8 @@ nf.ControllerService = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
nf.Client.setRevision(response.revision); // TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
// wait until the polling of each service finished // wait until the polling of each service finished
@ -627,7 +630,8 @@ nf.ControllerService = (function () {
ids.add(controllerService.id); ids.add(controllerService.id);
var checkReferencingServices = function (referencingComponents) { var checkReferencingServices = function (referencingComponents) {
$.each(referencingComponents, function (_, referencingComponent) { $.each(referencingComponents, function (_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') { if (referencingComponent.referenceType === 'ControllerService') {
// add the id // add the id
ids.add(referencingComponent.id); ids.add(referencingComponent.id);
@ -668,7 +672,8 @@ nf.ControllerService = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
nf.Client.setRevision(response.revision); // TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
// wait unil the polling of each service finished // wait unil the polling of each service finished
@ -785,7 +790,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
var stillRunning = false; var stillRunning = false;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') { if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') {
if (referencingComponent.state === 'RUNNING' || referencingComponent.activeThreadCount > 0) { if (referencingComponent.state === 'RUNNING' || referencingComponent.activeThreadCount > 0) {
stillRunning = true; stillRunning = true;
@ -809,7 +815,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = []; var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') { if (referencingComponent.referenceType === 'Processor' || referencingComponent.referenceType === 'ReportingTask') {
referencingSchedulableComponents.push(referencingComponent.id); referencingSchedulableComponents.push(referencingComponent.id);
} }
@ -831,7 +838,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
var notEnabled = false; var notEnabled = false;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') { if (referencingComponent.referenceType === 'ControllerService') {
if (referencingComponent.state !== 'ENABLING' && referencingComponent.state !== 'ENABLED') { if (referencingComponent.state !== 'ENABLING' && referencingComponent.state !== 'ENABLED') {
notEnabled = true; notEnabled = true;
@ -852,7 +860,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = []; var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') { if (referencingComponent.referenceType === 'ControllerService') {
referencingSchedulableComponents.push(referencingComponent.id); referencingSchedulableComponents.push(referencingComponent.id);
} }
@ -874,7 +883,8 @@ nf.ControllerService = (function () {
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
var notDisabled = false; var notDisabled = false;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') { if (referencingComponent.referenceType === 'ControllerService') {
if (referencingComponent.state !== 'DISABLED') { if (referencingComponent.state !== 'DISABLED') {
notDisabled = true; notDisabled = true;
@ -895,7 +905,8 @@ nf.ControllerService = (function () {
var referencingSchedulableComponents = []; var referencingSchedulableComponents = [];
var referencingComponents = service.referencingComponents; var referencingComponents = service.referencingComponents;
$.each(referencingComponents, function(_, referencingComponent) { $.each(referencingComponents, function(_, referencingComponentEntity) {
var referencingComponent = referencingComponentEntity.controllerServiceReferencingComponent;
if (referencingComponent.referenceType === 'ControllerService') { if (referencingComponent.referenceType === 'ControllerService') {
referencingSchedulableComponents.push(referencingComponent.id); referencingSchedulableComponents.push(referencingComponent.id);
} }
@ -928,7 +939,8 @@ nf.ControllerService = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
nf.Client.setRevision(response.revision); // TODO
// nf.Client.setRevision(response.revision);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);
// wait unil the polling of each service finished // wait unil the polling of each service finished
@ -1311,8 +1323,8 @@ nf.ControllerService = (function () {
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
if (nf.Common.isDefinedAndNotNull(response.controllerService)) { if (nf.Common.isDefinedAndNotNull(response.controllerService)) {
// update the revision // TODO - update the revision
nf.Client.setRevision(response.revision); // nf.Client.setRevision(response.revision);
// reload all previously referenced controller services // reload all previously referenced controller services
$.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) { $.each(previouslyReferencedServiceIds, function(_, oldServiceReferenceId) {
@ -1436,6 +1448,7 @@ nf.ControllerService = (function () {
// initialize the property table // initialize the property table
$('#controller-service-properties').propertytable({ $('#controller-service-properties').propertytable({
readOnly: false, readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-controller-service-property-container', dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor, descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty goToServiceDeferred: goToServiceFromProperty
@ -1583,6 +1596,7 @@ nf.ControllerService = (function () {
// initialize the property table // initialize the property table
$('#controller-service-properties').propertytable('destroy').propertytable({ $('#controller-service-properties').propertytable('destroy').propertytable({
readOnly: false, readOnly: false,
groupId: nf.Canvas.getGroupId(),
dialogContainer: '#new-controller-service-property-container', dialogContainer: '#new-controller-service-property-container',
descriptorDeferred: getControllerServicePropertyDescriptor, descriptorDeferred: getControllerServicePropertyDescriptor,
goToServiceDeferred: goToServiceFromProperty goToServiceDeferred: goToServiceFromProperty
@ -1888,7 +1902,8 @@ nf.ControllerService = (function () {
}), }),
dataType: 'json' dataType: 'json'
}).done(function (response) { }).done(function (response) {
nf.Client.setRevision(response.revision); // TODO
// nf.Client.setRevision(response.revision);
// remove the service // remove the service
var controllerServiceGrid = $('#controller-services-table').data('gridInstance'); var controllerServiceGrid = $('#controller-services-table').data('gridInstance');

View File

@ -49,7 +49,7 @@ nf.Draggable = (function () {
// build the entity // build the entity
var entity = { var entity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(d),
'component': { 'component': {
'id': d.id, 'id': d.id,
'position': newPosition 'position': newPosition
@ -65,9 +65,6 @@ nf.Draggable = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// update the component // update the component
nf[d.type].set(response); nf[d.type].set(response);
@ -106,7 +103,7 @@ nf.Draggable = (function () {
}); });
var entity = { var entity = {
'revision': revision, 'revision': nf.Client.getRevision(d),
'component': { 'component': {
id: d.id, id: d.id,
bends: newBends bends: newBends
@ -122,9 +119,6 @@ nf.Draggable = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// update the component // update the component
nf.Connection.set(response); nf.Connection.set(response);
@ -189,9 +183,6 @@ nf.Draggable = (function () {
$.each(componentConnections, function (_, connection) { $.each(componentConnections, function (_, connection) {
connections.add(connection.id); connections.add(connection.id);
}); });
// refresh the component
nf[component.type].position(component.id);
} }
}); });
@ -315,6 +306,15 @@ nf.Draggable = (function () {
*/ */
activate: function (components) { activate: function (components) {
components.classed('moveable', true).call(drag); 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', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
}).classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// funnel body // funnel body
@ -102,9 +100,6 @@ nf.Funnel = (function () {
}, },
'filter': 'url(#component-drop-shadow)', 'filter': 'url(#component-drop-shadow)',
'stroke-width': 0 'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// funnel icon // funnel icon
@ -118,13 +113,6 @@ nf.Funnel = (function () {
// always support selection // always support selection
funnel.call(nf.Selectable.activate).call(nf.ContextMenu.activate); 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 * @param {selection} updated The funnels to be updated
*/ */
var updateFunnels = function (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 * @param funnelEntities The funnel
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (funnelEntities, selectAll) { add: function (funnelEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (funnelEntity) { var add = function (funnelEntity) {
// add the funnel // add the funnel
@ -181,12 +194,55 @@ nf.Funnel = (function () {
$.each(funnelEntities, function (_, funnelEntity) { $.each(funnelEntities, function (_, funnelEntity) {
add(funnelEntity); add(funnelEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(funnelEntities)) {
add(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 // 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); 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. * Removes the specified funnel.
* *

View File

@ -65,8 +65,11 @@ nf.Graph = (function () {
* @argument {object} processGroupContents The contents of the process group * @argument {object} processGroupContents The contents of the process group
* @argument {boolean} selectAll Whether or not to select the new contents * @argument {boolean} selectAll Whether or not to select the new contents
*/ */
add: function (processGroupContents, selectAll) { add: function (processGroupContents, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; 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 we are going to select the new components, deselect the previous selection
if (selectAll) { if (selectAll) {
@ -77,28 +80,49 @@ nf.Graph = (function () {
var ports = combinePorts(processGroupContents); var ports = combinePorts(processGroupContents);
// add the components to the responsible object // add the components to the responsible object
if (!nf.Common.isEmpty(processGroupContents.labels)) { nf.Label.add(processGroupContents.labels, options);
nf.Label.add(processGroupContents.labels, selectAll); 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 we are going to select the new components, deselect the previous selection
} if (selectAll) {
if (!nf.Common.isEmpty(ports)) { nf.CanvasUtils.getSelection().classed('selected', false);
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);
} }
// 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 // inform Angular app if the selection is changing
if (selectAll) { if (selectAll) {
nf.ng.Bridge.digest(); 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 * 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. * 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 // build the label entity
var labelEntity = { var labelEntity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(labelData),
'component': { 'component': {
'id': labelId, 'id': labelId,
'label': labelValue, 'label': labelValue,
@ -60,9 +60,6 @@ nf.LabelConfiguration = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// get the label out of the response // get the label out of the response
nf.Label.set(response); nf.Label.set(response);
}).fail(nf.Common.handleAjaxError); }).fail(nf.Common.handleAjaxError);

View File

@ -84,16 +84,14 @@ nf.Label = (function () {
.attr({ .attr({
'class': 'border', 'class': 'border',
'fill': 'transparent', 'fill': 'transparent',
'stroke-opacity': 0.8, 'stroke': 'transparent'
'stroke-width': 1
}); });
// label // label
label.append('rect') label.append('rect')
.attr({ .attr({
'class': 'body', 'class': 'body',
'fill-opacity': 0.8, 'filter': 'url(#component-drop-shadow)',
'stroke-opacity': 0.8,
'stroke-width': 0 'stroke-width': 0
}); });
@ -108,14 +106,6 @@ nf.Label = (function () {
// always support selecting // always support selecting
label.call(nf.Selectable.activate).call(nf.ContextMenu.activate); 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);
}; };
/** /**
@ -131,59 +121,58 @@ nf.Label = (function () {
// update the border using the configured color // update the border using the configured color
updated.select('rect.border') updated.select('rect.border')
.attr({ .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) { 'width': function (d) {
return d.dimensions.width; return d.dimensions.width;
}, },
'height': function (d) { 'height': function (d) {
return d.dimensions.height; return d.dimensions.height;
} }
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// update the body fill using the configured color // update the body fill using the configured color
updated.select('rect.body') updated.select('rect.body')
.attr({ .attr({
'fill': 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) { 'width': function (d) {
return d.dimensions.width; return d.dimensions.width;
}, },
'height': function (d) { 'height': function (d) {
return d.dimensions.height; return d.dimensions.height;
} }
})
.style('fill', function (d) {
if (!d.accessPolicy.canRead) {
return null;
}
var color = nf.Label.defaultColor();
// 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 // go through each label being updated
updated.each(function (d) { updated.each(function (d) {
var updatedLabel = d3.select(this); var label = d3.select(this);
// update the component behavior as appropriate
nf.CanvasUtils.editable(label);
if (d.accessPolicy.canRead) {
// update the label // update the label
var label = updatedLabel.select('text.label-value'); var labelText = label.select('text.label-value');
var labelPoint = label.selectAll('rect.labelpoint');
if (d.accessPolicy.canRead) {
// udpate the font size // udpate the font size
label.attr('font-size', function () { labelText.attr('font-size', function () {
var fontSize = '12px'; var fontSize = '12px';
// use the specified color if appropriate // use the specified color if appropriate
@ -195,7 +184,7 @@ nf.Label = (function () {
}); });
// remove the previous label value // remove the previous label value
label.selectAll('tspan').remove(); labelText.selectAll('tspan').remove();
// parse the lines in this label // parse the lines in this label
var lines = []; var lines = [];
@ -207,7 +196,7 @@ nf.Label = (function () {
// add label value // add label value
$.each(lines, function (i, line) { $.each(lines, function (i, line) {
label.append('tspan') labelText.append('tspan')
.attr('x', '0.4em') .attr('x', '0.4em')
.attr('dy', '1.2em') .attr('dy', '1.2em')
.text(function () { .text(function () {
@ -224,7 +213,7 @@ nf.Label = (function () {
var pointData = [ var pointData = [
{x: d.dimensions.width, y: d.dimensions.height} {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 // create a point for the end
points.enter().append('rect') points.enter().append('rect')
@ -243,6 +232,12 @@ nf.Label = (function () {
// remove old items // remove old items
points.exit().remove(); points.exit().remove();
} }
} else {
// remove the previous label value
labelText.selectAll('tspan').remove();
// remove the label points
labelPoint.remove()
} }
}); });
}; };
@ -310,7 +305,7 @@ nf.Label = (function () {
// only save the updated bends if necessary // only save the updated bends if necessary
if (different) { if (different) {
var labelEntity = { var labelEntity = {
'revision': nf.Client.getRevision(), 'revision': nf.Client.getRevision(labelData),
'component': { 'component': {
'id': labelData.id, 'id': labelData.id,
'width': labelData.dimensions.width, 'width': labelData.dimensions.width,
@ -325,9 +320,6 @@ nf.Label = (function () {
dataType: 'json', dataType: 'json',
contentType: 'application/json' contentType: 'application/json'
}).done(function (response) { }).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// request was successful, update the entry // request was successful, update the entry
nf.Label.set(response); nf.Label.set(response);
}).fail(function () { }).fail(function () {
@ -360,13 +352,16 @@ nf.Label = (function () {
}, },
/** /**
* Populates the graph with the specified labels. * Adds the specified label entity.
* *
* @argument {object | array} labelEntities The labels to add * @param labelEntities The label
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (labelEntities, selectAll) { add: function (labelEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (labelEntity) { var add = function (labelEntity) {
// add the label // add the label
@ -380,12 +375,54 @@ nf.Label = (function () {
$.each(labelEntities, function (_, labelEntity) { $.each(labelEntities, function (_, labelEntity) {
add(labelEntity); add(labelEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(labelEntities)) {
add(labelEntities); add(labelEntities);
} }
// 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 // apply the selection and handle all new labels
select().enter().call(renderLabels, selectAll); var selection = select();
selection.enter().call(renderLabels, selectAll);
selection.call(updateLabels).call(nf.CanvasUtils.position, transition);
selection.exit().call(removeLabels);
}, },
/** /**
@ -443,35 +480,6 @@ nf.Label = (function () {
d3.select('#id-' + id).call(nf.CanvasUtils.position); 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. * Removes the specified label.
* *

View File

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

View File

@ -95,9 +95,6 @@ nf.Port = (function () {
}, },
'fill': 'transparent', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// port body // port body
@ -112,9 +109,6 @@ nf.Port = (function () {
}, },
'filter': 'url(#component-drop-shadow)', 'filter': 'url(#component-drop-shadow)',
'stroke-width': 0 'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
var offset = 0; var offset = 0;
@ -167,9 +161,6 @@ nf.Port = (function () {
port.filter(function (d) { port.filter(function (d) {
return d.accessPolicy.canWrite && d.accessPolicy.canRead; return d.accessPolicy.canWrite && d.accessPolicy.canRead;
}).call(nf.Draggable.activate).call(nf.Connectable.activate); }).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; 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) { updated.each(function (portData) {
var port = d3.select(this); var port = d3.select(this);
var details = port.select('g.port-details'); 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 this process group is visible, render everything
if (port.classed('visible')) { if (port.classed('visible')) {
if (details.empty()) { if (details.empty()) {
@ -277,6 +283,9 @@ nf.Port = (function () {
}).append('title').text(function (d) { }).append('title').text(function (d) {
return d.component.name; return d.component.name;
}); });
} else {
// clear the port name
port.select('text.port-name').text(null);
} }
// populate the stats // populate the stats
@ -321,14 +330,14 @@ nf.Port = (function () {
.attr({ .attr({
'fill': function (d) { 'fill': function (d) {
var fill = '#728e9b'; var fill = '#728e9b';
if (d.status.runStatus === 'Invalid') { if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
fill = '#ba554a'; fill = '#ba554a';
} }
return fill; return fill;
}, },
'font-family': function (d) { 'font-family': function (d) {
var family = 'FontAwesome'; var family = 'FontAwesome';
if (d.status.runStatus === 'Disabled') { if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
family = 'flowfont'; family = 'flowfont';
} }
return family; return family;
@ -336,13 +345,13 @@ nf.Port = (function () {
}) })
.text(function (d) { .text(function (d) {
var img = ''; var img = '';
if (d.status.runStatus === 'Disabled') { if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
img = '\ue802'; img = '\ue802';
} else if (d.status.runStatus === 'Invalid') { } else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
img = '\uf071'; img = '\uf071';
} else if (d.status.runStatus === 'Running') { } else if (d.status.aggregateSnapshot.runStatus === 'Running') {
img = '\uf04b'; img = '\uf04b';
} else if (d.status.runStatus === 'Stopped') { } else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
img = '\uf04d'; img = '\uf04d';
} }
return img; return img;
@ -378,7 +387,7 @@ nf.Port = (function () {
updated.select('text.port-transmission-icon') updated.select('text.port-transmission-icon')
.attr({ .attr({
'font-family': function (d) { 'font-family': function (d) {
if (d.status.transmitting === true) { if (d.status.aggregateSnapshot.transmitting === true) {
return 'FontAwesome'; return 'FontAwesome';
} else { } else {
return 'flowfont'; return 'flowfont';
@ -386,7 +395,7 @@ nf.Port = (function () {
} }
}) })
.text(function (d) { .text(function (d) {
if (d.status.transmitting === true) { if (d.status.aggregateSnapshot.transmitting === true) {
return '\uf140'; return '\uf140';
} else { } else {
return '\ue80a'; return '\ue80a';
@ -410,7 +419,7 @@ nf.Port = (function () {
// --------- // ---------
port.select('rect.bulletin-background').classed('has-bulletins', 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 () { 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 * @param portEntities The port
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (portEntities, selectAll) { add: function (portEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
// determine the appropriate dimensions for this port // determine the appropriate dimensions for this port
var dimensions = portDimensions; var dimensions = portDimensions;
@ -491,12 +503,64 @@ nf.Port = (function () {
$.each(portEntities, function (_, portNode) { $.each(portEntities, function (_, portNode) {
add(portNode); add(portNode);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(portEntities)) {
add(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 // 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); 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. * Sets the port status using the specified status.
* *

View File

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

View File

@ -101,9 +101,6 @@ nf.ProcessGroup = (function () {
}, },
'fill': 'transparent', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// process group body // process group body
@ -118,9 +115,6 @@ nf.ProcessGroup = (function () {
}, },
'filter': 'url(#component-drop-shadow)', 'filter': 'url(#component-drop-shadow)',
'stroke-width': 0 'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// process group name background // process group name background
@ -198,9 +192,6 @@ nf.ProcessGroup = (function () {
}) })
.call(nf.Draggable.activate) .call(nf.Draggable.activate)
.call(nf.Connectable.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 // attempt of space between component count and icon for process group contents
@ -216,10 +207,25 @@ nf.ProcessGroup = (function () {
return; 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) { updated.each(function (processGroupData) {
var processGroup = d3.select(this); var processGroup = d3.select(this);
var details = processGroup.select('g.process-group-details'); 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 this processor is visible, render everything
if (processGroup.classed('visible')) { if (processGroup.classed('visible')) {
if (details.empty()) { if (details.empty()) {
@ -244,8 +250,6 @@ nf.ProcessGroup = (function () {
// contents // contents
// -------- // --------
if (processGroupData.accessPolicy.canRead) {
// transmitting icon // transmitting icon
details.append('text') details.append('text')
.attr({ .attr({
@ -343,7 +347,6 @@ nf.ProcessGroup = (function () {
'y': 49, 'y': 49,
'class': 'process-group-disabled-count process-group-contents-count' 'class': 'process-group-disabled-count process-group-contents-count'
}); });
}
// ---------------- // ----------------
// stats background // stats background
@ -537,6 +540,12 @@ nf.ProcessGroup = (function () {
'class': 'size' 'class': 'size'
}); });
// in
inText.append('tspan')
.attr({
'class': 'ports'
});
// read/write value // read/write value
processGroupStatsValue.append('text') processGroupStatsValue.append('text')
.attr({ .attr({
@ -557,13 +566,19 @@ nf.ProcessGroup = (function () {
'class': 'process-group-out stats-value' 'class': 'process-group-out stats-value'
}); });
// in count // out ports
outText.append('tspan')
.attr({
'class': 'ports'
});
// out count
outText.append('tspan') outText.append('tspan')
.attr({ .attr({
'class': 'count' 'class': 'count'
}); });
// in size // out size
outText.append('tspan') outText.append('tspan')
.attr({ .attr({
'class': 'size' 'class': 'size'
@ -669,12 +684,10 @@ nf.ProcessGroup = (function () {
.text('\uf24a'); .text('\uf24a');
} }
if (processGroupData.accessPolicy.canRead) {
// update transmitting // update transmitting
var transmittingCount = details.select('text.process-group-transmitting-count') var transmittingCount = details.select('text.process-group-transmitting-count')
.text(function (d) { .text(function (d) {
return d.component.activeRemotePortCount; return d.activeRemotePortCount;
}); });
// update not transmitting // update not transmitting
@ -689,7 +702,7 @@ nf.ProcessGroup = (function () {
return notTransmittingCountX + notTransmitting.node().getComputedTextLength() + CONTENTS_SPACER; return notTransmittingCountX + notTransmitting.node().getComputedTextLength() + CONTENTS_SPACER;
}) })
.text(function (d) { .text(function (d) {
return d.component.inactiveRemotePortCount; return d.inactiveRemotePortCount;
}); });
// update running // update running
@ -704,7 +717,7 @@ nf.ProcessGroup = (function () {
return runningCountX + running.node().getComputedTextLength() + CONTENTS_SPACER; return runningCountX + running.node().getComputedTextLength() + CONTENTS_SPACER;
}) })
.text(function (d) { .text(function (d) {
return d.component.runningCount; return d.runningCount;
}); });
// update stopped // update stopped
@ -719,7 +732,7 @@ nf.ProcessGroup = (function () {
return stoppedCountX + stopped.node().getComputedTextLength() + CONTENTS_SPACER; return stoppedCountX + stopped.node().getComputedTextLength() + CONTENTS_SPACER;
}) })
.text(function (d) { .text(function (d) {
return d.component.stoppedCount; return d.stoppedCount;
}); });
// update invalid // update invalid
@ -737,7 +750,7 @@ nf.ProcessGroup = (function () {
return invalidCountX + invalid.node().getComputedTextLength() + CONTENTS_SPACER; return invalidCountX + invalid.node().getComputedTextLength() + CONTENTS_SPACER;
}) })
.text(function (d) { .text(function (d) {
return d.component.invalidCount; return d.invalidCount;
}); });
// update disabled // update disabled
@ -752,9 +765,10 @@ nf.ProcessGroup = (function () {
return disabledCountX + disabled.node().getComputedTextLength() + CONTENTS_SPACER; return disabledCountX + disabled.node().getComputedTextLength() + CONTENTS_SPACER;
}) })
.text(function (d) { .text(function (d) {
return d.component.disabledCount; return d.disabledCount;
}); });
if (processGroupData.accessPolicy.canRead) {
// update the process group comments // update the process group comments
details.select('text.process-group-comments') details.select('text.process-group-comments')
.each(function (d) { .each(function (d) {
@ -784,6 +798,12 @@ nf.ProcessGroup = (function () {
}).append('title').text(function (d) { }).append('title').text(function (d) {
return d.component.name; 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 // hide the preview
@ -832,71 +852,55 @@ nf.ProcessGroup = (function () {
// queued count value // queued count value
updated.select('text.process-group-queued tspan.count') updated.select('text.process-group-queued tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.queued, ' ');
return nf.Common.substringBeforeFirst(d.status.queued, ' ');
} else {
return '-';
}
}); });
// queued size value // queued size value
updated.select('text.process-group-queued tspan.size') updated.select('text.process-group-queued tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.queued, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.queued, ' ');
} else {
return ' (-)';
}
}); });
// in count value // in count value
updated.select('text.process-group-in tspan.count') updated.select('text.process-group-in tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
return nf.Common.substringBeforeFirst(d.status.input, ' ');
} else {
return '-';
}
}); });
// in size value // in size value
updated.select('text.process-group-in tspan.size') updated.select('text.process-group-in tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.input, ' '); });
} else {
return ' (-)'; // in ports value
} updated.select('text.process-group-in tspan.ports')
.text(function (d) {
return ' ' + String.fromCharCode(8594) + ' ' + d.inputPortCount;
}); });
// read/write value // read/write value
updated.select('text.process-group-read-write') updated.select('text.process-group-read-write')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
return d.status.read + ' / ' + d.status.written; });
} else {
return '- / -'; // out ports value
} updated.select('text.process-group-out tspan.ports')
.text(function (d) {
return d.outputPortCount + ' ' + String.fromCharCode(8594) + ' ';
}); });
// out count value // out count value
updated.select('text.process-group-out tspan.count') updated.select('text.process-group-out tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
return nf.Common.substringBeforeFirst(d.status.output, ' ');
} else {
return '-';
}
}); });
// out size value // out size value
updated.select('text.process-group-out tspan.size') updated.select('text.process-group-out tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.output, ' ');
} else {
return ' (-)';
}
}); });
updated.each(function (d) { updated.each(function (d) {
@ -916,7 +920,7 @@ nf.ProcessGroup = (function () {
// --------- // ---------
processGroup.select('rect.bulletin-background').classed('has-bulletins', 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 () { 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 * @param processGroupEntities The process group
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (processGroupEntities, selectAll) { add: function (processGroupEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (processGroupEntity) { var add = function (processGroupEntity) {
// add the process group // add the process group
@ -987,12 +994,55 @@ nf.ProcessGroup = (function () {
$.each(processGroupEntities, function (_, processGroupEntity) { $.each(processGroupEntities, function (_, processGroupEntity) {
add(processGroupEntity); add(processGroupEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(processGroupEntities)) {
add(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 // 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); 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. * Sets the process group status using the specified status.
* *

View File

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

View File

@ -80,9 +80,6 @@ nf.Processor = (function () {
}, },
'fill': 'transparent', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// processor body // processor body
@ -97,9 +94,6 @@ nf.Processor = (function () {
}, },
'filter': 'url(#component-drop-shadow)', 'filter': 'url(#component-drop-shadow)',
'stroke-width': 0 'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// processor name // processor name
@ -134,14 +128,6 @@ nf.Processor = (function () {
// make processors selectable // make processors selectable
processor.call(nf.Selectable.activate).call(nf.ContextMenu.activate); 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; 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) { updated.each(function (processorData) {
var processor = d3.select(this); var processor = d3.select(this);
var details = processor.select('g.processor-canvas-details'); 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 this processor is visible, render everything
if (processor.classed('visible')) { if (processor.classed('visible')) {
if (details.empty()) { if (details.empty()) {
@ -171,7 +172,6 @@ nf.Processor = (function () {
'y': 20 'y': 20
}); });
if (processorData.accessPolicy.canRead) {
// processor type // processor type
details.append('text') details.append('text')
.attr({ .attr({
@ -180,19 +180,7 @@ nf.Processor = (function () {
'y': 35, 'y': 35,
'width': 246, 'width': 246,
'height': 16 '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, '.');
}); });
}
// ----- // -----
// stats // stats
@ -500,6 +488,26 @@ nf.Processor = (function () {
}).append('title').text(function (d) { }).append('title').text(function (d) {
return d.component.name; 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 // hide the preview
@ -541,14 +549,17 @@ nf.Processor = (function () {
// update the processor color // update the processor color
updated.select('rect.body') updated.select('rect.body')
.style('fill', function (d) { .style('fill', function (d) {
if (!d.accessPolicy.canRead) {
return null;
}
// get the default color
var color = nf.Processor.defaultColor(); var color = nf.Processor.defaultColor();
if (d.accessPolicy.canRead) {
// use the specified color if appropriate // use the specified color if appropriate
if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) { if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
color = d.component.style['background-color']; color = d.component.style['background-color'];
} }
}
return color; return color;
}); });
@ -569,14 +580,14 @@ nf.Processor = (function () {
.attr({ .attr({
'fill': function (d) { 'fill': function (d) {
var fill = '#728e9b'; var fill = '#728e9b';
if (d.status && d.status.runStatus === 'Invalid') { if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
fill = '#ba554a'; fill = '#ba554a';
} }
return fill; return fill;
}, },
'font-family': function (d) { 'font-family': function (d) {
var family = 'FontAwesome'; var family = 'FontAwesome';
if (d.status && d.status.runStatus === 'Disabled') { if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
family = 'flowfont'; family = 'flowfont';
} }
return family; return family;
@ -584,13 +595,13 @@ nf.Processor = (function () {
}) })
.text(function (d) { .text(function (d) {
var img = ''; var img = '';
if (d.status && d.status.runStatus === 'Disabled') { if (d.status.aggregateSnapshot.runStatus === 'Disabled') {
img = '\ue802'; img = '\ue802';
} else if (d.status && d.status.runStatus === 'Invalid') { } else if (d.status.aggregateSnapshot.runStatus === 'Invalid') {
img = '\uf071'; img = '\uf071';
} else if (d.status && d.status.runStatus === 'Running') { } else if (d.status.aggregateSnapshot.runStatus === 'Running') {
img = '\uf04b'; img = '\uf04b';
} else if (d.status && d.status.runStatus === 'Stopped') { } else if (d.status.aggregateSnapshot.runStatus === 'Stopped') {
img = '\uf04d'; img = '\uf04d';
} }
return img; return img;
@ -626,61 +637,37 @@ nf.Processor = (function () {
// in count value // in count value
updated.select('text.processor-in tspan.count') updated.select('text.processor-in tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.input, ' ');
return nf.Common.substringBeforeFirst(d.status.input, ' ');
} else {
return '-';
}
}); });
// in size value // in size value
updated.select('text.processor-in tspan.size') updated.select('text.processor-in tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.input, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.input, ' ');
} else {
return ' (-)';
}
}); });
// read/write value // read/write value
updated.select('text.processor-read-write') updated.select('text.processor-read-write')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return d.status.aggregateSnapshot.read + ' / ' + d.status.aggregateSnapshot.written;
return d.status.read + ' / ' + d.status.written;
} else {
return '- / -';
}
}); });
// out count value // out count value
updated.select('text.processor-out tspan.count') updated.select('text.processor-out tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.output, ' ');
return nf.Common.substringBeforeFirst(d.status.output, ' ');
} else {
return '-';
}
}); });
// out size value // out size value
updated.select('text.processor-out tspan.size') updated.select('text.processor-out tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.output, ' ');
return ' ' + nf.Common.substringAfterFirst(d.status.output, ' ');
} else {
return ' (-)';
}
}); });
// tasks/time value // tasks/time value
updated.select('text.processor-tasks-time') updated.select('text.processor-tasks-time')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return d.status.aggregateSnapshot.tasks + ' / ' + d.status.aggregateSnapshot.tasksDuration;
return d.status.tasks + ' / ' + d.status.tasksDuration;
} else {
return '- / -';
}
}); });
updated.each(function (d) { updated.each(function (d) {
@ -697,7 +684,7 @@ nf.Processor = (function () {
// --------- // ---------
processor.select('rect.bulletin-background').classed('has-bulletins', 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 () { 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 * @param processorEntities The processor
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (processorNodeEntities, selectAll) { add: function (processorEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (processorEntity) { var add = function (processorEntity) {
// add the processor // add the processor
@ -765,16 +755,59 @@ nf.Processor = (function () {
}; };
// determine how to handle the specified processor // determine how to handle the specified processor
if ($.isArray(processorNodeEntities)) { if ($.isArray(processorEntities)) {
$.each(processorNodeEntities, function (_, processorEntity) { $.each(processorEntities, function (_, processorEntity) {
add(processorEntity); add(processorEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(processorEntities)) {
add(processorNodeEntities); 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 // 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. * Removes the specified processor.
* *

View File

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

View File

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

View File

@ -101,9 +101,6 @@ nf.RemoteProcessGroup = (function () {
}, },
'fill': 'transparent', 'fill': 'transparent',
'stroke': 'transparent' 'stroke': 'transparent'
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// remote process group body // remote process group body
@ -118,9 +115,6 @@ nf.RemoteProcessGroup = (function () {
}, },
'filter': 'url(#component-drop-shadow)', 'filter': 'url(#component-drop-shadow)',
'stroke-width': 0 'stroke-width': 0
})
.classed('unauthorized', function (d) {
return d.accessPolicy.canRead === false;
}); });
// remote process group name background // remote process group name background
@ -156,14 +150,6 @@ nf.RemoteProcessGroup = (function () {
// always support selection // always support selection
remoteProcessGroup.call(nf.Selectable.activate).call(nf.ContextMenu.activate); 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 // attempt of space between component count and icon for process group contents
@ -179,10 +165,25 @@ nf.RemoteProcessGroup = (function () {
return; 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) { updated.each(function (remoteProcessGroupData) {
var remoteProcessGroup = d3.select(this); var remoteProcessGroup = d3.select(this);
var details = remoteProcessGroup.select('g.remote-process-group-details'); 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 this processor is visible, render everything
if (remoteProcessGroup.classed('visible')) { if (remoteProcessGroup.classed('visible')) {
if (details.empty()) { if (details.empty()) {
@ -223,7 +224,6 @@ nf.RemoteProcessGroup = (function () {
'y': 48 'y': 48
}); });
if (remoteProcessGroupData.accessPolicy.canRead) {
// remote process group uri // remote process group uri
details.append('text') details.append('text')
.attr({ .attr({
@ -232,19 +232,7 @@ nf.RemoteProcessGroup = (function () {
'width': 305, 'width': 305,
'height': 12, 'height': 12,
'class': 'remote-process-group-uri' '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;
}); });
}
// ---------------- // ----------------
// stats background // stats background
@ -336,8 +324,8 @@ nf.RemoteProcessGroup = (function () {
'transform': 'translate(95, 75)' 'transform': 'translate(95, 75)'
}); });
// queued value // sent value
remoteProcessGroupStatsValue.append('text') var sentText = remoteProcessGroupStatsValue.append('text')
.attr({ .attr({
'width': 180, 'width': 180,
'height': 10, 'height': 10,
@ -346,8 +334,26 @@ nf.RemoteProcessGroup = (function () {
'class': 'remote-process-group-sent stats-value' '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 // received value
remoteProcessGroupStatsValue.append('text') var receivedText = remoteProcessGroupStatsValue.append('text')
.attr({ .attr({
'width': 180, 'width': 180,
'height': 10, 'height': 10,
@ -356,6 +362,24 @@ nf.RemoteProcessGroup = (function () {
'class': 'remote-process-group-received stats-value' '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 // stats value container
var processGroupStatsInfo = details.append('g') var processGroupStatsInfo = details.append('g')
.attr({ .attr({
@ -470,6 +494,20 @@ nf.RemoteProcessGroup = (function () {
} }
if (remoteProcessGroupData.accessPolicy.canRead) { 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 // update the process groups transmission status
details.select('text.remote-process-group-transmission-secure') details.select('text.remote-process-group-transmission-secure')
.text(function (d) { .text(function (d) {
@ -505,98 +543,6 @@ nf.RemoteProcessGroup = (function () {
nf.CanvasUtils.canvasTooltip(tip, d3.select(this)); 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 // update comments
// --------------- // ---------------
@ -643,6 +589,21 @@ nf.RemoteProcessGroup = (function () {
}).append('title').text(function (d) { }).append('title').text(function (d) {
return d.component.name; 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 // show the preview
@ -688,24 +649,40 @@ nf.RemoteProcessGroup = (function () {
return; return;
} }
// sent value // sent count value
updated.select('text.remote-process-group-sent') updated.select('text.remote-process-group-sent tspan.count')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return nf.Common.substringBeforeFirst(d.status.aggregateSnapshot.sent, ' ');
return d.status.sent;
} else {
return '- / -';
}
}); });
// received value // sent size value
updated.select('text.remote-process-group-received') updated.select('text.remote-process-group-sent tspan.size')
.text(function (d) { .text(function (d) {
if (nf.Common.isDefinedAndNotNull(d.status)) { return ' ' + nf.Common.substringAfterFirst(d.status.aggregateSnapshot.sent, ' ');
return d.status.received; });
} else {
return '- / -'; // 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') updated.select('text.remote-process-group-transmission-status')
.text(function (d) { .text(function (d) {
var icon = ''; var icon = '';
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues)) { if (!nf.Common.isEmpty(d.status.aggregateSnapshot.authorizationIssues)) {
icon = '\uf071'; icon = '\uf071';
} else if (d.accessPolicy.canRead) { } else if (d.accessPolicy.canRead) {
if (d.component.transmitting === true) { if (d.component.transmitting === true) {
@ -730,7 +707,7 @@ nf.RemoteProcessGroup = (function () {
}) })
.attr('font-family', function (d) { .attr('font-family', function (d) {
var family = ''; 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'; family = 'FontAwesome';
} else { } else {
family = 'flowfont'; family = 'flowfont';
@ -738,7 +715,7 @@ nf.RemoteProcessGroup = (function () {
return family; return family;
}) })
.classed('has-authorization-errors', function (d) { .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) { .each(function (d) {
// remove the existing tip if necessary // remove the existing tip if necessary
@ -748,14 +725,14 @@ nf.RemoteProcessGroup = (function () {
} }
// if there are validation errors generate a tooltip // 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') tip = d3.select('#remote-process-group-tooltips').append('div')
.attr('id', function () { .attr('id', function () {
return 'authorization-issues-' + d.id; return 'authorization-issues-' + d.id;
}) })
.attr('class', 'tooltip nifi-tooltip') .attr('class', 'tooltip nifi-tooltip')
.html(function () { .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) { if (list === null || list.length === 0) {
return ''; return '';
} else { } else {
@ -785,7 +762,7 @@ nf.RemoteProcessGroup = (function () {
// --------- // ---------
remoteProcessGroup.select('rect.bulletin-background').classed('has-bulletins', 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 () { 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 * @param remoteProcessGroupEntities The remote process group
* @argument {boolean} selectAll Whether or not to select the new contents * @param options Configuration options
*/ */
add: function (remoteProcessGroupEntities, selectAll) { add: function (remoteProcessGroupEntities, options) {
selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false; var selectAll = false;
if (nf.Common.isDefinedAndNotNull(options)) {
selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? options.selectAll : selectAll;
}
var add = function (remoteProcessGroupEntity) { var add = function (remoteProcessGroupEntity) {
// add the remote process group // add the remote process group
@ -858,12 +838,55 @@ nf.RemoteProcessGroup = (function () {
$.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) { $.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
add(remoteProcessGroupEntity); add(remoteProcessGroupEntity);
}); });
} else { } else if (nf.Common.isDefinedAndNotNull(remoteProcessGroupEntities)) {
add(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 // 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); 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. * Sets the remote process group status using the specified status.
* *

View File

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

View File

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

View File

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

View File

@ -17,43 +17,34 @@
/* global nf */ /* global nf */
nf.Client = {}; nf.Client = (function() {
var clientId = null;
nf.Client.version = -1;
nf.Client.clientId = null;
/**
* Gets the current revision.
*/
nf.Client.getRevision = function () {
return { 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. * Builds the revision fof the specified component
* * @param d The component
* @argument {integer} revision The revision * @returns The revision
*/ */
nf.Client.setRevision = function (revision) { getRevision: function (d) {
// ensure a value was returned return {
if (nf.Common.isDefinedAndNotNull(revision.version)) { 'clientId': clientId,
if (nf.Common.isDefinedAndNotNull(nf.Client.version)) { 'version': d.revision.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;
}
}
// 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(); nf.ContextMenu.hide();
// shut off the auto refresh // shut off the auto refresh
nf.Canvas.stopRevisionPolling(); nf.Canvas.stopPolling();
nf.Canvas.stopStatusPolling();
} }
}, },