Repository: nifi
Updated Branches:
  refs/heads/NIFI-108 de264b1c7 -> bbe819811


NIFI-108:
- Adding initial listing capabilities.
- Passing through the sort column and direction.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/bbe81981
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/bbe81981
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/bbe81981

Branch: refs/heads/NIFI-108
Commit: bbe819811752d5710626a19ec813225e67826562
Parents: de264b1
Author: Matt Gilman <[email protected]>
Authored: Thu Dec 17 23:04:48 2015 -0500
Committer: Matt Gilman <[email protected]>
Committed: Thu Dec 17 23:04:48 2015 -0500

----------------------------------------------------------------------
 .../nifi/web/api/dto/FlowFileSummaryDTO.java    |  34 +-
 .../nifi/controller/FlowFileSummaries.java      |   4 +-
 .../org/apache/nifi/web/NiFiServiceFacade.java  |   6 +-
 .../nifi/web/StandardNiFiServiceFacade.java     |   6 +-
 .../apache/nifi/web/api/ConnectionResource.java |  44 +-
 .../org/apache/nifi/web/api/dto/DtoFactory.java |  24 +-
 .../org/apache/nifi/web/dao/ConnectionDAO.java  |   6 +-
 .../web/dao/impl/StandardConnectionDAO.java     |   6 +-
 .../src/main/resources/nifi-web-api-context.xml |   1 +
 .../nifi-framework/nifi-web/nifi-web-ui/pom.xml |   2 +
 .../main/resources/filters/canvas.properties    |   1 +
 .../src/main/webapp/WEB-INF/pages/canvas.jsp    |   2 +
 .../canvas/listing-request-status-dialog.jsp    |  29 ++
 .../WEB-INF/partials/canvas/queue-listing.jsp   |  29 ++
 .../nifi-web-ui/src/main/webapp/css/canvas.css  |   1 +
 .../nifi-web-ui/src/main/webapp/css/dialog.css  |  21 +-
 .../src/main/webapp/css/queue-listing.css       |  86 ++++
 .../src/main/webapp/images/iconListQueue.png    | Bin 0 -> 1502 bytes
 .../src/main/webapp/js/nf/canvas/nf-actions.js  |  25 +-
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |   1 +
 .../main/webapp/js/nf/canvas/nf-context-menu.js |  11 +
 .../webapp/js/nf/canvas/nf-queue-listing.js     | 435 +++++++++++++++++++
 22 files changed, 730 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java
index 06b2776..e787e41 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java
@@ -17,10 +17,6 @@
 package org.apache.nifi.web.api.dto;
 
 import com.wordnik.swagger.annotations.ApiModelProperty;
-import org.apache.nifi.web.api.dto.util.TimestampAdapter;
-
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import java.util.Date;
 
 public class FlowFileSummaryDTO {
 
@@ -30,8 +26,8 @@ public class FlowFileSummaryDTO {
     private String filename;
     private Integer position;
     private Long size;
-    private Date lastQueuedTime;
-    private Date linageStartDate;
+    private Long queuedDuration;
+    private Long lineageDuration;
     private Boolean isPenalized;
 
     private String clusterNodeId;
@@ -107,33 +103,31 @@ public class FlowFileSummaryDTO {
     }
 
     /**
-     * @return when the FlowFile was last added to the queue
+     * @return how long this FlowFile has been enqueued
      */
-    @XmlJavaTypeAdapter(TimestampAdapter.class)
     @ApiModelProperty(
-        value = "When the FlowFile was last added to the queue."
+        value = "How long this FlowFile has been enqueued."
     )
-    public Date getLastQueuedTime() {
-        return lastQueuedTime;
+    public Long getQueuedDuration() {
+        return queuedDuration;
     }
 
-    public void setLastQueuedTime(Date lastQueuedTime) {
-        this.lastQueuedTime = lastQueuedTime;
+    public void setQueuedDuration(Long queuedDuration) {
+        this.queuedDuration = queuedDuration;
     }
 
     /**
-     * @return when the FlowFile's greatest ancestor entered the flow
+     * @return duration since the FlowFile's greatest ancestor entered the flow
      */
-    @XmlJavaTypeAdapter(TimestampAdapter.class)
     @ApiModelProperty(
-        value = "When the FlowFile's greatest ancestor entered the flow."
+        value = "Duration since the FlowFile's greatest ancestor entered the 
flow."
     )
-    public Date getLinageStartDate() {
-        return linageStartDate;
+    public Long getLineageDuration() {
+        return lineageDuration;
     }
 
-    public void setLinageStartDate(Date linageStartDate) {
-        this.linageStartDate = linageStartDate;
+    public void setLineageDuration(Long lineageDuration) {
+        this.lineageDuration = lineageDuration;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowFileSummaries.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowFileSummaries.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowFileSummaries.java
index 5a0a3ab..7687d8a 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowFileSummaries.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowFileSummaries.java
@@ -68,7 +68,7 @@ public class FlowFileSummaries {
                     case FILENAME:
                         return o1.getFilename().compareTo(o2.getFilename());
                     case FLOWFILE_AGE:
-                        return 
o1.getLinageStartDate().compareTo(o2.getLinageStartDate());
+                        return 
o1.getLineageDuration().compareTo(o2.getLineageDuration());
                     case FLOWFILE_SIZE:
                         return Long.compare(o1.getSize(), o2.getSize());
                     case FLOWFILE_UUID:
@@ -78,7 +78,7 @@ public class FlowFileSummaries {
                     case QUEUE_POSITION:
                         return Long.compare(o1.getPosition(), 
o2.getPosition());
                     case QUEUED_DURATION:
-                        return 
o1.getLastQueuedTime().compareTo(o2.getLastQueuedTime());
+                        return 
o1.getQueuedDuration().compareTo(o2.getQueuedDuration());
                 }
 
                 return 0;

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index fe67473..4bc1222 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -21,6 +21,8 @@ import java.util.Date;
 import java.util.Set;
 import org.apache.nifi.controller.ScheduledState;
 
+import org.apache.nifi.controller.queue.SortColumn;
+import org.apache.nifi.controller.queue.SortDirection;
 import org.apache.nifi.controller.repository.claim.ContentDirection;
 import org.apache.nifi.controller.service.ControllerServiceState;
 import org.apache.nifi.web.api.dto.BulletinBoardDTO;
@@ -583,9 +585,11 @@ public interface NiFiServiceFacade {
      * @param groupId group
      * @param connectionId The ID of the connection
      * @param listingRequestId The ID of the listing request
+     * @param column sort column
+     * @param direction sort direction
      * @return The ListingRequest
      */
-    ListingRequestDTO createFlowFileListingRequest(String groupId, String 
connectionId, String listingRequestId);
+    ListingRequestDTO createFlowFileListingRequest(String groupId, String 
connectionId, String listingRequestId, SortColumn column, SortDirection 
direction);
 
     /**
      * Gets a new flow file listing request.

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index abfd5b8..2f92588 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -62,6 +62,8 @@ import org.apache.nifi.controller.ProcessorNode;
 import org.apache.nifi.controller.Snippet;
 import org.apache.nifi.controller.Template;
 import org.apache.nifi.controller.label.Label;
+import org.apache.nifi.controller.queue.SortColumn;
+import org.apache.nifi.controller.queue.SortDirection;
 import org.apache.nifi.controller.repository.claim.ContentDirection;
 import org.apache.nifi.controller.status.ConnectionStatus;
 import org.apache.nifi.controller.status.PortStatus;
@@ -1086,8 +1088,8 @@ public class StandardNiFiServiceFacade implements 
NiFiServiceFacade {
     }
 
     @Override
-    public ListingRequestDTO createFlowFileListingRequest(String groupId, 
String connectionId, String listingRequestId) {
-        return 
dtoFactory.createListingRequestDTO(connectionDAO.createFlowFileListingRequest(groupId,
 connectionId, listingRequestId));
+    public ListingRequestDTO createFlowFileListingRequest(String groupId, 
String connectionId, String listingRequestId, SortColumn column, SortDirection 
direction) {
+        return 
dtoFactory.createListingRequestDTO(connectionDAO.createFlowFileListingRequest(groupId,
 connectionId, listingRequestId, column, direction));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
index 1415846..4b5193f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
@@ -29,6 +29,8 @@ import 
org.apache.nifi.cluster.manager.exception.UnknownNodeException;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
+import org.apache.nifi.controller.queue.SortColumn;
+import org.apache.nifi.controller.queue.SortDirection;
 import org.apache.nifi.stream.io.StreamUtils;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.ConfigurationSnapshot;
@@ -1273,7 +1275,38 @@ public class ConnectionResource extends 
ApplicationResource {
                 value = "The connection id.",
                 required = true
             )
-            @PathParam("connection-id") String id) {
+            @PathParam("connection-id") String id,
+            @ApiParam(
+                value = "The sort column.",
+                required = false,
+                defaultValue = "QUEUE_POSITION",
+                allowableValues = "QUEUE_POSITION, FLOWFILE_UUID, FILENAME, 
FLOWFILE_SIZE, QUEUED_DURATION, FLOWFILE_AGE, PENALIZATION"
+            )
+            @FormParam("sortColumn") String sortColumn,
+            @ApiParam(
+                value = "The sort direction.",
+                required = false,
+                defaultValue = "asc",
+                allowableValues = "asc, desc"
+            )
+            @FormParam("sortOrder") @DefaultValue("asc") String sortOrder) {
+
+        // parse the sort column
+        final SortColumn column;
+        if (sortColumn == null) {
+            column = SortColumn.QUEUE_POSITION;
+        } else {
+            try {
+                column = SortColumn.valueOf(sortColumn);
+            } catch (final IllegalArgumentException iae) {
+                throw new IllegalArgumentException(String.format("Sort Column: 
Value must be one of [%s]", StringUtils.join(SortColumn.values(), ", ")));
+            }
+        }
+
+        // normalize the sort order
+        if (!sortOrder.equalsIgnoreCase("asc") && 
!sortOrder.equalsIgnoreCase("desc")) {
+            throw new IllegalArgumentException("The sort order must be 'asc' 
or 'desc'.");
+        }
 
         // replicate if cluster manager
         if (properties.isClusterManager()) {
@@ -1287,6 +1320,13 @@ public class ConnectionResource extends 
ApplicationResource {
             return generateContinueResponse().build();
         }
 
+        final SortDirection direction;
+        if (sortOrder.equalsIgnoreCase("asc")) {
+            direction = SortDirection.ASCENDING;
+        } else {
+            direction = SortDirection.DESCENDING;
+        }
+
         // ensure the id is the same across the cluster
         final String listingRequestId;
         final ClusterContext clusterContext = 
ClusterContextThreadLocal.getContext();
@@ -1297,7 +1337,7 @@ public class ConnectionResource extends 
ApplicationResource {
         }
 
         // submit the listing request
-        final ListingRequestDTO listingRequest = 
serviceFacade.createFlowFileListingRequest(groupId, id, listingRequestId);
+        final ListingRequestDTO listingRequest = 
serviceFacade.createFlowFileListingRequest(groupId, id, listingRequestId, 
column, direction);
         populateRemainingFlowFileListingContent(id, listingRequest);
 
         // create the revision

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 5c3e864..9d02cbc 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -378,9 +378,10 @@ public final class DtoFactory {
         if (isListingRequestComplete(listingRequest.getState())) {
             final List<FlowFileSummary> flowFileSummaries = 
listingRequest.getFlowFileSummaries();
             if (flowFileSummaries != null) {
+                final Date now = new Date();
                 final List<FlowFileSummaryDTO> summaryDtos = new 
ArrayList<>(flowFileSummaries.size());
                 for (final FlowFileSummary summary : flowFileSummaries) {
-                    summaryDtos.add(createFlowFileSummaryDTO(summary));
+                    summaryDtos.add(createFlowFileSummaryDTO(summary, now));
                 }
                 dto.setFlowFileSummaries(summaryDtos);
             }
@@ -395,15 +396,20 @@ public final class DtoFactory {
      * @param summary summary
      * @return dto
      */
-    public FlowFileSummaryDTO createFlowFileSummaryDTO(final FlowFileSummary 
summary) {
+    public FlowFileSummaryDTO createFlowFileSummaryDTO(final FlowFileSummary 
summary, final Date now) {
         final FlowFileSummaryDTO dto = new FlowFileSummaryDTO();
         dto.setUuid(summary.getUuid());
         dto.setFilename(summary.getFilename());
-        dto.setLastQueuedTime(new Date(summary.getLastQueuedTime()));
-        dto.setLinageStartDate(new Date(summary.getLineageStartDate()));
         dto.setPenalized(summary.isPenalized());
         dto.setPosition(summary.getPosition());
         dto.setSize(summary.getSize());
+
+        final long queuedDuration = now.getTime() - 
summary.getLastQueuedTime();
+        dto.setQueuedDuration(queuedDuration);
+
+        final long age = now.getTime() - summary.getLineageStartDate();
+        dto.setLineageDuration(age);
+
         return dto;
     }
 
@@ -414,14 +420,20 @@ public final class DtoFactory {
      * @return dto
      */
     public FlowFileDTO createFlowFileDTO(final FlowFileRecord record) {
+        final Date now = new Date();
         final FlowFileDTO dto = new FlowFileDTO();
         dto.setUuid(record.getAttribute(CoreAttributes.UUID.key()));
         dto.setFilename(record.getAttribute(CoreAttributes.FILENAME.key()));
-        dto.setLastQueuedTime(new Date(record.getLastQueueDate()));
-        dto.setLinageStartDate(new Date(record.getLineageStartDate()));
         dto.setPenalized(record.isPenalized());
         dto.setSize(record.getSize());
         dto.setAttributes(record.getAttributes());
+
+        final long queuedDuration = now.getTime() - record.getLastQueueDate();
+        dto.setQueuedDuration(queuedDuration);
+
+        final long age = now.getTime() - record.getLineageStartDate();
+        dto.setLineageDuration(age);
+
         return dto;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectionDAO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectionDAO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectionDAO.java
index 85cd9b3..932cc23 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectionDAO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectionDAO.java
@@ -20,6 +20,8 @@ import java.util.Set;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.controller.queue.DropFlowFileStatus;
 import org.apache.nifi.controller.queue.ListFlowFileStatus;
+import org.apache.nifi.controller.queue.SortColumn;
+import org.apache.nifi.controller.queue.SortDirection;
 import org.apache.nifi.controller.repository.FlowFileRecord;
 import org.apache.nifi.web.DownloadableContent;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
@@ -116,9 +118,11 @@ public interface ConnectionDAO {
      * @param groupId group id
      * @param id connection id
      * @param listingRequestId listing request id
+     * @param column sort column
+     * @param direction sort direction
      * @return The listing request status
      */
-    ListFlowFileStatus createFlowFileListingRequest(String groupId, String id, 
String listingRequestId);
+    ListFlowFileStatus createFlowFileListingRequest(String groupId, String id, 
String listingRequestId, SortColumn column, SortDirection direction);
 
     /**
      * Verifies the listing can be processed.

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
index dca1c18..24601b3 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
@@ -40,6 +40,8 @@ import 
org.apache.nifi.controller.exception.ValidationException;
 import org.apache.nifi.controller.queue.DropFlowFileStatus;
 import org.apache.nifi.controller.queue.FlowFileQueue;
 import org.apache.nifi.controller.queue.ListFlowFileStatus;
+import org.apache.nifi.controller.queue.SortColumn;
+import org.apache.nifi.controller.queue.SortDirection;
 import org.apache.nifi.controller.repository.ContentNotFoundException;
 import org.apache.nifi.controller.repository.FlowFileRecord;
 import org.apache.nifi.flowfile.attributes.CoreAttributes;
@@ -373,10 +375,10 @@ public class StandardConnectionDAO extends ComponentDAO 
implements ConnectionDAO
     }
 
     @Override
-    public ListFlowFileStatus createFlowFileListingRequest(String groupId, 
String id, String listingRequestId) {
+    public ListFlowFileStatus createFlowFileListingRequest(String groupId, 
String id, String listingRequestId, SortColumn column, SortDirection direction) 
{
         final Connection connection = locateConnection(groupId, id);
         final FlowFileQueue queue = connection.getFlowFileQueue();
-        return queue.listFlowFiles(listingRequestId, 100);
+        return queue.listFlowFiles(listingRequestId, 100, column, direction);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 9f3d2f5..406f38c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -76,6 +76,7 @@
     </bean>
     <bean id="connectionDAO" 
class="org.apache.nifi.web.dao.impl.StandardConnectionDAO">
         <property name="flowController" ref="flowController"/>
+        <property name="userService" ref="userService"/>
     </bean>
     <bean id="processorDAO" 
class="org.apache.nifi.web.dao.impl.StandardProcessorDAO">
         <property name="flowController" ref="flowController"/>

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
index dc3c448..409afd9 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/pom.xml
@@ -280,6 +280,7 @@
                                                 
<include>${staging.dir}/js/nf/canvas/nf-snippet.js</include>
                                                 
<include>${staging.dir}/js/nf/canvas/nf-canvas-toolbox.js</include>
                                                 
<include>${staging.dir}/js/nf/canvas/nf-custom-ui.js</include>
+                                                
<include>${staging.dir}/js/nf/canvas/nf-queue-listing.js</include>
                                                 
<include>${staging.dir}/js/nf/canvas/nf-controller-service.js</include>
                                                 
<include>${staging.dir}/js/nf/canvas/nf-reporting-task.js</include>
                                                 
<include>${staging.dir}/js/nf/canvas/nf-processor-configuration.js</include>
@@ -445,6 +446,7 @@
                                                 
<include>${staging.dir}/css/remote-process-group-configuration.css</include>
                                                 
<include>${staging.dir}/css/port-configuration.css</include>
                                                 
<include>${staging.dir}/css/port-details.css</include>
+                                                
<include>${staging.dir}/css/queue-listing.css</include>
                                                 
<include>${staging.dir}/css/label-configuration.css</include>
                                                 
<include>${staging.dir}/css/connection-configuration.css</include>
                                                 
<include>${staging.dir}/css/connection-details.css</include>

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
index bf61846..43e60f4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/resources/filters/canvas.properties
@@ -21,6 +21,7 @@ nf.canvas.script.tags=<script type="text/javascript" 
src="js/nf/nf-namespace.js?
 <script type="text/javascript" 
src="js/nf/nf-shell.js?${project.version}"></script>\n\
 <script type="text/javascript" 
src="js/nf/nf-storage.js?${project.version}"></script>\n\
 <script type="text/javascript" 
src="js/nf/canvas/nf-snippet.js?${project.version}"></script>\n\
+<script type="text/javascript" 
src="js/nf/canvas/nf-queue-listing.js?${project.version}"></script>\n\
 <script type="text/javascript" 
src="js/nf/canvas/nf-canvas-toolbox.js?${project.version}"></script>\n\
 <script type="text/javascript" 
src="js/nf/canvas/nf-custom-ui.js?${project.version}"></script>\n\
 <script type="text/javascript" 
src="js/nf/canvas/nf-controller-service.js?${project.version}"></script>\n\

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
index f9970df..337b2b0 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/pages/canvas.jsp
@@ -119,6 +119,8 @@
         <jsp:include page="/WEB-INF/partials/canvas/label-configuration.jsp"/>
         <jsp:include 
page="/WEB-INF/partials/canvas/connection-configuration.jsp"/>
         <jsp:include 
page="/WEB-INF/partials/canvas/drop-request-status-dialog.jsp"/>
+        <jsp:include 
page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/>
+        <jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/>
         <jsp:include page="/WEB-INF/partials/connection-details.jsp"/>
         <div id="faded-background"></div>
         <div id="glass-pane"></div>

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/listing-request-status-dialog.jsp
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/listing-request-status-dialog.jsp
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/listing-request-status-dialog.jsp
new file mode 100644
index 0000000..3320388
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/listing-request-status-dialog.jsp
@@ -0,0 +1,29 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="listing-request-status-dialog">
+    <div class="dialog-content">
+        <div class="setting">
+            <div class="setting-field">
+                <div id="listing-request-status-message"></div>
+            </div>
+            <div class="setting-field">
+                <div id="listing-request-percent-complete"></div>
+            </div>
+        </div>
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/queue-listing.jsp
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/queue-listing.jsp
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/queue-listing.jsp
new file mode 100644
index 0000000..d00e365
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/queue-listing.jsp
@@ -0,0 +1,29 @@
+<%--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+--%>
+<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
+<div id="queue-listing-container" class="hidden">
+    <div id="queue-listing-header-and-filter">
+        <div id="queue-listing-header-text"></div>
+    </div>
+    <div id="queue-listing-refresh-container">
+        <div id="queue-listing-last-refreshed-container">
+            Last updated:&nbsp;<span id="queue-listing-last-refreshed"></span>
+        </div>
+        <div id="queue-listing-loading-container" 
class="loading-container"></div>
+    </div>
+    <div id="queue-listing-table"></div>
+</div>

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
index abb5ebd..2df31d6 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/canvas.css
@@ -19,6 +19,7 @@
 @import url(processor-details.css);
 @import url(process-group-configuration.css);
 @import url(process-group-details.css);
+@import url(queue-listing.css);
 @import url(remote-process-group-configuration.css);
 @import url(controller-service.css);
 @import url(reporting-task.css);

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
index 9f4fefb..86d52fe 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/dialog.css
@@ -276,10 +276,6 @@ div.go-to-link {
     z-index: 1301;
 }
 
-#drop-request-status-message {
-    
-}
-
 #drop-request-percent-complete {
     margin-top: 10px;
     width: 378px;
@@ -290,6 +286,23 @@ div.go-to-link {
     border-radius: 0;
 }
 
+#listing-request-status-dialog {
+    display: none;
+    width: 400px;
+    height: 125px;
+    z-index: 1301;
+}
+
+#listing-request-percent-complete {
+    margin-top: 10px;
+    width: 378px;
+    border-radius: 0;
+}
+
+#listing-request-percent-complete .ui-progressbar-value {
+    border-radius: 0;
+}
+
 div.progress-label {
     color: #000000;
     display: block;

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/queue-listing.css
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/queue-listing.css
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/queue-listing.css
new file mode 100644
index 0000000..f705ceb
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/css/queue-listing.css
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+    Queue listing styles
+*/
+
+#queue-listing-container {
+    position: absolute;
+    top: 0px;
+    bottom: 0px;
+    left: 0px;
+    right: 0px;
+}
+
+#queue-listing-header-and-filter {
+    height: 35px;
+    margin-top: 20px;
+    margin-left: 20px;
+    margin-right: 20px;
+}
+
+#queue-listing-header-text {
+    float: left;
+    font-size: 16px;
+    font-weight: bold;
+}
+
+#queue-listing-refresh-container {
+    height: 26px;
+    margin-left: 20px;
+    margin-right: 20px;
+    margin-top: 18px;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+}
+
+#queue-listing-last-refreshed-container {
+    float: left;
+    color: #666;
+    font-weight: normal;
+    margin-top: 6px;
+    margin-left: 3px;
+}
+
+#queue-listing-loading-container {
+    float: left;
+    width: 16px;
+    height: 16px;
+    background-color: transparent;
+    margin-top: 4px;
+    margin-left: 3px;
+}
+
+#queue-listing-last-refreshed {
+    font-weight: bold;
+}
+
+#queue-listing-header {
+    padding-top: 10px;
+}
+
+/* queue listing table */
+
+#queue-listing-table {
+    position: absolute;
+    top: 100px;
+    left: 20px;
+    bottom: 20px;
+    right: 20px;
+    border: 1px solid #666;
+    overflow: hidden;
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconListQueue.png
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconListQueue.png
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconListQueue.png
new file mode 100644
index 0000000..9a60eef
Binary files /dev/null and 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/images/iconListQueue.png
 differ

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
index 08f0e42..2f1bbd3 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
@@ -928,7 +928,7 @@ nf.Actions = (function () {
                                         // cancel it
                                         clearTimeout(dropRequestTimer);
 
-                                        // cancel the provenance
+                                        // cancel the drop request
                                         completeDropRequest();
                                     }
                                 }
@@ -1028,8 +1028,8 @@ nf.Actions = (function () {
 
                     // issue the request to delete the flow files
                     $.ajax({
-                        type: 'DELETE',
-                        url: connection.component.uri + '/contents',
+                        type: 'POST',
+                        url: connection.component.uri + '/drop-requests',
                         dataType: 'json'
                     }).done(function(response) {
                         // initialize the progress bar value
@@ -1045,7 +1045,24 @@ nf.Actions = (function () {
                 }
             });
         },
-        
+
+        /**
+         * Lists the flow files in the specified connection.
+         *
+         * @param {selection} selection
+         */
+        listQueue: function (selection) {
+            if (selection.size() !== 1 || 
!nf.CanvasUtils.isConnection(selection)) {
+                return;
+            }
+
+            // get the connection data
+            var connection = selection.datum();
+
+            // list the flow files in the specified connection
+            nf.QueueListing.listQueue(connection);
+        },
+
         /**
          * Opens the fill color dialog for the component in the specified 
selection.
          * 

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 428ddf2..25d7255 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -1145,6 +1145,7 @@ nf.Canvas = (function () {
                             nf.Search.init();
                             nf.Settings.init();
                             nf.Actions.init();
+                            nf.QueueListing.init();
 
                             // initialize the component behaviors
                             nf.Draggable.init();

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
index d5f49d6..1e7925e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
@@ -299,6 +299,16 @@ nf.ContextMenu = (function () {
     var canEmptyQueue = function (selection) {
         return nf.Common.isDFM() && isConnection(selection);
     };
+
+    /**
+     * Only DFMs can list a queue.
+     *
+     * @param {selection} selection
+     */
+    var canListQueue = function (selection) {
+        // TODO verify source/destination stopped and 0 active threads
+        return nf.Common.isDFM() && isConnection(selection) && 
nf.CanvasUtils.supportsModification(selection);
+    };
     
     /**
      * Determines if the components in the specified selection can be moved 
into a parent group.
@@ -402,6 +412,7 @@ nf.ContextMenu = (function () {
         {condition: isCopyable, menuItem: {img: 'images/iconCopy.png', text: 
'Copy', action: 'copy'}},
         {condition: isPastable, menuItem: {img: 'images/iconPaste.png', text: 
'Paste', action: 'paste'}},
         {condition: canMoveToParent, menuItem: {img: 
'images/iconMoveToParent.png', text: 'Move to parent group', action: 
'moveIntoParent'}},
+        {condition: canListQueue, menuItem: {img: 'images/iconListQueue.png', 
text: 'List queue', action: 'listQueue'}},
         {condition: canEmptyQueue, menuItem: {img: 
'images/iconEmptyQueue.png', text: 'Empty queue', action: 'emptyQueue'}},
         {condition: isDeletable, menuItem: {img: 'images/iconDelete.png', 
text: 'Delete', action: 'delete'}}
     ];

http://git-wip-us.apache.org/repos/asf/nifi/blob/bbe81981/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
new file mode 100644
index 0000000..5336b89
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
@@ -0,0 +1,435 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* global nf */
+
+/**
+ * Lists FlowFiles from a given connection.
+ */
+nf.QueueListing = (function () {
+
+    var DEFAULT_SORT_COL = 'QUEUE_POSITION';
+    var DEFAULT_SORT_ASC = true;
+
+    /**
+     * Initializes the listing request status dialog.
+     */
+    var initializeListingRequestStatusDialog = function () {
+        // initialize the listing request progress bar
+        var listingRequestProgressBar = 
$('#listing-request-percent-complete').progressbar();
+
+        // configure the drop request status dialog
+        $('#listing-request-status-dialog').modal({
+            overlayBackground: false,
+            handler: {
+                close: function () {
+                    // reset the progress bar
+                    
listingRequestProgressBar.find('div.progress-label').remove();
+
+                    // update the progress bar
+                    var label = $('<div 
class="progress-label"></div>').text('0%');
+                    listingRequestProgressBar.progressbar('value', 
0).append(label);
+
+                    // clear the current button model
+                    
$('#listing-request-status-dialog').modal('setButtonModel', []);
+                }
+            }
+        }).draggable({
+            containment: 'parent',
+            handle: '.dialog-header'
+        });
+    };
+
+    /**
+     * Downloads the content for the provenance event that is currently loaded 
in the specified direction.
+     *
+     * @param {string} direction
+     */
+    var downloadContent = function (direction) {
+        var connection = $('#queue-listing-table').data('connection');
+
+        // build the url to the data
+        var url = config.urls.provenance + '/events/' + 
encodeURIComponent(eventId) + '/content/' + encodeURIComponent(direction);
+
+        // conditionally include the cluster node id
+        var clusterNodeId = $('#provenance-event-cluster-node-id').text();
+        if (!nf.Common.isBlank(clusterNodeId)) {
+            window.open(url + '?' + $.param({
+                    'clusterNodeId': clusterNodeId
+                }));
+        } else {
+            window.open(url);
+        }
+    };
+
+    /**
+     * Views the content for the provenance event that is currently loaded in 
the specified direction.
+     *
+     * @param {string} direction
+     */
+    var viewContent = function (direction) {
+
+        // build the uri to the data
+        var dataUri = controllerUri + '/provenance/events/' + 
encodeURIComponent(eventId) + '/content/' + encodeURIComponent(direction);
+
+        // conditionally include the cluster node id
+        var clusterNodeId = $('#provenance-event-cluster-node-id').text();
+        if (!nf.Common.isBlank(clusterNodeId)) {
+            var parameters = {
+                'clusterNodeId': clusterNodeId
+            };
+
+            dataUri = dataUri + '?' + $.param(parameters);
+        }
+
+        // open the content viewer
+        var contentViewerUrl = $('#nifi-content-viewer-url').text();
+
+        // if there's already a query string don't add another ?... this 
assumes valid
+        // input meaning that if the url has already included a ? it also 
contains at
+        // least one query parameter
+        if (contentViewerUrl.indexOf('?') === -1) {
+            contentViewerUrl += '?';
+        } else {
+            contentViewerUrl += '&';
+        }
+
+        // open the content viewer
+        window.open(contentViewerUrl + $.param({
+                'ref': dataUri
+            }));
+    };
+
+    /**
+     * Initializes the flowfile details dialog.
+     */
+    var initFlowFileDetailsDialog = function () {
+
+    };
+
+    /**
+     * Performs a listing on the specified connection.
+     *
+     * @param connection the connection
+     * @param sortCol the sort column
+     * @param sortAsc if sort is asc
+     */
+    var performListing = function (connection, sortCol, sortAsc) {
+
+        var MAX_DELAY = 4;
+        var cancelled = false;
+        var listingRequest = null;
+        var listingRequestTimer = null;
+
+        // updates the progress bar
+        var updateProgress = function (percentComplete) {
+            // remove existing labels
+            var progressBar = $('#listing-request-percent-complete');
+            progressBar.find('div.progress-label').remove();
+
+            // update the progress bar
+            var label = $('<div 
class="progress-label"></div>').text(percentComplete + '%');
+            if (percentComplete > 0) {
+                label.css('margin-top', '-19px');
+            }
+            progressBar.progressbar('value', percentComplete).append(label);
+        };
+
+        // update the button model of the drop request status dialog
+        $('#listing-request-status-dialog').modal('setButtonModel', [{
+            buttonText: 'Stop',
+            handler: {
+                click: function () {
+                    cancelled = true;
+
+                    // we are waiting for the next poll attempt
+                    if (listingRequestTimer !== null) {
+                        // cancel it
+                        clearTimeout(listingRequestTimer);
+
+                        // cancel the listing request
+                        completeListingRequest();
+                    }
+                }
+            }
+        }]);
+
+        // completes the listing request by removing it
+        var completeListingRequest = function () {
+            if (nf.Common.isDefinedAndNotNull(listingRequest)) {
+                $.ajax({
+                    type: 'DELETE',
+                    url: listingRequest.uri,
+                    dataType: 'json'
+                }).always(function() {
+                    $('#listing-request-status-dialog').modal('hide');
+
+                    // use the listing request from when the listing completed
+                    if 
(nf.Common.isDefinedAndNotNull(listingRequest.flowFileSummaries)) {
+                        var queueListingGrid = 
$('#queue-listing-table').data('gridInstance');
+                        var queueListingData = queueListingGrid.getData();
+
+                        // load the flowfiles
+                        queueListingData.beginUpdate();
+                        
queueListingData.setItems(listingRequest.flowFileSummaries, 'uuid');
+                        queueListingData.endUpdate();
+                    } else {
+                        if (cancelled === false) {
+                            nf.Dialog.showOkDialog({
+                                dialogContent: 'The queue has no FlowFiles.',
+                                overlayBackground: false
+                            });
+                        }
+                    }
+                });
+            } else {
+                // close the dialog
+                $('#listing-request-status-dialog').modal('hide');
+            }
+        };
+
+        // process the listing request
+        var processListingRequest = function (delay) {
+            // update the percent complete
+            updateProgress(listingRequest.percentCompleted);
+
+            // update the status of the listing request
+            $('#listing-request-status-message').text(listingRequest.state);
+
+            // close the dialog if the
+            if (listingRequest.finished === true || cancelled === true) {
+                completeListingRequest();
+            } else {
+                // wait delay to poll again
+                listingRequestTimer = setTimeout(function () {
+                    // clear the listing request timer
+                    listingRequestTimer = null;
+
+                    // schedule to poll the status again in nextDelay
+                    pollListingRequest(Math.min(MAX_DELAY, delay * 2));
+                }, delay * 1000);
+            }
+        };
+
+        // schedule for the next poll iteration
+        var pollListingRequest = function (nextDelay) {
+            $.ajax({
+                type: 'GET',
+                url: listingRequest.uri,
+                dataType: 'json'
+            }).done(function(response) {
+                listingRequest = response.listingRequest;
+                processListingRequest(nextDelay);
+            }).fail(completeListingRequest);
+        };
+
+        // issue the request to list the flow files
+        $.ajax({
+            type: 'POST',
+            url: connection.component.uri + '/listing-requests',
+            data: {
+                sortCol: sortCol,
+                sortDir: sortAsc ? 'asc' : 'desc'
+            },
+            dataType: 'json'
+        }).done(function(response) {
+            // initialize the progress bar value
+            updateProgress(0);
+
+            // show the progress dialog
+            $('#listing-request-status-dialog').modal('show');
+
+            // process the drop request
+            listingRequest = response.listingRequest;
+            processListingRequest(1);
+        }).fail(completeListingRequest);
+    };
+
+    /**
+     * Shows the details for the specified flowfile.
+     *
+     * @param flowFileSummary the flowfile summary
+     */
+    var showFlowFileDetails = function (flowFileSummary) {
+        $.ajax({
+            type: 'GET',
+            url: flowFileSummary.uri,
+            dataType: 'json'
+        }).done(function(response) {
+            var flowFile = response.flowfile;
+
+            // show the flowfile details dialog
+
+        }).fail(nf.Common.handleAjaxError);
+    };
+
+    /**
+     * Deletes the specified flowfile.
+     *
+     * @param flowFileSummary the flowfile summary
+     */
+    var deleteFlowfile = function (flowFileSummary) {
+        $.ajax({
+            type: 'DELETE',
+            url: flowFileSummary.uri,
+            dataType: 'json'
+        }).done(function(response) {
+            // get the table and update the row accordingly
+            var queueListingGrid = 
$('#queue-listing-table').data('gridInstance');
+            var queueListingData = queueListingGrid.getData();
+            queueListingData.deleteItem(flowFileSummary.uuid);
+        }).fail(nf.Common.handleAjaxError);
+    };
+
+    /**
+     * Resets the table size.
+     */
+    var resetTableSize = function () {
+        var queueListingGrid = $('#queue-listing-table').data('gridInstance');
+        if (nf.Common.isDefinedAndNotNull(queueListingGrid)) {
+            queueListingGrid.resizeCanvas();
+        }
+    };
+
+    return {
+        init: function () {
+            initializeListingRequestStatusDialog();
+            initFlowFileDetailsDialog();
+
+            // listen for browser resize events to update the page size
+            $(window).resize(function () {
+                resetTableSize();
+            });
+
+            // define a custom formatter for showing more processor details
+            var moreDetailsFormatter = function (row, cell, value, columnDef, 
dataContext) {
+                return '<img src="images/iconDetails.png" title="View Details" 
class="pointer show-flowfile-details" style="margin-top: 5px; float: left;"/>';
+            };
+
+            // function for formatting data sizes
+            var dataSizeFormatter = function (row, cell, value, columnDef, 
dataContext) {
+                return nf.Common.formatDataSize(value);
+            };
+
+            // function for formatting durations
+            var formatDuration = function (row, cell, value, columnDef, 
dataContext) {
+                return nf.Common.formatDuration(value);
+            }
+
+            // function for formatting the actions column
+            var actionFormatter = function (row, cell, value, columnDef, 
dataContext) {
+                return '<img src="images/iconDelete.png" title="Delete 
FlowFile" class="pointer delete-flowfile" style="margin-top: 2px;"/>';
+            };
+
+            // initialize the queue listing table
+            var flowFileListingColumns = [
+                {id: 'moreDetails', field: 'moreDetails', name: '&nbsp;', 
resizable: false, formatter: moreDetailsFormatter, sortable: true, width: 50, 
maxWidth: 50},
+                {id: 'QUEUE_POSITION', name: 'Position', field: 'position', 
sortable: true, resizable: true},
+                {id: 'FLOWFILE_UUID', name: 'UUID', field: 'uuid', sortable: 
true, resizable: true},
+                {id: 'FILENAME', name: 'Filename', field: 'filename', 
sortable: true, resizable: true},
+                {id: 'FLOWFILE_SIZE', name: 'File Size', field: 'size', 
sortable: true, resizable: true, defaultSortAsc: false, formatter: 
dataSizeFormatter},
+                {id: 'QUEUED_DURATION', name: 'Queued Duration', field: 
'queuedDuration', sortable: true, resizable: true, formatter: formatDuration},
+                {id: 'FLOWFILE_AGE', name: 'Lineage Duration', field: 
'lineageDuration', sortable: true, resizable: true, formatter: formatDuration},
+                {id: 'PENALIZATION', name: 'Penalized', field: 'penalized', 
sortable: true, resizable: true},
+                {id: 'actions', name: '&nbsp;', sortable: false, resizable: 
false, formatter: actionFormatter, width: 100, maxWidth: 100}
+            ];
+
+            var queueListingOptions = {
+                forceFitColumns: true,
+                enableTextSelectionOnCells: true,
+                enableCellNavigation: false,
+                enableColumnReorder: false,
+                autoEdit: false
+            };
+
+            // initialize the dataview
+            var queueListingData = new Slick.Data.DataView({
+                inlineFilters: false
+            });
+            queueListingData.setItems([]);
+
+            // initialize the grid
+            var queueListingGrid = new Slick.Grid('#queue-listing-table', 
queueListingData, flowFileListingColumns, queueListingOptions);
+            queueListingGrid.setSelectionModel(new Slick.RowSelectionModel());
+            queueListingGrid.registerPlugin(new Slick.AutoTooltips());
+            queueListingGrid.setSortColumn(DEFAULT_SORT_COL, DEFAULT_SORT_ASC);
+            queueListingGrid.onSort.subscribe(function (e, args) {
+                var connection = $('#queue-listing-table').data('connection');
+                performListing(connection, args.sortCol.id, args.sortAsc);
+            });
+
+            // configure a click listener
+            queueListingGrid.onClick.subscribe(function (e, args) {
+                var target = $(e.target);
+
+                // get the node at this row
+                var item = queueListingData.getItem(args.row);
+
+                // determine the desired action
+                if (queueListingGrid.getColumns()[args.cell].id === 
'moreDetails') {
+                    if (target.hasClass('show-flowfile-details')) {
+                        showFlowFileDetails(item);
+                    }
+                } else if (queueListingGrid.getColumns()[args.cell].id === 
'actions') {
+                    if (target.hasClass('delete-flowfile')) {
+                        deleteFlowfile(item);
+                    }
+                }
+            });
+
+            // wire up the dataview to the grid
+            queueListingData.onRowCountChanged.subscribe(function (e, args) {
+                queueListingGrid.updateRowCount();
+                queueListingGrid.render();
+
+                // update the total number of displayed processors
+                $('#displayed-flowfiles').text(args.current);
+            });
+            queueListingData.onRowsChanged.subscribe(function (e, args) {
+                queueListingGrid.invalidateRows(args.rows);
+                queueListingGrid.render();
+            });
+
+            // hold onto an instance of the grid
+            $('#queue-listing-table').data('gridInstance', queueListingGrid);
+
+            // initialize the number of display items
+            $('#displayed-flowfiles').text('0');
+        },
+
+        /**
+         * Shows the listing of the FlowFiles from a given connection.
+         *
+         * @param   {object}    The connection
+         */
+        listQueue: function (connection) {
+            // show the listing container
+            nf.Shell.showContent('#queue-listing-container').done(function () {
+                $('#queue-listing-table').removeData('connection');
+            });
+
+            // adjust the table size
+            resetTableSize();
+
+            // store the connection for access later
+            $('#queue-listing-table').data('connection', connection);
+
+            // perform the initial listing
+            performListing(connection, DEFAULT_SORT_COL, DEFAULT_SORT_ASC);
+        }
+    };
+}());
\ No newline at end of file

Reply via email to