NIFI-1781:
- Incorporating updated styles to reflect component level authorization. - Updating canvas for new look and feel. - This closes #417
|
@ -17,6 +17,7 @@
|
|||
package org.apache.nifi.web.api.entity;
|
||||
|
||||
import org.apache.nifi.web.api.dto.ProcessorDTO;
|
||||
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
|
@ -27,6 +28,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
public class ProcessorEntity extends ComponentEntity {
|
||||
|
||||
private ProcessorDTO component;
|
||||
private ProcessorStatusDTO status;
|
||||
|
||||
/**
|
||||
* The ProcessorDTO that is being serialized.
|
||||
|
@ -41,4 +43,16 @@ public class ProcessorEntity extends ComponentEntity {
|
|||
this.component = component;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Processor status.
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
public ProcessorStatusDTO getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(ProcessorStatusDTO status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -634,7 +634,7 @@ public class StatusMerger {
|
|||
}
|
||||
|
||||
public static String prettyPrint(final Integer count, final Long bytes) {
|
||||
return formatCount(count) + " / " + formatDataSize(bytes);
|
||||
return formatCount(count) + " (" + formatDataSize(bytes) + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<md-menu-item layout-align="space-around center">
|
||||
<a id="bulletin-board-link"
|
||||
ng-click="appCtrl.serviceProvider.headerCtrl.globalMenuCtrl.bulletinBoard.shell.launch();"><i
|
||||
class="icon icon-bulletin"></i>Bulletin Board</a>
|
||||
class="fa fa-sticky-note-o"></i>Bulletin Board</a>
|
||||
</md-menu-item>
|
||||
<md-menu-divider></md-menu-divider>
|
||||
<md-menu-item
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<div layout="row" layout-align="end center">
|
||||
<input id="search-field" type="text"/>
|
||||
<button id="search-button"><i class="fa fa-search"></i></button>
|
||||
<button id="bulletin-button"><i class="icon-bulletin"></i></button>
|
||||
<button id="bulletin-button"><i class="fa fa-sticky-note-o"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="search-flow-results"></div>
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
background-color:#728E9B; /*base-color*/
|
||||
}
|
||||
|
||||
#bulletin-button i{
|
||||
#bulletin-button i.fa {
|
||||
color: #fff;
|
||||
font-size:15px;
|
||||
}
|
||||
|
|
|
@ -53,16 +53,78 @@ text.unset {
|
|||
*/
|
||||
|
||||
g.component {
|
||||
font-family: Arial, sans-serif;
|
||||
font-family: Roboto;
|
||||
}
|
||||
|
||||
g.component rect.body {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
g.component rect.body.unauthorized {
|
||||
fill: #f4f6f7;
|
||||
}
|
||||
|
||||
g.component rect.border.unauthorized {
|
||||
stroke-width: 1.5;
|
||||
stroke: #ba554a;
|
||||
stroke-dasharray: 3,3;
|
||||
}
|
||||
|
||||
g.component.selected rect.border {
|
||||
stroke: #ffcc00;
|
||||
stroke-width: 5;
|
||||
stroke: #004849;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
g.funnel.selected rect.border {
|
||||
stroke-width: 2.5;
|
||||
text.stats-label {
|
||||
fill: #262626;
|
||||
font-size: 12px;
|
||||
font-family: Roboto Slab;
|
||||
}
|
||||
|
||||
text.stats-value {
|
||||
fill: #775351;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
text.stats-value tspan.size, text.stats-value tspan.size {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
text.stats-info {
|
||||
fill: #728E9B;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
text.bulletin-icon {
|
||||
font-size: 13px;
|
||||
font-family: FontAwesome;
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
rect.bulletin-background {
|
||||
fill: #728e9b;
|
||||
}
|
||||
|
||||
rect.bulletin-background.has-bulletins {
|
||||
fill: #ba554a;
|
||||
}
|
||||
|
||||
text.process-group-invalid.has-validation-errors {
|
||||
fill: #ba554a;
|
||||
}
|
||||
|
||||
text.active-thread-count-icon {
|
||||
font-family: flowfont;
|
||||
font-size: 12px;
|
||||
fill: #728e9b;
|
||||
text-anchor: end;
|
||||
}
|
||||
|
||||
text.active-thread-count {
|
||||
fill: #775351;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,19 +150,24 @@ image.add-connect {
|
|||
Processor
|
||||
*/
|
||||
|
||||
text.processor-stats-label {
|
||||
fill: #fff;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text.processor-name {
|
||||
fill: #262626;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
text.processor-stats-value {
|
||||
font-size: 11px;
|
||||
text.processor-type {
|
||||
fill: #728e9b;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
text.processor-stats-info {
|
||||
fill: #999999;
|
||||
font-size: 11px;
|
||||
text.processor-icon {
|
||||
fill: #ad9897;
|
||||
font-family: flowfont;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
text.run-status-icon {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -108,7 +175,27 @@ text.processor-stats-info {
|
|||
*/
|
||||
|
||||
g.connection {
|
||||
font-family: Arial, sans-serif;
|
||||
font-family: Roboto;
|
||||
}
|
||||
|
||||
g.connection rect.body {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
g.connection rect.body.unauthorized {
|
||||
fill: #f4f6f7;
|
||||
}
|
||||
|
||||
g.connection rect.border.unauthorized {
|
||||
stroke-width: 1.5;
|
||||
stroke: #ba554a;
|
||||
stroke-dasharray: 3,3;
|
||||
}
|
||||
|
||||
g.connection.selected rect.border {
|
||||
/*stroke: #004849;*/
|
||||
stroke: #ffcc00;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
path.connector {
|
||||
|
@ -126,12 +213,6 @@ path.connector.connectable {
|
|||
stroke-dasharray: 4;
|
||||
}
|
||||
|
||||
g.connection rect.connection-label {
|
||||
fill: #ffffff;
|
||||
stroke: #000000;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
g.connection path.connection-path {
|
||||
fill: none;
|
||||
stroke: #000000;
|
||||
|
@ -139,6 +220,21 @@ g.connection path.connection-path {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
g.connection path.connection-path.unauthorized {
|
||||
stroke: #ba554a;
|
||||
stroke-dasharray: 3,3;
|
||||
}
|
||||
|
||||
text.connection-from-run-status, text.connection-to-run-status {
|
||||
fill: #728e9b;
|
||||
font-family: FontAwesome;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
text.connection-from-run-status.is-missing-port, text.connection-to-run-status.is-missing-port {
|
||||
fill: #ba554a;
|
||||
}
|
||||
|
||||
/* grouped connection */
|
||||
|
||||
g.connection.grouped path.connection-path, g.connection.grouped rect.connection-label {
|
||||
|
@ -196,12 +292,6 @@ g.connection rect.endpoint {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
g.connection text.connection-stats-label {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
fill: #598599;
|
||||
}
|
||||
|
||||
/* labels */
|
||||
|
||||
g.label rect.labelpoint {
|
||||
|
@ -218,8 +308,30 @@ g.label.selected rect.labelpoint {
|
|||
|
||||
/* funnels */
|
||||
|
||||
text.funnel-icon {
|
||||
fill: #ad9897;
|
||||
font-family: flowfont;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
/* ports */
|
||||
|
||||
text.port-name {
|
||||
fill: #262626;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
text.port-icon {
|
||||
fill: #ad9897;
|
||||
font-family: flowfont;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
text.port-transmission-icon {
|
||||
font-size: 11px;
|
||||
fill: #728e9b
|
||||
}
|
||||
|
||||
/* active thread count */
|
||||
|
||||
text.active-thread-count {
|
||||
|
@ -228,35 +340,55 @@ text.active-thread-count {
|
|||
|
||||
/* process groups */
|
||||
|
||||
text.process-group-name {
|
||||
fill: #262626;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
text.process-group-contents-count {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
fill: #294c58;
|
||||
}
|
||||
|
||||
g.process-group.drop rect.border {
|
||||
stroke: #0000ff;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
text.process-group-contents-count {
|
||||
font-weight: bold;
|
||||
fill: #294c58;
|
||||
}
|
||||
|
||||
text.process-group-stats-label {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
fill: #598599;
|
||||
}
|
||||
|
||||
text.process-group-stats-value {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
text.process-group-stats-info {
|
||||
fill: #999999;
|
||||
font-size: 11px;
|
||||
text.process-group-contents-icon {
|
||||
font-size: 13px;
|
||||
fill: #728e9b;
|
||||
}
|
||||
|
||||
/* remote process group */
|
||||
|
||||
text.remote-process-group-name {
|
||||
fill: #262626;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
text.remote-process-group-uri {
|
||||
fill: #004849;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
text.remote-process-group-transmission-status {
|
||||
font-size: 13px;
|
||||
fill: #728e9b
|
||||
}
|
||||
|
||||
text.remote-process-group-transmission-status.has-authorization-errors {
|
||||
fill: #ba554a;
|
||||
}
|
||||
|
||||
text.remote-process-group-transmission-secure {
|
||||
font-family: FontAwesome;
|
||||
font-size: 13px;
|
||||
fill: #004849;
|
||||
}
|
||||
|
||||
text.remote-process-group-last-refresh {
|
||||
fill: #cccccc;
|
||||
font-style: italic;
|
||||
fill: #728e9b;
|
||||
text-anchor: end;
|
||||
}
|
|
@ -74,12 +74,13 @@ md-toolbar.md-small .md-toolbar-tools {
|
|||
|
||||
#global-menu-content {
|
||||
font-size: 13px;
|
||||
padding: 3px 0;
|
||||
padding: 0px 0;
|
||||
background-color:rgba(249,250,251,0.97); /*tint base-color 96%*/
|
||||
border:1px solid #004849; /*link-color*/
|
||||
border-radius:2px;
|
||||
box-shadow:0 2px 3px rgba(0,0,0,0.35);
|
||||
width: 215px;
|
||||
max-height: inherit;
|
||||
}
|
||||
|
||||
#global-menu-content md-menu-item{
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto+Slab';
|
||||
font-family: 'Roboto Slab';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: local('RobotoSlab Regular'),
|
||||
|
@ -78,7 +78,7 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto+Slab';
|
||||
font-family: 'Roboto Slab';
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: local('RobotoSlab Bold'),
|
||||
|
|
Before Width: | Height: | Size: 746 B |
Before Width: | Height: | Size: 618 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 585 B |
Before Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 227 B |
Before Width: | Height: | Size: 356 B |
Before Width: | Height: | Size: 356 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 880 B |
Before Width: | Height: | Size: 495 B |
Before Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 588 B |
Before Width: | Height: | Size: 530 B |
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 869 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 499 B |
Before Width: | Height: | Size: 435 B |
Before Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 319 B |
Before Width: | Height: | Size: 317 B |
Before Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 337 B |
Before Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 45 B |
|
@ -152,7 +152,7 @@ nf.Actions = (function () {
|
|||
url: d.component.uri,
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var remoteProcessGroup = response.remoteProcessGroup;
|
||||
var remoteProcessGroup = response.component;
|
||||
|
||||
// the timestamp has not updated yet, poll again
|
||||
if (refreshTimestamp === remoteProcessGroup.flowRefreshed) {
|
||||
|
@ -163,7 +163,7 @@ nf.Actions = (function () {
|
|||
// reload the group's connections
|
||||
var connections = nf.Connection.getComponentConnections(remoteProcessGroup.id);
|
||||
$.each(connections, function (_, connection) {
|
||||
nf.Connection.reload(connection);
|
||||
nf.Connection.reload(connection.component);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -405,16 +405,12 @@ nf.CanvasUtils = (function () {
|
|||
.each(function () {
|
||||
var bBox = this.getBBox();
|
||||
d3.select(this).attr('x', function () {
|
||||
return d.dimensions.width - bBox.width - 4;
|
||||
return d.dimensions.width - bBox.width - 15;
|
||||
});
|
||||
});
|
||||
|
||||
// update the background width
|
||||
selection.select('rect.active-thread-count-background')
|
||||
.attr('width', function () {
|
||||
var bBox = activeThreadCount.node().getBBox();
|
||||
return bBox.width + 8;
|
||||
})
|
||||
selection.select('text.active-thread-count-icon')
|
||||
.attr('x', function () {
|
||||
var bBox = activeThreadCount.node().getBBox();
|
||||
|
||||
|
@ -423,22 +419,11 @@ nf.CanvasUtils = (function () {
|
|||
setOffset(bBox.width + 6);
|
||||
}
|
||||
|
||||
return d.dimensions.width - bBox.width - 8;
|
||||
})
|
||||
.attr('stroke-dasharray', function() {
|
||||
var rect = d3.select(this);
|
||||
var width = parseFloat(rect.attr('width'));
|
||||
var height = parseFloat(rect.attr('height'));
|
||||
|
||||
var dashArray = [];
|
||||
dashArray.push(0);
|
||||
dashArray.push(width + height);
|
||||
dashArray.push(width + height);
|
||||
return dashArray.join(' ');
|
||||
return d.dimensions.width - bBox.width - 20;
|
||||
})
|
||||
.style('display', 'block');
|
||||
} else {
|
||||
selection.selectAll('text.active-thread-count, rect.active-thread-count-background').style('display', 'none');
|
||||
selection.selectAll('text.active-thread-count, text.active-thread-count-icon').style('display', 'none');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -475,16 +460,8 @@ nf.CanvasUtils = (function () {
|
|||
// if there are bulletins show them, otherwise hide
|
||||
if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins)) {
|
||||
// update the tooltip
|
||||
selection.select('image.bulletin-icon')
|
||||
.style('display', 'block')
|
||||
selection.select('text.bulletin-icon')
|
||||
.each(function () {
|
||||
var bBox = this.getBBox();
|
||||
var bulletinIcon = d3.select(this);
|
||||
|
||||
bulletinIcon.attr('x', function () {
|
||||
return d.dimensions.width - offset - bBox.width - 4;
|
||||
});
|
||||
|
||||
// if there are bulletins generate a tooltip
|
||||
tip = getTooltipContainer().append('div')
|
||||
.attr('id', function () {
|
||||
|
@ -505,10 +482,8 @@ nf.CanvasUtils = (function () {
|
|||
});
|
||||
|
||||
// add the tooltip
|
||||
nf.CanvasUtils.canvasTooltip(tip, bulletinIcon);
|
||||
nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
|
||||
});
|
||||
} else {
|
||||
selection.selectAll('image.bulletin-icon').style('display', 'none');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ nf.Canvas = (function () {
|
|||
|
||||
// create arrow definitions for the various line types
|
||||
defs.selectAll('marker')
|
||||
.data(['normal', 'ghost'])
|
||||
.data(['normal', 'ghost', 'unauthorized'])
|
||||
.enter().append('marker')
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
|
@ -256,6 +256,8 @@ nf.Canvas = (function () {
|
|||
'fill': function (d) {
|
||||
if (d === 'ghost') {
|
||||
return '#aaaaaa';
|
||||
} else if (d === 'unauthorized') {
|
||||
return '#ba554a';
|
||||
} else {
|
||||
return '#000000';
|
||||
}
|
||||
|
@ -264,77 +266,42 @@ nf.Canvas = (function () {
|
|||
.append('path')
|
||||
.attr('d', 'M2,3 L0,6 L6,3 L0,0 z');
|
||||
|
||||
// define the gradient for the processor stats background
|
||||
var processGroupStatsBackground = defs.append('linearGradient')
|
||||
.attr({
|
||||
'id': 'process-group-stats-background',
|
||||
'x1': '0%',
|
||||
'y1': '100%',
|
||||
'x2': '0%',
|
||||
'y2': '0%'
|
||||
});
|
||||
// filter for drop shadow
|
||||
var filter = defs.append('filter')
|
||||
.attr('id', 'component-drop-shadow');
|
||||
|
||||
processGroupStatsBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '0%',
|
||||
'stop-color': '#dedede'
|
||||
});
|
||||
// blur
|
||||
filter.append('feGaussianBlur')
|
||||
.attr('in', 'SourceAlpha')
|
||||
.attr('stdDeviation', 2)
|
||||
.attr('result', 'blur');
|
||||
|
||||
processGroupStatsBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '50%',
|
||||
'stop-color': '#ffffff'
|
||||
});
|
||||
// offset
|
||||
filter.append('feOffset')
|
||||
.attr('in', 'blur')
|
||||
.attr('dx', 0)
|
||||
.attr('dy', 1)
|
||||
.attr('result', 'offsetBlur');
|
||||
|
||||
processGroupStatsBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '100%',
|
||||
'stop-color': '#dedede'
|
||||
});
|
||||
// color/opacity
|
||||
filter.append('feFlood')
|
||||
.attr('flood-color', '#000000')
|
||||
.attr('flood-opacity', 0.25)
|
||||
.attr('result', 'offsetColor');
|
||||
|
||||
// define the gradient for the processor stats background
|
||||
var processorStatsBackground = defs.append('linearGradient')
|
||||
.attr({
|
||||
'id': 'processor-stats-background',
|
||||
'x1': '0%',
|
||||
'y1': '100%',
|
||||
'x2': '0%',
|
||||
'y2': '0%'
|
||||
});
|
||||
// combine
|
||||
filter.append('feComposite')
|
||||
.attr('in', 'offsetColor')
|
||||
.attr('in2', 'offsetBlur')
|
||||
.attr('operator', 'in')
|
||||
.attr('result', 'offsetColorBlur');
|
||||
|
||||
processorStatsBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '0%',
|
||||
'stop-color': '#6f97ac'
|
||||
});
|
||||
|
||||
processorStatsBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '100%',
|
||||
'stop-color': '#30505c'
|
||||
});
|
||||
|
||||
// define the gradient for the port background
|
||||
var portBackground = defs.append('linearGradient')
|
||||
.attr({
|
||||
'id': 'port-background',
|
||||
'x1': '0%',
|
||||
'y1': '100%',
|
||||
'x2': '0%',
|
||||
'y2': '0%'
|
||||
});
|
||||
|
||||
portBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '0%',
|
||||
'stop-color': '#aaaaaa'
|
||||
});
|
||||
|
||||
portBackground.append('stop')
|
||||
.attr({
|
||||
'offset': '100%',
|
||||
'stop-color': '#ffffff'
|
||||
});
|
||||
// stack the effect under the source graph
|
||||
var feMerge = filter.append('feMerge');
|
||||
feMerge.append('feMergeNode')
|
||||
.attr('in', 'offsetColorBlur');
|
||||
feMerge.append('feMergeNode')
|
||||
.attr('in', 'SourceGraphic');
|
||||
|
||||
// define the gradient for the expiration icon
|
||||
var expirationBackground = defs.append('linearGradient')
|
||||
|
@ -636,51 +603,6 @@ nf.Canvas = (function () {
|
|||
}).fail(nf.Common.handleAjaxError);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the colors for the specified type.
|
||||
*
|
||||
* @param {array} colors The possible colors
|
||||
* @param {string} type The component type for these colors
|
||||
*/
|
||||
var setColors = function (colors, type) {
|
||||
var defs = d3.select('defs');
|
||||
|
||||
// update processors
|
||||
var processorSelection = defs.selectAll('linearGradient.' + type + '-background').data(colors, function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
// define the gradient for the processor background
|
||||
var gradient = processorSelection.enter().append('linearGradient')
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
return type + '-background-' + d;
|
||||
},
|
||||
'class': type + '-background',
|
||||
'x1': '0%',
|
||||
'y1': '100%',
|
||||
'x2': '0%',
|
||||
'y2': '0%'
|
||||
});
|
||||
|
||||
gradient.append('stop')
|
||||
.attr({
|
||||
'offset': '0%',
|
||||
'stop-color': function (d) {
|
||||
return '#' + d;
|
||||
}
|
||||
});
|
||||
|
||||
gradient.append('stop')
|
||||
.attr({
|
||||
'offset': '100%',
|
||||
'stop-color': '#ffffff'
|
||||
});
|
||||
|
||||
// remove old processor colors
|
||||
processorSelection.exit().remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Reloads the current status of this flow.
|
||||
*/
|
||||
|
@ -1172,24 +1094,6 @@ nf.Canvas = (function () {
|
|||
}).fail(nf.Common.handleAjaxError);
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines the gradient colors used to render processors.
|
||||
*
|
||||
* @param {array} colors The colors
|
||||
*/
|
||||
defineProcessorColors: function (colors) {
|
||||
setColors(colors, 'processor');
|
||||
},
|
||||
|
||||
/**
|
||||
* Defines the gradient colors used to render label.
|
||||
*
|
||||
* @param {array} colors The colors
|
||||
*/
|
||||
defineLabelColors: function (colors) {
|
||||
setColors(colors, 'label');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return whether this instance of NiFi is clustered.
|
||||
*
|
||||
|
|
|
@ -248,29 +248,32 @@ nf.ConnectionConfiguration = (function () {
|
|||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.id),
|
||||
url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupData.id),
|
||||
data: {
|
||||
verbose: true
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var processGroup = response.component;
|
||||
var processGroupContents = processGroup.contents;
|
||||
var processGroup = response.processGroupFlow;
|
||||
var processGroupContents = processGroup.flow;
|
||||
|
||||
// show the output port options
|
||||
var options = [];
|
||||
$.each(processGroupContents.outputPorts, function (i, outputPort) {
|
||||
if (outputPort.accessPolicy.canRead && outputPort.accessPolicy.canWrite) {
|
||||
var component = outputPort.component;
|
||||
options.push({
|
||||
text: component.name,
|
||||
value: component.id,
|
||||
description: nf.Common.escapeHtml(component.comments)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// only proceed if there are output ports
|
||||
if (!nf.Common.isEmpty(processGroupContents.outputPorts)) {
|
||||
if (!nf.Common.isEmpty(options)) {
|
||||
$('#output-port-source').show();
|
||||
|
||||
// show the output port options
|
||||
var options = [];
|
||||
$.each(processGroupContents.outputPorts, function (i, outputPort) {
|
||||
options.push({
|
||||
text: outputPort.name,
|
||||
value: outputPort.id,
|
||||
description: nf.Common.escapeHtml(outputPort.comments)
|
||||
});
|
||||
});
|
||||
|
||||
// sort the options
|
||||
options.sort(function (a, b) {
|
||||
return a.text.localeCompare(b.text);
|
||||
|
@ -331,7 +334,7 @@ nf.ConnectionConfiguration = (function () {
|
|||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var remoteProcessGroup = response.remoteProcessGroup;
|
||||
var remoteProcessGroup = response.component;
|
||||
var remoteProcessGroupContents = remoteProcessGroup.contents;
|
||||
|
||||
// only proceed if there are output ports
|
||||
|
@ -473,29 +476,29 @@ nf.ConnectionConfiguration = (function () {
|
|||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.id),
|
||||
data: {
|
||||
verbose: true
|
||||
},
|
||||
url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupData.id),
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var processGroup = response.component;
|
||||
var processGroupContents = processGroup.contents;
|
||||
var processGroup = response.processGroupFlow;
|
||||
var processGroupContents = processGroup.flow;
|
||||
|
||||
// show the input port options
|
||||
var options = [];
|
||||
$.each(processGroupContents.inputPorts, function (i, inputPort) {
|
||||
if (inputPort.accessPolicy.canRead && inputPort.accessPolicy.canWrite) {
|
||||
var component = inputPort.component;
|
||||
options.push({
|
||||
text: component.name,
|
||||
value: component.id,
|
||||
description: nf.Common.escapeHtml(component.comments)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// only proceed if there are output ports
|
||||
if (!nf.Common.isEmpty(processGroupContents.inputPorts)) {
|
||||
if (!nf.Common.isEmpty(options)) {
|
||||
$('#input-port-destination').show();
|
||||
|
||||
// show the input port options
|
||||
var options = [];
|
||||
$.each(processGroupContents.inputPorts, function (i, inputPort) {
|
||||
options.push({
|
||||
text: inputPort.name,
|
||||
value: inputPort.id,
|
||||
description: nf.Common.escapeHtml(inputPort.comments)
|
||||
});
|
||||
});
|
||||
|
||||
// sort the options
|
||||
options.sort(function (a, b) {
|
||||
return a.text.localeCompare(b.text);
|
||||
|
@ -555,7 +558,7 @@ nf.ConnectionConfiguration = (function () {
|
|||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var remoteProcessGroup = response.remoteProcessGroup;
|
||||
var remoteProcessGroup = response.component;
|
||||
var remoteProcessGroupContents = remoteProcessGroup.contents;
|
||||
|
||||
// only proceed if there are output ports
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
nf.Funnel = (function () {
|
||||
|
||||
var dimensions = {
|
||||
width: 61,
|
||||
height: 61
|
||||
width: 48,
|
||||
height: 48
|
||||
};
|
||||
|
||||
// -----------------------------
|
||||
|
@ -51,7 +51,7 @@ nf.Funnel = (function () {
|
|||
|
||||
/**
|
||||
* Renders the funnels in the specified selection.
|
||||
*
|
||||
*
|
||||
* @param {selection} entered The selection of funnels to be rendered
|
||||
* @param {boolean} selected Whether the element should be selected
|
||||
*/
|
||||
|
@ -61,40 +61,60 @@ nf.Funnel = (function () {
|
|||
}
|
||||
|
||||
var funnel = entered.append('g')
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
return 'id-' + d.id;
|
||||
},
|
||||
'class': 'funnel component'
|
||||
})
|
||||
.classed('selected', selected)
|
||||
.call(nf.CanvasUtils.position);
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
return 'id-' + d.id;
|
||||
},
|
||||
'class': 'funnel component'
|
||||
})
|
||||
.classed('selected', selected)
|
||||
.call(nf.CanvasUtils.position);
|
||||
|
||||
// funnel border
|
||||
funnel.append('rect')
|
||||
.attr({
|
||||
'class': 'border',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'fill': 'transparent',
|
||||
'stroke-opacity': 0.8,
|
||||
'stroke-width': 1
|
||||
});
|
||||
.attr({
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
'class': 'border',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'fill': 'transparent',
|
||||
'stroke': 'transparent'
|
||||
}).classed('unauthorized', function (d) {
|
||||
return d.accessPolicy.canRead === false;
|
||||
});
|
||||
|
||||
// processor icon
|
||||
funnel.append('image')
|
||||
.call(nf.CanvasUtils.disableImageHref)
|
||||
.attr({
|
||||
'xlink:href': 'images/iconFunnel.png',
|
||||
'width': 41,
|
||||
'height': 41,
|
||||
'x': 10,
|
||||
'y': 10
|
||||
});
|
||||
// funnel body
|
||||
funnel.append('rect')
|
||||
.attr({
|
||||
'rx': 2,
|
||||
'ry': 2,
|
||||
'class': 'body',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'filter': 'url(#component-drop-shadow)',
|
||||
'stroke-width': 0
|
||||
})
|
||||
.classed('unauthorized', function (d) {
|
||||
return d.accessPolicy.canRead === false;
|
||||
});
|
||||
|
||||
// funnel icon
|
||||
funnel.append('text')
|
||||
.attr({
|
||||
'class': 'funnel-icon',
|
||||
'x': 9,
|
||||
'y': 34
|
||||
})
|
||||
.text('\ue803');
|
||||
|
||||
// always support selection
|
||||
funnel.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
|
||||
|
@ -109,7 +129,7 @@ nf.Funnel = (function () {
|
|||
|
||||
/**
|
||||
* Updates the funnels in the specified selection.
|
||||
*
|
||||
*
|
||||
* @param {selection} updated The funnels to be updated
|
||||
*/
|
||||
var updateFunnels = function (updated) {
|
||||
|
@ -117,7 +137,7 @@ nf.Funnel = (function () {
|
|||
|
||||
/**
|
||||
* Removes the funnels in the specified selection.
|
||||
*
|
||||
*
|
||||
* @param {selection} removed The funnels to be removed
|
||||
*/
|
||||
var removeFunnels = function (removed) {
|
||||
|
@ -133,15 +153,15 @@ nf.Funnel = (function () {
|
|||
|
||||
// create the funnel container
|
||||
funnelContainer = d3.select('#canvas').append('g')
|
||||
.attr({
|
||||
'pointer-events': 'all',
|
||||
'class': 'funnels'
|
||||
});
|
||||
.attr({
|
||||
'pointer-events': 'all',
|
||||
'class': 'funnels'
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Populates the graph with the specified funnels.
|
||||
*
|
||||
*
|
||||
* @argument {object | array} funnelEntities The funnels to add
|
||||
* @argument {boolean} selectAll Whether or not to select the new contents
|
||||
*/
|
||||
|
@ -168,11 +188,11 @@ nf.Funnel = (function () {
|
|||
// apply the selection and handle all new processors
|
||||
select().enter().call(renderFunnels, selectAll);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* If the funnel id is specified it is returned. If no funnel id
|
||||
* specified, all funnels are returned.
|
||||
*
|
||||
*
|
||||
* @param {string} id
|
||||
*/
|
||||
get: function (id) {
|
||||
|
@ -182,11 +202,11 @@ nf.Funnel = (function () {
|
|||
return funnelMap.get(id);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* If the funnel id is specified it is refresh according to the current
|
||||
* If the funnel id is specified it is refresh according to the current
|
||||
* state. If not funnel id is specified, all funnels are refreshed.
|
||||
*
|
||||
*
|
||||
* @param {string} id Optional
|
||||
*/
|
||||
refresh: function (id) {
|
||||
|
@ -196,11 +216,11 @@ nf.Funnel = (function () {
|
|||
d3.selectAll('g.funnel').call(updateFunnels);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the funnel state from the server and refreshes the UI.
|
||||
* If the funnel is currently unknown, this function just returns.
|
||||
*
|
||||
*
|
||||
* @param {object} funnel The funnel to reload
|
||||
*/
|
||||
reload: function (funnel) {
|
||||
|
@ -214,21 +234,21 @@ nf.Funnel = (function () {
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Positions the component.
|
||||
*
|
||||
*
|
||||
* @param {string} id The id
|
||||
*/
|
||||
position: function (id) {
|
||||
d3.select('#id-' + id).call(nf.CanvasUtils.position);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified funnel(s). If the is an array, it
|
||||
* will set each funnel. If it is not an array, it will
|
||||
* Sets the specified funnel(s). If the is an array, it
|
||||
* will set each funnel. If it is not an array, it will
|
||||
* attempt to set the specified funnel.
|
||||
*
|
||||
*
|
||||
* @param {object | array} funnelEntities
|
||||
*/
|
||||
set: function (funnelEntities) {
|
||||
|
@ -237,7 +257,7 @@ nf.Funnel = (function () {
|
|||
// update the current entry
|
||||
var funnelEntry = funnelMap.get(funnelEntity.id);
|
||||
$.extend(funnelEntry, funnelEntity);
|
||||
|
||||
|
||||
// update the connection in the UI
|
||||
d3.select('#id-' + funnelEntity.id).call(updateFunnels);
|
||||
}
|
||||
|
@ -255,7 +275,7 @@ nf.Funnel = (function () {
|
|||
|
||||
/**
|
||||
* Removes the specified funnel.
|
||||
*
|
||||
*
|
||||
* @param {array|string} funnels The funnel id
|
||||
*/
|
||||
remove: function (funnels) {
|
||||
|
@ -270,7 +290,7 @@ nf.Funnel = (function () {
|
|||
// apply the selection and handle all removed funnels
|
||||
select().exit().call(removeFunnels);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Removes all processors.
|
||||
*/
|
||||
|
|
|
@ -53,7 +53,9 @@ nf.Label = (function () {
|
|||
* Selects the labels elements against the current label map.
|
||||
*/
|
||||
var select = function () {
|
||||
return labelContainer.selectAll('g.label').data(labelMap.values());
|
||||
return labelContainer.selectAll('g.label').data(labelMap.values(), function (d) {
|
||||
return d.id;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -126,21 +128,6 @@ nf.Label = (function () {
|
|||
return;
|
||||
}
|
||||
|
||||
// reset the colors
|
||||
var colors = d3.set();
|
||||
colors.add(nf.Common.substringAfterLast(nf.Label.defaultColor(), '#'));
|
||||
|
||||
// determine all unique colors
|
||||
labelMap.forEach(function (id, d) {
|
||||
if (d.accessPolicy.canRead) {
|
||||
var color = d.component.style['background-color'];
|
||||
if (nf.Common.isDefinedAndNotNull(color)) {
|
||||
colors.add(nf.Common.substringAfterLast(color, '#'));
|
||||
}
|
||||
}
|
||||
});
|
||||
nf.Canvas.defineLabelColors(colors.values());
|
||||
|
||||
// update the border using the configured color
|
||||
updated.select('rect.border')
|
||||
.attr({
|
||||
|
@ -177,10 +164,7 @@ nf.Label = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
// get just the color code part
|
||||
color = nf.Common.substringAfterLast(color, '#');
|
||||
|
||||
return 'url(#label-background-' + color + ')';
|
||||
return color;
|
||||
},
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
nf.Port = (function () {
|
||||
|
||||
var PREVIEW_NAME_LENGTH = 15;
|
||||
var OFFSET_VALUE = 12;
|
||||
var OFFSET_VALUE = 25;
|
||||
|
||||
var portDimensions = {
|
||||
width: 160,
|
||||
height: 40
|
||||
width: 240,
|
||||
height: 50
|
||||
};
|
||||
var remotePortDimensions = {
|
||||
width: 160,
|
||||
height: 56
|
||||
width: 240,
|
||||
height: 75
|
||||
};
|
||||
|
||||
// ----------------------------
|
||||
|
@ -51,7 +51,9 @@ nf.Port = (function () {
|
|||
* Selects the port elements against the current port map.
|
||||
*/
|
||||
var select = function () {
|
||||
return portContainer.selectAll('g.input-port, g.output-port').data(portMap.values());
|
||||
return portContainer.selectAll('g.input-port, g.output-port').data(portMap.values(), function (d) {
|
||||
return d.id;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -66,36 +68,54 @@ nf.Port = (function () {
|
|||
}
|
||||
|
||||
var port = entered.append('g')
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
return 'id-' + d.id;
|
||||
},
|
||||
'class': function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return 'input-port component';
|
||||
} else {
|
||||
return 'output-port component';
|
||||
}
|
||||
.attr({
|
||||
'id': function (d) {
|
||||
return 'id-' + d.id;
|
||||
},
|
||||
'class': function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return 'input-port component';
|
||||
} else {
|
||||
return 'output-port component';
|
||||
}
|
||||
})
|
||||
.classed('selected', selected)
|
||||
.call(nf.CanvasUtils.position);
|
||||
}
|
||||
})
|
||||
.classed('selected', selected)
|
||||
.call(nf.CanvasUtils.position);
|
||||
|
||||
// port border
|
||||
port.append('rect')
|
||||
.attr({
|
||||
'class': 'border',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'fill': 'transparent',
|
||||
'stroke-opacity': 0.8,
|
||||
'stroke-width': 1,
|
||||
'stroke': '#aaaaaa'
|
||||
});
|
||||
.attr({
|
||||
'class': 'border',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'fill': 'transparent',
|
||||
'stroke': 'transparent'
|
||||
})
|
||||
.classed('unauthorized', function (d) {
|
||||
return d.accessPolicy.canRead === false;
|
||||
});
|
||||
|
||||
// port body
|
||||
port.append('rect')
|
||||
.attr({
|
||||
'class': 'body',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height;
|
||||
},
|
||||
'filter': 'url(#component-drop-shadow)',
|
||||
'stroke-width': 0
|
||||
})
|
||||
.classed('unauthorized', function (d) {
|
||||
return d.accessPolicy.canRead === false;
|
||||
});
|
||||
|
||||
var offset = 0;
|
||||
|
||||
|
@ -105,84 +125,47 @@ nf.Port = (function () {
|
|||
|
||||
// port remote banner
|
||||
port.append('rect')
|
||||
.attr({
|
||||
'class': 'remote-banner',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': offset,
|
||||
'fill': '#294c58',
|
||||
'fill-opacity': 0.95
|
||||
});
|
||||
}
|
||||
|
||||
// port body
|
||||
port.append('rect')
|
||||
.attr({
|
||||
'x': 0,
|
||||
'y': offset,
|
||||
'class': 'port-body',
|
||||
'class': 'remote-banner',
|
||||
'width': function (d) {
|
||||
return d.dimensions.width;
|
||||
},
|
||||
'height': function (d) {
|
||||
return d.dimensions.height - offset;
|
||||
},
|
||||
'fill': 'url(#port-background)',
|
||||
'fill-opacity': 0.8,
|
||||
'stroke-opacity': 0.8,
|
||||
'stroke-width': 0,
|
||||
'stroke': '#aaaaaa'
|
||||
'height': offset,
|
||||
'fill': '#e3e8eb'
|
||||
});
|
||||
}
|
||||
|
||||
// port icon
|
||||
port.append('image')
|
||||
.call(nf.CanvasUtils.disableImageHref)
|
||||
.attr({
|
||||
'xlink:href': function (d) {
|
||||
if (d.portTtype === 'INPUT_PORT') {
|
||||
return 'images/iconInputPort.png';
|
||||
} else {
|
||||
return 'images/iconOutputPort.png';
|
||||
}
|
||||
},
|
||||
'width': 46,
|
||||
'height': 31,
|
||||
'x': function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return 0;
|
||||
} else {
|
||||
return 114;
|
||||
}
|
||||
},
|
||||
'y': 5 + offset
|
||||
});
|
||||
port.append('text')
|
||||
.attr({
|
||||
'class': 'port-icon',
|
||||
'x': 10,
|
||||
'y': 38 + offset
|
||||
})
|
||||
.text(function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return '\ue832';
|
||||
} else {
|
||||
return '\ue833';
|
||||
}
|
||||
});
|
||||
|
||||
// port name
|
||||
port.append('text')
|
||||
.attr({
|
||||
'x': function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return 52;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
},
|
||||
'y': 18 + offset,
|
||||
'width': 95,
|
||||
'height': 30,
|
||||
'font-size': '10px',
|
||||
'font-weight': 'bold',
|
||||
'fill': '#294c58',
|
||||
'class': 'port-name'
|
||||
});
|
||||
.attr({
|
||||
'x': 70,
|
||||
'y': 25 + offset,
|
||||
'width': 95,
|
||||
'height': 30,
|
||||
'class': 'port-name'
|
||||
});
|
||||
|
||||
// make ports selectable
|
||||
port.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
|
||||
|
||||
// only activate dragging and connecting if appropriate
|
||||
port.filter(function (d) {
|
||||
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
|
||||
return d.accessPolicy.canWrite && d.accessPolicy.canRead;
|
||||
}).call(nf.Draggable.activate).call(nf.Connectable.activate);
|
||||
|
||||
// call update to trigger some rendering
|
||||
|
@ -213,132 +196,85 @@ nf.Port = (function () {
|
|||
offset = OFFSET_VALUE;
|
||||
|
||||
// port transmitting icon
|
||||
details.append('image')
|
||||
.call(nf.CanvasUtils.disableImageHref)
|
||||
.attr({
|
||||
'class': 'port-transmission-icon',
|
||||
'width': 10,
|
||||
'height': 10,
|
||||
'x': 3,
|
||||
'y': 1
|
||||
});
|
||||
details.append('text')
|
||||
.attr({
|
||||
'class': 'port-transmission-icon',
|
||||
'x': 10,
|
||||
'y': 15
|
||||
});
|
||||
|
||||
// bulletin background
|
||||
details.append('rect')
|
||||
.attr({
|
||||
'class': 'bulletin-background',
|
||||
'x': function (d) {
|
||||
return portData.dimensions.width - offset;
|
||||
},
|
||||
'width': offset,
|
||||
'height': offset
|
||||
});
|
||||
|
||||
// bulletin icon
|
||||
details.append('image')
|
||||
.call(nf.CanvasUtils.disableImageHref)
|
||||
.attr({
|
||||
'class': 'bulletin-icon',
|
||||
'xlink:href': 'images/iconBulletin.png',
|
||||
'width': 12,
|
||||
'height': 12,
|
||||
'x': 147,
|
||||
'y': 0
|
||||
});
|
||||
details.append('text')
|
||||
.attr({
|
||||
'class': 'bulletin-icon',
|
||||
'x': function (d) {
|
||||
return portData.dimensions.width - 18;
|
||||
},
|
||||
'y': 18
|
||||
})
|
||||
.text('\uf24a');
|
||||
}
|
||||
|
||||
// run status icon
|
||||
details.append('image')
|
||||
.call(nf.CanvasUtils.disableImageHref)
|
||||
.attr({
|
||||
'class': 'port-run-status-icon',
|
||||
'width': 16,
|
||||
'height': 16,
|
||||
'x': function (d) {
|
||||
if (d.portType === 'INPUT_PORT') {
|
||||
return 33;
|
||||
} else {
|
||||
return 107;
|
||||
}
|
||||
},
|
||||
'y': function () {
|
||||
return 24 + offset;
|
||||
}
|
||||
});
|
||||
|
||||
// active thread count
|
||||
details.append('rect')
|
||||
.attr({
|
||||
'class': 'active-thread-count-background',
|
||||
'height': 11,
|
||||
'y': 0,
|
||||
'fill': '#fff',
|
||||
'fill-opacity': '0.65',
|
||||
'stroke': '#aaa',
|
||||
'stroke-width': '1'
|
||||
});
|
||||
|
||||
// active thread bacground
|
||||
details.append('text')
|
||||
.attr({
|
||||
'class': 'active-thread-count',
|
||||
'height': 11,
|
||||
'y': 9,
|
||||
'fill': '#000'
|
||||
});
|
||||
.attr({
|
||||
'class': 'run-status-icon',
|
||||
'x': 50,
|
||||
'y': function () {
|
||||
return 25 + offset;
|
||||
}
|
||||
});
|
||||
|
||||
// -------------------
|
||||
// active thread count
|
||||
// -------------------
|
||||
|
||||
// active thread count
|
||||
details.append('text')
|
||||
.attr({
|
||||
'class': 'active-thread-count-icon',
|
||||
'y': 68
|
||||
})
|
||||
.text('\ue83f');
|
||||
|
||||
// active thread icon
|
||||
details.append('text')
|
||||
.attr({
|
||||
'class': 'active-thread-count',
|
||||
'y': 68
|
||||
});
|
||||
}
|
||||
|
||||
if (portData.accessPolicy.canRead) {
|
||||
// update the run status
|
||||
details.select('image.port-run-status-icon')
|
||||
.attr('xlink:href', function (d) {
|
||||
var img = '';
|
||||
if (d.component.state === 'DISABLED') {
|
||||
img = 'images/iconDisable.png';
|
||||
} else if (!nf.Common.isEmpty(d.component.validationErrors)) {
|
||||
img = 'images/iconAlert.png';
|
||||
} else if (d.component.state === 'RUNNING') {
|
||||
img = 'images/iconRun.png';
|
||||
} else if (d.component.state === 'STOPPED') {
|
||||
img = 'images/iconStop.png';
|
||||
}
|
||||
return img;
|
||||
})
|
||||
.each(function (d) {
|
||||
// remove the existing tip if necessary
|
||||
var tip = d3.select('#run-status-tip-' + d.id);
|
||||
if (!tip.empty()) {
|
||||
tip.remove();
|
||||
}
|
||||
|
||||
// if there are validation errors generate a tooltip
|
||||
if (!nf.Common.isEmpty(d.component.validationErrors)) {
|
||||
tip = d3.select('#port-tooltips').append('div')
|
||||
.attr('id', function () {
|
||||
return 'run-status-tip-' + d.id;
|
||||
})
|
||||
.attr('class', 'tooltip nifi-tooltip')
|
||||
.html(function () {
|
||||
var list = nf.Common.formatUnorderedList(d.component.validationErrors);
|
||||
if (list === null || list.length === 0) {
|
||||
return '';
|
||||
} else {
|
||||
return $('<div></div>').append(list).html();
|
||||
}
|
||||
});
|
||||
|
||||
// add the tooltip
|
||||
nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
|
||||
}
|
||||
});
|
||||
|
||||
// update the port name
|
||||
port.select('text.port-name')
|
||||
.each(function (d) {
|
||||
var portName = d3.select(this);
|
||||
var name = d.component.name;
|
||||
var words = name.split(/\s+/);
|
||||
.each(function (d) {
|
||||
var portName = d3.select(this);
|
||||
var name = d.component.name;
|
||||
var words = name.split(/\s+/);
|
||||
|
||||
// reset the port name to handle any previous state
|
||||
portName.text(null).selectAll('tspan, title').remove();
|
||||
// reset the port name to handle any previous state
|
||||
portName.text(null).selectAll('tspan, title').remove();
|
||||
|
||||
// handle based on the number of tokens in the port name
|
||||
if (words.length === 1) {
|
||||
// apply ellipsis to the port name as necessary
|
||||
nf.CanvasUtils.ellipsis(portName, name);
|
||||
} else {
|
||||
nf.CanvasUtils.multilineEllipsis(portName, 2, name);
|
||||
}
|
||||
}).append('title').text(function (d) {
|
||||
// handle based on the number of tokens in the port name
|
||||
if (words.length === 1) {
|
||||
// apply ellipsis to the port name as necessary
|
||||
nf.CanvasUtils.ellipsis(portName, name);
|
||||
} else {
|
||||
nf.CanvasUtils.multilineEllipsis(portName, 2, name);
|
||||
}
|
||||
}).append('title').text(function (d) {
|
||||
return d.component.name;
|
||||
});
|
||||
}
|
||||
|
@ -349,14 +285,14 @@ nf.Port = (function () {
|
|||
if (portData.accessPolicy.canRead) {
|
||||
// update the port name
|
||||
port.select('text.port-name')
|
||||
.text(function (d) {
|
||||
var name = d.component.name;
|
||||
if (name.length > PREVIEW_NAME_LENGTH) {
|
||||
return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
});
|
||||
.text(function (d) {
|
||||
var name = d.component.name;
|
||||
if (name.length > PREVIEW_NAME_LENGTH) {
|
||||
return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// remove tooltips if necessary
|
||||
|
@ -372,7 +308,7 @@ nf.Port = (function () {
|
|||
|
||||
/**
|
||||
* Updates the port status.
|
||||
*
|
||||
*
|
||||
* @param {selection} updated The ports to be updated
|
||||
*/
|
||||
var updatePortStatus = function (updated) {
|
||||
|
@ -380,14 +316,82 @@ nf.Port = (function () {
|
|||
return;
|
||||
}
|
||||
|
||||
updated.select('image.port-transmission-icon')
|
||||
.attr('xlink:href', function (d) {
|
||||
if (d.status.transmitting === true) {
|
||||
return 'images/iconPortTransmitting.png';
|
||||
} else {
|
||||
return 'images/iconPortNotTransmitting.png';
|
||||
// update the run status
|
||||
updated.select('text.run-status-icon')
|
||||
.attr({
|
||||
'fill': function (d) {
|
||||
var fill = '#728e9b';
|
||||
if (d.status.runStatus === 'Invalid') {
|
||||
fill = '#ba554a';
|
||||
}
|
||||
});
|
||||
return fill;
|
||||
},
|
||||
'font-family': function (d) {
|
||||
var family = 'FontAwesome';
|
||||
if (d.status.runStatus === 'Disabled') {
|
||||
family = 'flowfont';
|
||||
}
|
||||
return family;
|
||||
}
|
||||
})
|
||||
.text(function (d) {
|
||||
var img = '';
|
||||
if (d.status.runStatus === 'Disabled') {
|
||||
img = '\ue802';
|
||||
} else if (d.status.runStatus === 'Invalid') {
|
||||
img = '\uf071';
|
||||
} else if (d.status.runStatus === 'Running') {
|
||||
img = '\uf04b';
|
||||
} else if (d.status.runStatus === 'Stopped') {
|
||||
img = '\uf04d';
|
||||
}
|
||||
return img;
|
||||
})
|
||||
.each(function (d) {
|
||||
// remove the existing tip if necessary
|
||||
var tip = d3.select('#run-status-tip-' + d.id);
|
||||
if (!tip.empty()) {
|
||||
tip.remove();
|
||||
}
|
||||
|
||||
// if there are validation errors generate a tooltip
|
||||
if (d.accessPolicy.canRead && !nf.Common.isEmpty(d.component.validationErrors)) {
|
||||
tip = d3.select('#port-tooltips').append('div')
|
||||
.attr('id', function () {
|
||||
return 'run-status-tip-' + d.id;
|
||||
})
|
||||
.attr('class', 'tooltip nifi-tooltip')
|
||||
.html(function () {
|
||||
var list = nf.Common.formatUnorderedList(d.component.validationErrors);
|
||||
if (list === null || list.length === 0) {
|
||||
return '';
|
||||
} else {
|
||||
return $('<div></div>').append(list).html();
|
||||
}
|
||||
});
|
||||
|
||||
// add the tooltip
|
||||
nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
|
||||
}
|
||||
});
|
||||
|
||||
updated.select('text.port-transmission-icon')
|
||||
.attr({
|
||||
'font-family': function (d) {
|
||||
if (d.status.transmitting === true) {
|
||||
return 'FontAwesome';
|
||||
} else {
|
||||
return 'flowfont';
|
||||
}
|
||||
}
|
||||
})
|
||||
.text(function (d) {
|
||||
if (d.status.transmitting === true) {
|
||||
return '\uf140';
|
||||
} else {
|
||||
return '\ue80a';
|
||||
}
|
||||
});
|
||||
|
||||
updated.each(function (d) {
|
||||
var port = d3.select(this);
|
||||
|
@ -405,6 +409,10 @@ nf.Port = (function () {
|
|||
// bulletins
|
||||
// ---------
|
||||
|
||||
port.select('rect.bulletin-background').classed('has-bulletins', function () {
|
||||
return nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.bulletins);
|
||||
});
|
||||
|
||||
nf.CanvasUtils.bulletins(port, d, function () {
|
||||
return d3.select('#port-tooltips');
|
||||
}, offset);
|
||||
|
@ -426,7 +434,7 @@ nf.Port = (function () {
|
|||
|
||||
/**
|
||||
* Removes the tooltips for the ports in the specified selection.
|
||||
*
|
||||
*
|
||||
* @param {selection} removed
|
||||
*/
|
||||
var removeTooltips = function (removed) {
|
||||
|
@ -446,12 +454,12 @@ nf.Port = (function () {
|
|||
|
||||
// create the port container
|
||||
portContainer = d3.select('#canvas').append('g')
|
||||
.attr({
|
||||
'pointer-events': 'all',
|
||||
'class': 'ports'
|
||||
});
|
||||
.attr({
|
||||
'pointer-events': 'all',
|
||||
'class': 'ports'
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Populates the graph with the specified ports.
|
||||
*
|
||||
|
@ -490,7 +498,7 @@ nf.Port = (function () {
|
|||
// apply the selection and handle all new ports
|
||||
select().enter().call(renderPorts, selectAll);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* If the port id is specified it is returned. If no port id
|
||||
* specified, all ports are returned.
|
||||
|
@ -504,7 +512,7 @@ nf.Port = (function () {
|
|||
return portMap.get(id);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* If the port id is specified it is refresh according to the current
|
||||
* state. If not port id is specified, all ports are refreshed.
|
||||
|
@ -518,14 +526,14 @@ nf.Port = (function () {
|
|||
d3.selectAll('g.input-port, g.output-port').call(updatePorts);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes the components necessary after a pan event.
|
||||
*/
|
||||
pan: function () {
|
||||
d3.selectAll('g.input-port.entering, g.output-port.entering, g.input-port.leaving, g.output-port.leaving').call(updatePorts);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the port state from the server and refreshes the UI.
|
||||
* If the port is currently unknown, this function just returns.
|
||||
|
@ -547,16 +555,16 @@ nf.Port = (function () {
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Positions the component.
|
||||
*
|
||||
*
|
||||
* @param {string} id The id
|
||||
*/
|
||||
position: function (id) {
|
||||
d3.select('#id-' + id).call(nf.CanvasUtils.position);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified port(s). If the is an array, it
|
||||
* will set each port. If it is not an array, it will
|
||||
|
@ -585,10 +593,10 @@ nf.Port = (function () {
|
|||
set(portEntities);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Sets the port status using the specified status.
|
||||
*
|
||||
*
|
||||
* @param {array} portStatus Port status
|
||||
*/
|
||||
setStatus: function (portStatus) {
|
||||
|
@ -625,7 +633,7 @@ nf.Port = (function () {
|
|||
// apply the selection and handle all removed ports
|
||||
select().exit().call(removePorts);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Removes all ports..
|
||||
*/
|
||||
|
|
|
@ -722,6 +722,43 @@ nf.Common = (function () {
|
|||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts the contents of the specified str after the strToFind. If the
|
||||
* strToFind is not found or the last part of the str, an empty string is
|
||||
* returned.
|
||||
*
|
||||
* @argument {string} str The full string
|
||||
* @argument {string} strToFind The substring to find
|
||||
*/
|
||||
substringAfterFirst: function (str, strToFind) {
|
||||
var result = '';
|
||||
var indexOfStrToFind = str.indexOf(strToFind);
|
||||
if (indexOfStrToFind >= 0) {
|
||||
var indexAfterStrToFind = indexOfStrToFind + strToFind.length;
|
||||
if (indexAfterStrToFind < str.length) {
|
||||
result = str.substr(indexAfterStrToFind);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts the contents of the specified str before the strToFind. If the
|
||||
* strToFind is not found or the first part of the str, an empty string is
|
||||
* returned.
|
||||
*
|
||||
* @argument {string} str The full string
|
||||
* @argument {string} strToFind The substring to find
|
||||
*/
|
||||
substringBeforeFirst: function(str, strToFind) {
|
||||
var result = '';
|
||||
var indexOfStrToFind = str.indexOf(strToFind);
|
||||
if (indexOfStrToFind >= 0) {
|
||||
result = str.substr(0, indexOfStrToFind);
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the mouse pointer.
|
||||
*
|
||||
|
|