NIFI-2182:

- Ensuring the active thread count is shown.
NIFI-2019:
- Ensuring correct color of the run status in the From connection label.
NIFI-2183:
- Removing the DownloadSvg servlet and hidding the download icon until we're able to support save the svg entirely from the client side.

This closes #634.
This commit is contained in:
Matt Gilman 2016-07-12 19:24:11 -04:00 committed by Mark Payne
parent 8ab9fca7f8
commit 1e1630cc69
8 changed files with 68 additions and 199 deletions

View File

@ -1,88 +0,0 @@
/*
* 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.
*/
package org.apache.nifi.web.servlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
*
*/
public class DownloadSvg extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(DownloadSvg.class);
/**
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final String svg = request.getParameter("svg");
// ensure the image markup has been included
if (svg == null) {
// set the response status
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
// write the response message
PrintWriter out = response.getWriter();
out.println("SVG must be specified.");
return;
}
try {
if (logger.isDebugEnabled()) {
logger.debug(svg);
}
String filename = request.getParameter("filename");
if (filename == null) {
filename = "image.svg";
} else if (!filename.endsWith(".svg")) {
filename += ".svg";
}
response.setContentType("image/svg+xml");
response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(svg);
} catch (final Exception e) {
logger.error(e.getMessage(), e);
// set the response status
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
// write the response message
PrintWriter out = response.getWriter();
out.println("Unable to export image as a SVG.");
}
}
}

View File

@ -56,7 +56,7 @@
<div id="provenance-lineage-loading" class="loading-container"></div> <div id="provenance-lineage-loading" class="loading-container"></div>
</div> </div>
<div id="provenance-lineage-close-container"> <div id="provenance-lineage-close-container">
<div id="provenance-lineage-downloader" title="Download"></div> <div id="provenance-lineage-downloader" class="hidden" title="Download"></div>
<div id="provenance-lineage-closer" title="Close"></div> <div id="provenance-lineage-closer" title="Close"></div>
</div> </div>
<div id="provenance-lineage-context-menu"></div> <div id="provenance-lineage-context-menu"></div>

View File

@ -116,16 +116,6 @@
<url-pattern>/message</url-pattern> <url-pattern>/message</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- servlet to support image downloading -->
<servlet>
<servlet-name>DownloadSvg</servlet-name>
<servlet-class>org.apache.nifi.web.servlet.DownloadSvg</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadSvg</servlet-name>
<url-pattern>/download-svg</url-pattern>
</servlet-mapping>
<!-- servlet to login page --> <!-- servlet to login page -->
<servlet> <servlet>
<servlet-name>Login</servlet-name> <servlet-name>Login</servlet-name>

View File

@ -427,11 +427,11 @@ nf.CanvasUtils = (function () {
*/ */
activeThreadCount: function (selection, d, setOffset) { activeThreadCount: function (selection, d, setOffset) {
// if there is active threads show the count, otherwise hide // if there is active threads show the count, otherwise hide
if (nf.Common.isDefinedAndNotNull(d.status) && d.status.activeThreadCount > 0) { if (nf.Common.isDefinedAndNotNull(d.status) && d.status.aggregateSnapshot.activeThreadCount > 0) {
// update the active thread count // update the active thread count
var activeThreadCount = selection.select('text.active-thread-count') var activeThreadCount = selection.select('text.active-thread-count')
.text(function () { .text(function () {
return d.status.activeThreadCount; return d.status.aggregateSnapshot.activeThreadCount;
}) })
.style('display', 'block') .style('display', 'block')
.each(function () { .each(function () {

View File

@ -787,7 +787,7 @@ nf.Connection = (function () {
} }
}) })
.classed('is-missing-port', function () { .classed('is-missing-port', function () {
return d.component.source.exists === true; return d.component.source.exists === false;
}); });
} else { } else {
// there is no connection from, but check if the name was previous // there is no connection from, but check if the name was previous

View File

@ -250,7 +250,7 @@ nf.Port = (function () {
details.append('text') details.append('text')
.attr({ .attr({
'class': 'active-thread-count-icon', 'class': 'active-thread-count-icon',
'y': 68 'y': 43 + offset
}) })
.text('\ue83f'); .text('\ue83f');
@ -258,7 +258,7 @@ nf.Port = (function () {
details.append('text') details.append('text')
.attr({ .attr({
'class': 'active-thread-count', 'class': 'active-thread-count',
'y': 68 'y': 43 + offset
}); });
} }

View File

@ -724,41 +724,6 @@ nf.Common = (function () {
} }
}, },
/**
* Creates a form inline in order to submit the specified params to the specified URL
* using the specified method.
*
* @param {string} url The URL
* @param {object} params An object with the params to include in the submission
*/
post: function (url, params) {
// temporarily override beforeunload
var previousBeforeUnload = window.onbeforeunload;
window.onbeforeunload = null;
// create a form for submission
var form = $('<form></form>').attr({
'method': 'POST',
'action': url,
'style': 'display: none;'
});
// add each parameter when specified
if (nf.Common.isDefinedAndNotNull(params)) {
$.each(params, function (name, value) {
$('<textarea></textarea>').attr('name', name).val(value).appendTo(form);
});
}
// submit the form and clean up
form.appendTo('body').submit().remove();
// restore previous beforeunload if necessary
if (previousBeforeUnload !== null) {
window.onbeforeunload = previousBeforeUnload;
}
},
/** /**
* Formats the specified array as an unordered list. If the array is not an * Formats the specified array as an unordered list. If the array is not an
* array, null is returned. * array, null is returned.

View File

@ -1237,67 +1237,69 @@ nf.ProvenanceLineage = (function () {
$('#provenance-event-search').show(); $('#provenance-event-search').show();
$('#provenance-lineage').hide(); $('#provenance-lineage').hide();
}); });
$('#provenance-lineage-downloader').on('click', function () {
var svg = $('#provenance-lineage-container').html();
// get the lineage to determine the actual dimensions // TODO - restore this as necessary when able to download lineage svg entirely client side
var lineage = $('g.lineage')[0]; // $('#provenance-lineage-downloader').on('click', function () {
var bbox = lineage.getBBox(); // var svg = $('#provenance-lineage-container').html();
//
// adjust to provide some padding // // get the lineage to determine the actual dimensions
var height = bbox.height + 30; // var lineage = $('g.lineage')[0];
var width = bbox.width + 30; // var bbox = lineage.getBBox();
var offsetX = bbox.x - 15; //
var offsetY = bbox.y - 15; // // adjust to provide some padding
// var height = bbox.height + 30;
// replace the svg height, width with the actual values // var width = bbox.width + 30;
svg = svg.replace(/height=".*?"/, 'height="' + height + '"'); // var offsetX = bbox.x - 15;
svg = svg.replace(/width=".*?"/, 'width="' + width + '"'); // var offsetY = bbox.y - 15;
//
// remove any transform applied to the lineage // // replace the svg height, width with the actual values
svg = svg.replace(/transform=".*?"/, ''); // svg = svg.replace(/height=".*?"/, 'height="' + height + '"');
// svg = svg.replace(/width=".*?"/, 'width="' + width + '"');
// adjust link positioning based on the offset of the bounding box //
svg = svg.replace(/<path([^>]*?)d="M[\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?L[\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?"(.*?)>/g, function (match, before, rawMoveX, rawMoveY, rawLineX, rawLineY, after) { // // remove any transform applied to the lineage
// this regex captures the content before and after the d attribute in order to ensure that it contains the link class. // svg = svg.replace(/transform=".*?"/, '');
// within the svg image, there are other paths that are (within markers) that we do not want to offset //
if (before.indexOf('link') === -1 && after.indexOf('link') === -1) { // // adjust link positioning based on the offset of the bounding box
return match; // svg = svg.replace(/<path([^>]*?)d="M[\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?L[\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?"(.*?)>/g, function (match, before, rawMoveX, rawMoveY, rawLineX, rawLineY, after) {
} // // this regex captures the content before and after the d attribute in order to ensure that it contains the link class.
// // within the svg image, there are other paths that are (within markers) that we do not want to offset
var moveX = parseFloat(rawMoveX) - offsetX; // if (before.indexOf('link') === -1 && after.indexOf('link') === -1) {
var moveY = parseFloat(rawMoveY) - offsetY; // return match;
var lineX = parseFloat(rawLineX) - offsetX; // }
var lineY = parseFloat(rawLineY) - offsetY; //
return '<path' + before + 'd="M' + moveX + ',' + moveY + 'L' + lineX + ',' + lineY + '"' + after + '>'; // var moveX = parseFloat(rawMoveX) - offsetX;
}); // var moveY = parseFloat(rawMoveY) - offsetY;
// var lineX = parseFloat(rawLineX) - offsetX;
// adjust node positioning based on the offset of the bounding box // var lineY = parseFloat(rawLineY) - offsetY;
svg = svg.replace(/<g([^>]*?)transform="translate\([\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?\)"(.*?)>/g, function (match, before, rawX, rawY, after) { // return '<path' + before + 'd="M' + moveX + ',' + moveY + 'L' + lineX + ',' + lineY + '"' + after + '>';
// this regex captures the content before and after the transform attribute in order to ensure that it contains the // });
// node class. only node groups are translated with absolute coordinates since all other translated groups fall under //
// a parent that is already positioned. this makes their translation relative and not appropriate for this adjustment // // adjust node positioning based on the offset of the bounding box
if (before.indexOf('node') === -1 && after.indexOf('node') === -1) { // svg = svg.replace(/<g([^>]*?)transform="translate\([\s]?([^\s]+?)[\s,]([^\s]+?)[\s]?\)"(.*?)>/g, function (match, before, rawX, rawY, after) {
return match; // // this regex captures the content before and after the transform attribute in order to ensure that it contains the
} // // node class. only node groups are translated with absolute coordinates since all other translated groups fall under
// // a parent that is already positioned. this makes their translation relative and not appropriate for this adjustment
var x = parseFloat(rawX) - offsetX; // if (before.indexOf('node') === -1 && after.indexOf('node') === -1) {
var y = parseFloat(rawY) - offsetY; // return match;
return '<g' + before + 'transform="translate(' + x + ',' + y + ')"' + after + '>'; // }
}); //
// var x = parseFloat(rawX) - offsetX;
// namespaces // var y = parseFloat(rawY) - offsetY;
svg = svg.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"'); // return '<g' + before + 'transform="translate(' + x + ',' + y + ')"' + after + '>';
// });
// doctype //
svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + svg; // // namespaces
// svg = svg.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"');
// send to server to initiate download... client side only support is too browser specific at this point //
nf.Common.post('./download-svg', { // // doctype
'filename': 'provenance', // svg = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + svg;
'svg': svg //
}); // // send to server to initiate download... client side only support is too browser specific at this point
}); // nf.Common.post('./download-svg', {
// 'filename': 'provenance',
// 'svg': svg
// });
// });
initLineageQueryDialog(); initLineageQueryDialog();
}, },