Repository: nifi Updated Branches: refs/heads/NIFI-108 0676165e0 -> cd50dbc59
NIFI-108: - Adding initial support for viewing flowfile details dialog. - Adding initial support for click to content. Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/cd50dbc5 Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/cd50dbc5 Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/cd50dbc5 Branch: refs/heads/NIFI-108 Commit: cd50dbc59a9f22a4af63a7d509c36e92422d1811 Parents: 0676165 Author: Matt Gilman <[email protected]> Authored: Mon Dec 21 11:32:09 2015 -0500 Committer: Matt Gilman <[email protected]> Committed: Mon Dec 21 11:32:09 2015 -0500 ---------------------------------------------------------------------- .../apache/nifi/web/api/dto/FlowFileDTO.java | 91 ++++++++++++ .../nifi/web/StandardNiFiContentAccess.java | 52 +++++-- .../org/apache/nifi/web/api/dto/DtoFactory.java | 13 ++ .../src/main/webapp/WEB-INF/pages/canvas.jsp | 2 + .../partials/canvas/flowfile-details-dialog.jsp | 114 ++++++++++++++ .../src/main/webapp/css/queue-listing.css | 137 +++++++++++++++++ .../src/main/webapp/js/nf/canvas/nf-canvas.js | 5 + .../webapp/js/nf/canvas/nf-queue-listing.js | 147 ++++++++++++++++--- .../src/main/webapp/js/nf/nf-common.js | 10 ++ .../js/nf/provenance/nf-provenance-table.js | 12 +- 10 files changed, 539 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java index 95e91ef..98f60e8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java @@ -26,6 +26,13 @@ public class FlowFileDTO extends FlowFileSummaryDTO { private Map<String, String> attributes; + private String contentClaimSection; + private String contentClaimContainer; + private String contentClaimIdentifier; + private Long contentClaimOffset; + private String contentClaimFileSize; + private Long contentClaimFileSizeBytes; + /** * @return the FlowFile attributes */ @@ -39,4 +46,88 @@ public class FlowFileDTO extends FlowFileSummaryDTO { public void setAttributes(Map<String, String> attributes) { this.attributes = attributes; } + + /** + * @return the Section in which the Content Claim lives, or <code>null</code> if no Content Claim exists + */ + @ApiModelProperty( + value = "The section in which the content claim lives." + ) + public String getContentClaimSection() { + return contentClaimSection; + } + + public void setContentClaimSection(String contentClaimSection) { + this.contentClaimSection = contentClaimSection; + } + + /** + * @return the Container in which the Content Claim lives, or <code>null</code> if no Content Claim exists + */ + @ApiModelProperty( + value = "The container in which the content claim lives." + ) + public String getContentClaimContainer() { + return contentClaimContainer; + } + + public void setContentClaimContainer(String contentClaimContainer) { + this.contentClaimContainer = contentClaimContainer; + } + + /** + * @return the Identifier of the Content Claim, or <code>null</code> if no Content Claim exists + */ + @ApiModelProperty( + value = "The identifier of the content claim." + ) + public String getContentClaimIdentifier() { + return contentClaimIdentifier; + } + + public void setContentClaimIdentifier(String contentClaimIdentifier) { + this.contentClaimIdentifier = contentClaimIdentifier; + } + + /** + * @return the offset into the the Content Claim where the FlowFile's content begins, or <code>null</code> if no Content Claim exists + */ + @ApiModelProperty( + value = "The offset into the content claim where the flowfiles content begins." + ) + public Long getContentClaimOffset() { + return contentClaimOffset; + } + + public void setContentClaimOffset(Long contentClaimOffset) { + this.contentClaimOffset = contentClaimOffset; + } + + /** + * @return the formatted file size of the content claim + */ + @ApiModelProperty( + value = "The file size of the content claim formatted." + ) + public String getContentClaimFileSize() { + return contentClaimFileSize; + } + + public void setContentClaimFileSize(String contentClaimFileSize) { + this.contentClaimFileSize = contentClaimFileSize; + } + + /** + * @return the number of bytes of the content claim + */ + @ApiModelProperty( + value = "The file size of the content claim in bytes." + ) + public Long getContentClaimFileSizeBytes() { + return contentClaimFileSizeBytes; + } + + public void setContentClaimFileSizeBytes(Long contentClaimFileSizeBytes) { + this.contentClaimFileSizeBytes = contentClaimFileSizeBytes; + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java index 2f75004..f994c52 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java @@ -25,6 +25,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.MultivaluedMap; import org.apache.commons.lang3.StringUtils; @@ -51,6 +53,12 @@ public class StandardNiFiContentAccess implements ContentAccess { private static final Logger logger = LoggerFactory.getLogger(StandardNiFiContentAccess.class); public static final String CLIENT_ID_PARAM = "clientId"; + private static final Pattern FLOWFILE_CONTENT_URI_PATTERN = Pattern + .compile("/controller/process-groups/((?:root)|(?:[a-f0-9\\-]{36}))/connections/([a-f0-9\\-]{36})/flowfiles/([a-f0-9\\-]{36})/content"); + + private static final Pattern PROVENANCE_CONTENT_URI_PATTERN = Pattern + .compile("/controller/provenance/events/([0-9]+)/content/((?:input)|(?:output))"); + private NiFiProperties properties; private NiFiServiceFacade serviceFacade; private WebClusterManager clusterManager; @@ -115,21 +123,41 @@ public class StandardNiFiContentAccess implements ContentAccess { // create the downloadable content return new DownloadableContent(filename, contentType, clientResponse.getEntityInputStream()); } else { - // example URI: http://localhost:8080/nifi-api/controller/provenance/events/1/content/input - final String eventDetails = StringUtils.substringAfterLast(request.getDataUri(), "events/"); - final String rawEventId = StringUtils.substringBefore(eventDetails, "/content/"); - final String rawDirection = StringUtils.substringAfterLast(eventDetails, "/content/"); + // example URIs: + // http://localhost:8080/nifi-api/controller/provenance/events/{id}/content/{input|output} + // http://localhost:8080/nifi-api/controller/process-groups/{root|uuid}/connections/{uuid}/flowfiles/{uuid}/content - // get the content type - final Long eventId; - final ContentDirection direction; - try { - eventId = Long.parseLong(rawEventId); - direction = ContentDirection.valueOf(rawDirection.toUpperCase()); - } catch (final IllegalArgumentException iae) { + // get just the context path for comparison + final String dataUri = StringUtils.substringAfter(request.getDataUri(), "/nifi-api"); + if (StringUtils.isBlank(dataUri)) { throw new IllegalArgumentException("The specified data reference URI is not valid."); } - return serviceFacade.getContent(eventId, request.getDataUri(), direction); + + // flowfile listing content + final Matcher flowFileMatcher = FLOWFILE_CONTENT_URI_PATTERN.matcher(dataUri); + if (flowFileMatcher.matches()) { + final String groupId = flowFileMatcher.group(1); + final String connectionId = flowFileMatcher.group(2); + final String flowfileId = flowFileMatcher.group(3); + + return serviceFacade.getContent(groupId, connectionId, flowfileId, dataUri); + } + + // provenance event content + final Matcher provenanceMatcher = PROVENANCE_CONTENT_URI_PATTERN.matcher(dataUri); + if (provenanceMatcher.matches()) { + try { + final Long eventId = Long.parseLong(provenanceMatcher.group(1)); + final ContentDirection direction = ContentDirection.valueOf(provenanceMatcher.group(2).toUpperCase()); + + return serviceFacade.getContent(eventId, dataUri, direction); + } catch (final IllegalArgumentException iae) { + throw new IllegalArgumentException("The specified data reference URI is not valid."); + } + } + + // invalid uri + throw new IllegalArgumentException("The specified data reference URI is not valid."); } } http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/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 22031bb..99bffc4 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 @@ -79,6 +79,8 @@ import org.apache.nifi.controller.queue.FlowFileSummary; import org.apache.nifi.controller.queue.ListFlowFileState; import org.apache.nifi.controller.queue.ListFlowFileStatus; import org.apache.nifi.controller.repository.FlowFileRecord; +import org.apache.nifi.controller.repository.claim.ContentClaim; +import org.apache.nifi.controller.repository.claim.ResourceClaim; import org.apache.nifi.controller.status.ConnectionStatus; import org.apache.nifi.controller.status.PortStatus; import org.apache.nifi.controller.status.ProcessGroupStatus; @@ -443,6 +445,17 @@ public final class DtoFactory { final long age = now.getTime() - record.getLineageStartDate(); dto.setLineageDuration(age); + final ContentClaim contentClaim = record.getContentClaim(); + if (contentClaim != null) { + final ResourceClaim resourceClaim = contentClaim.getResourceClaim(); + dto.setContentClaimSection(resourceClaim.getSection()); + dto.setContentClaimContainer(resourceClaim.getContainer()); + dto.setContentClaimIdentifier(resourceClaim.getId()); + dto.setContentClaimOffset(contentClaim.getOffset()); + dto.setContentClaimFileSizeBytes(contentClaim.getLength()); + dto.setContentClaimFileSize(FormatUtils.formatDataSize(contentClaim.getLength())); + } + return dto; } http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/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 337b2b0..5a9eab7 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,11 +119,13 @@ <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/flowfile-details-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> <div id="context-menu" class="unselectable"></div> + <span id="nifi-content-viewer-url" class="hidden"></span> </body> </html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flowfile-details-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/flowfile-details-dialog.jsp b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flowfile-details-dialog.jsp new file mode 100644 index 0000000..cead866 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/WEB-INF/partials/canvas/flowfile-details-dialog.jsp @@ -0,0 +1,114 @@ +<%-- + 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="flowfile-details-dialog"> + <div id="flowfile-details-dialog-content"> + <div id="flowfile-details-tabs"></div> + <div id="flowfile-details-tabs-content"> + <div id="flowfile-details-tab-content" class="details-tab"> + <span id="flowfile-uri" class="hidden"></span> + <span id="flowfile-cluster-node-id" class="hidden"></span> + <div class="settings-left"> + <div id="flowfile-details"> + <div class="flowfile-header">FlowFile Details</div> + <div class="flowfile-detail"> + <div class="detail-name">UUID</div> + <div id="flowfile-uuid" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">Filename</div> + <div id="flowfile-filename" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">File Size</div> + <div id="flowfile-file-size" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">Queue Position</div> + <div id="flowfile-queue-position" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">Queued Duration</div> + <div id="flowfile-queued-duration" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">Lineage Duration</div> + <div id="flowfile-lineage-duration" class="detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="detail-name">Penalized</div> + <div id="flowfile-penalized" class="detail-value"></div> + <div class="clear"></div> + </div> + <div id="additional-flowfile-details"></div> + </div> + </div> + <div class="spacer"> </div> + <div class="settings-right"> + <div id="flowfile-content-details" class="content-details"> + <div class="flowfile-header">Content Claim</div> + <div class="flowfile-detail"> + <div class="content-detail-name">Container</div> + <div id="content-container" class="content-detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="content-detail-name">Section</div> + <div id="content-section" class="content-detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="content-detail-name">Identifier</div> + <div id="content-identifier" class="content-detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="content-detail-name">Offset</div> + <div id="content-offset" class="content-detail-value"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div class="content-detail-name">Size</div> + <div id="content-size" class="content-detail-value"></div> + <div id="content-bytes" class="content-detail-value hidden"></div> + <div class="clear"></div> + </div> + <div class="flowfile-detail"> + <div id="content-download" class="button">Download</div> + <div id="content-view" class="button hidden">View</div> + <div class="clear"></div> + </div> + </div> + </div> + <div class="clear"></div> + </div> + <div id="flowfile-attributes-tab-content" class="details-tab"> + <div id="flowfile-attributes-details"> + <div id="flowfile-attributes-header" class="flowfile-header">Attribute Values</div> + <div class="clear"></div> + <div id="flowfile-attributes-container"></div> + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/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 index 2d7205e..689ceaf 100644 --- 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 @@ -76,3 +76,140 @@ border: 1px solid #666; overflow: hidden; } + +/* flowfile details */ + +#flowfile-details-dialog { + display: none; + width: 800px; + height: 450px; + z-index: 1301; +} + +#flowfile-details-dialog-content { + margin-top: -10px; + padding: 5px 11px +} + +#flowfile-details-tabs { + background-color: transparent; + border-bottom: 3px solid #666666; + height: 21px; + width: 778px; +} + +#flowfile-details-dialog div.details-tab { + background: url("../images/bgTabContainer.png") repeat-x scroll 0 0 #EEEEEE; + display: none; + height: 330px; + padding: 10px; +} + +#flowfile-details-tab-content div.settings-left { + float: left; + width: 420px; +} + +#flowfile-details-tab-content div.spacer { + float: left; + margin-right: 40px; +} + +#flowfile-details-tab-content div.settings-right { + float: left; + width: 292px; +} + +div.flowfile-header { + color: #264C58; + font-size: 11px; + font-weight: bold; + margin-bottom: 5px; +} + +#flowfile-attributes-container { + height: 290px; + overflow: auto; + border: 1px solid #aaa; + padding: 5px; +} + +div.detail-name { + float: left; + width: 145px; + color: #527991; + font-size: 10px; + font-weight: bold; + overflow: hidden; + white-space: nowrap; + line-height: normal; +} + +div.detail-value { + float: left; + width: 270px; + overflow: hidden; + white-space: nowrap; + line-height: normal; +} + +div.attribute-detail { + margin-bottom: 5px; +} + +div.attribute-name { + float: left; + width: 225px; + color: #527991; + font-size: 10px; + font-weight: bold; + overflow: hidden; + white-space: nowrap; + line-height: normal; +} + +div.attribute-value { + float: left; + width: 490px; + margin-left: 10px; + overflow: hidden; + white-space: nowrap; + line-height: normal; +} + +#flowfile-attributes-header { + float: left; +} + +div.flowfile-detail { + margin-bottom: 4px; +} + +#content-download { + float: left; + margin: 0; +} + +#content-view { + float: left; + margin-left: 5px; +} + +div.content-detail-name { + color: #527991; + float: left; + font-size: 10px; + font-weight: bold; + line-height: normal; + overflow: hidden; + white-space: nowrap; + width: 90px; +} + +div.content-detail-value { + width: 200px; + float: left; + line-height: normal; + overflow: hidden; + white-space: nowrap; +} http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/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 25d7255..005f7e3 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 @@ -1122,6 +1122,11 @@ nf.Canvas = (function () { var configDetails = configResponse.config; var loginDetails = loginResponse.config; + // store the content viewer url if available + if (!nf.Common.isBlank(configDetails.contentViewerUrl)) { + $('#nifi-content-viewer-url').text(configDetails.contentViewerUrl); + } + // when both request complete, load the application isClusteredRequest.done(function () { // get the auto refresh interval http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/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 index cba598a..b0bba1f 100644 --- 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 @@ -55,39 +55,30 @@ nf.QueueListing = (function () { }; /** - * Downloads the content for the provenance event that is currently loaded in the specified direction. - * - * @param {string} direction + * Downloads the content for the flowfile currently being viewed. */ - 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); + var downloadContent = function () { + var dataUri = $('#flowfile-uri').text() + '/content'; // conditionally include the cluster node id - var clusterNodeId = $('#provenance-event-cluster-node-id').text(); + var clusterNodeId = $('#flowfile-cluster-node-id').text(); if (!nf.Common.isBlank(clusterNodeId)) { - window.open(url + '?' + $.param({ + window.open(dataUri + '?' + $.param({ 'clusterNodeId': clusterNodeId })); } else { - window.open(url); + window.open(dataUri); } }; /** - * Views the content for the provenance event that is currently loaded in the specified direction. - * - * @param {string} direction + * Views the content for the flowfile currently being viewed. */ - var viewContent = function (direction) { - - // build the uri to the data - var dataUri = controllerUri + '/provenance/events/' + encodeURIComponent(eventId) + '/content/' + encodeURIComponent(direction); + var viewContent = function () { + var dataUri = $('#flowfile-uri').text() + '/content'; // conditionally include the cluster node id - var clusterNodeId = $('#provenance-event-cluster-node-id').text(); + var clusterNodeId = $('#flowfile-cluster-node-id').text();; if (!nf.Common.isBlank(clusterNodeId)) { var parameters = { 'clusterNodeId': clusterNodeId @@ -118,7 +109,46 @@ nf.QueueListing = (function () { * Initializes the flowfile details dialog. */ var initFlowFileDetailsDialog = function () { + $('#content-download').on('click', downloadContent); + + // only show if content viewer is configured + if (nf.Common.isContentViewConfigured()) { + $('#content-view').show(); + $('#content-view').on('click', viewContent); + } + + $('#flowfile-details-tabs').tabbs({ + tabStyle: 'tab', + selectedTabStyle: 'selected-tab', + tabs: [{ + name: 'Details', + tabContentId: 'flowfile-details-tab-content' + }, { + name: 'Attributes', + tabContentId: 'flowfile-attributes-tab-content' + }] + }); + $('#flowfile-details-dialog').modal({ + headerText: 'FlowFile', + overlayBackground: false, + buttons: [{ + buttonText: 'Ok', + handler: { + click: function () { + $('#flowfile-details-dialog').modal('hide'); + } + } + }], + handler: { + close: function () { + // clear the details + $('#flowfile-attributes-container').empty(); + $('#flowfile-cluster-node-id').text(''); + $('#additional-flowfile-details').empty(); + } + } + }); }; /** @@ -129,7 +159,6 @@ nf.QueueListing = (function () { * @param sortAsc if sort is asc */ var performListing = function (connection, sortCol, sortAsc) { - var MAX_DELAY = 4; var cancelled = false; var listingRequest = null; @@ -270,15 +299,91 @@ nf.QueueListing = (function () { * @param flowFileSummary the flowfile summary */ var showFlowFileDetails = function (flowFileSummary) { + // formats an flowfile detail + var formatFlowFileDetail = function (label, value) { + $('<div class="flowfile-detail"></div>').append( + $('<div class="detail-name"></div>').text(label)).append( + $('<div class="detail-value">' + nf.Common.formatValue(value) + '</div>').ellipsis()).append( + $('<div class="clear"></div>')).appendTo('#additional-flowfile-details'); + }; + + // formats the content value + var formatContentValue = function (element, value) { + if (nf.Common.isDefinedAndNotNull(value)) { + element.removeClass('unset').text(value); + } else { + element.addClass('unset').text('No value set'); + } + }; + $.ajax({ type: 'GET', url: flowFileSummary.uri, dataType: 'json' }).done(function(response) { - var flowFile = response.flowfile; + var flowFile = response.flowFile; + + // show the URI to this flowfile + $('#flowfile-uri').text(flowFile.uri); // show the flowfile details dialog + $('#flowfile-uuid').html(nf.Common.formatValue(flowFile.uuid)); + $('#flowfile-filename').html(nf.Common.formatValue(flowFile.filename)); + $('#flowfile-queue-position').html(nf.Common.formatValue(flowFile.position)); + $('#flowfile-file-size').html(nf.Common.formatValue(flowFile.contentClaimFileSize)); + $('#flowfile-queued-duration').text(nf.Common.formatDuration(flowFile.queuedDuration)); + $('#flowfile-lineage-duration').text(nf.Common.formatDuration(flowFile.lineageDuration)); + $('#flowfile-penalized').text(flowFile.penalized === true ? 'Yes' : 'No'); + + // conditionally show the cluster node identifier + if (nf.Common.isDefinedAndNotNull(flowFile.clusterNodeId)) { + // save the cluster node id + $('#flowfile-cluster-node-id').text(flowFile.clusterNodeId); + + // render the cluster node address + formatFlowFileDetail('Node Address', flowFile.clusterNodeAddress); + } + + if (nf.Common.isDefinedAndNotNull(flowFile.contentClaimContainer)) { + // content claim + formatContentValue($('#content-container'), flowFile.contentClaimContainer); + formatContentValue($('#content-section'), flowFile.contentClaimSection); + formatContentValue($('#content-identifier'), flowFile.contentClaimIdentifier); + formatContentValue($('#content-offset'), flowFile.contentClaimOffset); + formatContentValue($('#content-bytes'), flowFile.contentClaimFileSizeBytes); + + // input content file size + var contentSize = $('#content-size'); + formatContentValue(contentSize, flowFile.contentClaimFileSize); + if (nf.Common.isDefinedAndNotNull(flowFile.contentClaimFileSize)) { + // over the default tooltip with the actual byte count + contentSize.attr('title', nf.Common.formatInteger(flowFile.contentClaimFileSizeBytes) + ' bytes'); + } + + // show the content details + $('#flowfile-content-details').show(); + } else { + $('#flowfile-content-details').hide(); + } + + // attributes + var attributesContainer = $('#flowfile-attributes-container'); + + // get any action details + $.each(flowFile.attributes, function (attributeName, attributeValue) { + // create the attribute record + var attributeRecord = $('<div class="attribute-detail"></div>') + .append($('<div class="attribute-name">' + nf.Common.formatValue(attributeName) + '</div>').ellipsis()) + .appendTo(attributesContainer); + + // add the current value + attributeRecord + .append($('<div class="attribute-value">' + nf.Common.formatValue(attributeValue) + '</div>').ellipsis()) + .append('<div class="clear"></div>'); + }); + // show the dialog + $('#flowfile-details-dialog').modal('show'); }).fail(nf.Common.handleAjaxError); }; http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js index cf83e16..6b4a5ea 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-common.js @@ -463,6 +463,16 @@ nf.Common = (function () { }, /** + * Returns whether a content viewer has been configured. + * + * @returns {boolean} + */ + isContentViewConfigured: function () { + var contentViewerUrl = $('#nifi-content-viewer-url').text(); + return !nf.Common.isBlank(contentViewerUrl); + }, + + /** * Populates the specified field with the specified value. If the value is * undefined, the field will read 'No value set.' If the value is an empty * string, the field will read 'Empty string set.' http://git-wip-us.apache.org/repos/asf/nifi/blob/cd50dbc5/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js index faa6adc..0ea44b2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance-table.js @@ -70,16 +70,6 @@ nf.ProvenanceTable = (function () { }; /** - * Returns whether a content viewer has been configured. - * - * @returns {boolean} - */ - var isContentViewConfigured = function () { - var contentViewerUrl = $('#nifi-content-viewer-url').text(); - return !nf.Common.isBlank(contentViewerUrl); - }; - - /** * Downloads the content for the provenance event that is currently loaded in the specified direction. * * @param {string} direction @@ -206,7 +196,7 @@ nf.ProvenanceTable = (function () { }); // if a content viewer url is specified, use it - if (isContentViewConfigured()) { + if (nf.Common.isContentViewConfigured()) { // input view $('#input-content-view').on('click', function () { viewContent('input');
