mirror of https://github.com/apache/nifi.git
NIFI-5986 Adding "Stop & Configure" button functionality to Processor Details modal.
NIFI-5986 Refactored Stop & Configure feature to enable bulletin/thread notifications and terminate capability in processor dialogs. Also added feature as a menu item to the canvas context menu. NIFI-5986 Refactored Stop & Configure feature to enable a status bar in a dialog that conveys bulletin/thread notifications and buttons. NIFI-5986 Refactored Stop & Configure feature to decouple status bar from modal component, updated styling and revised graph synchronization process. NIFI-5986 Refactored Stop & Configure feature to improve status bar button hide/show functionality. NIFI-5986: Rebased and resolved conflicts. NIFI-5986 - Refactored Stop & Configure statusbar observer, as well as processor dialogs to remove duplicative code. This closes #3281
This commit is contained in:
parent
31463c5dad
commit
c5c9425989
|
@ -32,6 +32,7 @@
|
|||
<link rel="stylesheet" href="js/jquery/propertytable/jquery.propertytable.css?${project.version}" type="text/css" />
|
||||
<link rel="stylesheet" href="js/jquery/tagcloud/jquery.tagcloud.css?${project.version}" type="text/css" />
|
||||
<link rel="stylesheet" href="js/jquery/modal/jquery.modal.css?${project.version}" type="text/css" />
|
||||
<link rel="stylesheet" href="js/jquery/statusbar/jquery.statusbar.css?${project.version}" type="text/css" />
|
||||
<link rel="stylesheet" href="assets/qtip2/dist/jquery.qtip.min.css?" type="text/css" />
|
||||
<link rel="stylesheet" href="assets/jquery-ui-dist/jquery-ui.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="assets/jquery-minicolors/jquery.minicolors.css" type="text/css" />
|
||||
|
@ -88,6 +89,7 @@
|
|||
<script type="text/javascript" src="js/jquery/nfeditor/jquery.nfeditor.js?${project.version}"></script>
|
||||
<script type="text/javascript" src="js/jquery/propertytable/jquery.propertytable.js?${project.version}"></script>
|
||||
<script type="text/javascript" src="js/jquery/tagcloud/jquery.tagcloud.js?${project.version}"></script>
|
||||
<script type="text/javascript" src="js/jquery/statusbar/jquery.statusbar.js?${project.version}"></script>
|
||||
</head>
|
||||
<body ng-controller="ngCanvasAppCtrl" id="canvas-body">
|
||||
<div id="splash">
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
--%>
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
|
||||
<div id="processor-configuration" layout="column" class="hidden large-dialog">
|
||||
<div id="processor-configuration-status-bar"></div>
|
||||
<div class="processor-configuration-tab-container dialog-content">
|
||||
<div id="processor-configuration-tabs" class="tab-container"></div>
|
||||
<div id="processor-configuration-tabs-content">
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
--%>
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
|
||||
<div id="processor-details" class="hidden large-dialog">
|
||||
<div id="processor-details-status-bar"></div>
|
||||
<div class="dialog-content">
|
||||
<div id="processor-details-tabs" class="tab-container"></div>
|
||||
<div id="processor-details-tabs-content">
|
||||
|
|
|
@ -415,6 +415,33 @@ input.filter {
|
|||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* overlay icon styles */
|
||||
|
||||
.stop-configure-icon.fa-stop {
|
||||
display : inline-block;
|
||||
font-size: 15px;
|
||||
position : relative;
|
||||
top : -1px;
|
||||
}
|
||||
|
||||
.stop-configure-icon::after {
|
||||
content : "\f013";
|
||||
font-size: 14px;
|
||||
position : relative;
|
||||
top : 0px;
|
||||
left : -8px;
|
||||
color : #ffffff;
|
||||
-webkit-text-stroke-width : 1px;
|
||||
-webkit-text-stroke-color : #004849;
|
||||
|
||||
}
|
||||
|
||||
*.stop-configure-icon + span {
|
||||
display : inline-block;
|
||||
padding : 0px 0px 0px 0px;
|
||||
margin-left : -10px;
|
||||
}
|
||||
|
||||
/* buttons */
|
||||
|
||||
button.fa {
|
||||
|
@ -443,6 +470,11 @@ div.button-icon {
|
|||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
div.button.auto-width,
|
||||
div.button-icon.auto-width {
|
||||
width : auto !important;
|
||||
}
|
||||
|
||||
div.button {
|
||||
height: 32px;
|
||||
width: 90px;
|
||||
|
|
|
@ -187,3 +187,8 @@ div.processor-relationship-container {
|
|||
#processor-comments {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* status bar button icon */
|
||||
#processor-configuration div.dialog-status-bar div.button-icon.fa-hourglass-end {
|
||||
font-size : 11px !important;
|
||||
}
|
|
@ -71,3 +71,8 @@ div.relationship-description {
|
|||
margin-left: 16px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* status bar button icon */
|
||||
#processor-details div.dialog-status-bar div.button-icon.fa-cog {
|
||||
font-size : 14px !important;
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
Styles for the Nifi status bar module.
|
||||
*/
|
||||
|
||||
.dialog-status-bar {
|
||||
padding-left : 32px;
|
||||
background-color : #e3e8eb;
|
||||
width : calc(100% - 32px);
|
||||
height : 32px;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state] + .dialog-content {
|
||||
top: 104px;
|
||||
}
|
||||
|
||||
.dialog-status-bar:not([state]),
|
||||
.dialog-status-bar:not([state]) text.run-status-icon,
|
||||
.dialog-status-bar-bulletins-content,
|
||||
.dialog-status-bar-bulletins[count="0"],
|
||||
.dialog-status-bar-threads[count="0"] {
|
||||
display : none;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state] text.run-status-icon {
|
||||
position : absolute;
|
||||
font-style : normal;
|
||||
font-weight : normal;
|
||||
text-decoration : inherit;
|
||||
font-family : FontAwesome;
|
||||
font-size : 14px;
|
||||
margin: 8px 5px 0px -17px;
|
||||
}
|
||||
|
||||
.dialog-status-bar-buttons,
|
||||
.dialog-status-bar[state] text.run-status-icon:before {
|
||||
display : inline-block;
|
||||
}
|
||||
|
||||
.dialog-status-bar-buttons {
|
||||
float : right;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state="RUNNING"] text.run-status-icon::before {
|
||||
content : "\f04b";
|
||||
color : #7dc7a0;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state="STOPPED"] text.run-status-icon::before {
|
||||
content : "\f04d";
|
||||
color : #d18686;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state="VALIDATING"] text.run-status-icon::before {
|
||||
content: '\f1ce';
|
||||
color : #7728e9b;
|
||||
-webkit-animation: fa-spin 2s linear infinite;
|
||||
-moz-animation: fa-spin 2s linear infinite;
|
||||
animation: fa-spin 2s linear infinite;
|
||||
margin-left : -3px !important;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state="DISABLED"] text.run-status-icon::before {
|
||||
content: '\e802';
|
||||
color : #7728e9b;
|
||||
font-family: flowfont;
|
||||
}
|
||||
|
||||
.dialog-status-bar[state="INVALID"] text.run-status-icon::before {
|
||||
content : "\f071";
|
||||
color : #cf9f5d;
|
||||
margin-left : -3px !important;
|
||||
}
|
||||
|
||||
.dialog-status-bar-state,
|
||||
.dialog-status-bar-threads:not([count="0"]){
|
||||
display : inline-block;
|
||||
position : relative;
|
||||
font-size : 12px;
|
||||
color : #775351;
|
||||
top : 10px;
|
||||
left : -2px;
|
||||
margin-right : 5px;
|
||||
font-weight : bold;
|
||||
cursor : default;
|
||||
}
|
||||
|
||||
.dialog-status-bar .dialog-buttons {
|
||||
position: static;
|
||||
display : inline-block !important;
|
||||
height: 32px;
|
||||
width : auto !important;
|
||||
}
|
||||
|
||||
.dialog-status-bar-bulletins:not([count="0"]) {
|
||||
float : right;
|
||||
display : inline-block;
|
||||
padding : 10px 8px 7px 8px;
|
||||
background-color : #ba544a;
|
||||
color : #ffffff;
|
||||
font-size : 15px;
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
.dialog-status-bar-bulletins:not([count="0"]):hover .dialog-status-bar-bulletins-content {
|
||||
position : fixed;
|
||||
display : block;
|
||||
float : right;
|
||||
margin-left : 22px;
|
||||
margin-top : 5px;
|
||||
background-color : rgba(36,36,36,0.75);
|
||||
font-family: Arial;
|
||||
font-weight : bold;
|
||||
font-size : 12px;
|
||||
padding : 10px 10px 10px 20px;
|
||||
width : auto;
|
||||
max-width : 490px;
|
||||
}
|
||||
|
||||
.dialog-status-bar-bulletins-content ul {
|
||||
list-style-type : disc !important;
|
||||
}
|
||||
|
||||
.dialog-status-bar-buttons *.disabled-button {
|
||||
display:none;
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new status bar.
|
||||
*
|
||||
* $(selector).statusbar();
|
||||
*
|
||||
*
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
// static key path variables
|
||||
var PROCESSOR_ID_KEY = 'component.id',
|
||||
ACTIVE_THREAD_COUNT_KEY = 'status.aggregateSnapshot.activeThreadCount',
|
||||
RUN_STATUS_KEY = 'status.aggregateSnapshot.runStatus',
|
||||
BULLETINS_KEY = 'bulletins';
|
||||
|
||||
var isUndefined = function (obj) {
|
||||
return typeof obj === 'undefined';
|
||||
};
|
||||
|
||||
var isNull = function (obj) {
|
||||
return obj === null;
|
||||
};
|
||||
|
||||
var isDefinedAndNotNull = function (obj) {
|
||||
return !isUndefined(obj) && !isNull(obj);
|
||||
};
|
||||
|
||||
var getKeyValue = function(obj,key){
|
||||
return key.split('.').reduce(function(o,x){
|
||||
return(typeof o === undefined || o === null)? o : (typeof o[x] == 'function')?o[x]():o[x];
|
||||
}, obj);
|
||||
};
|
||||
|
||||
var methods = {
|
||||
|
||||
/**
|
||||
* Initializes the status bar.
|
||||
*/
|
||||
init: function () {
|
||||
// get the combo
|
||||
var bar = $(this).addClass('dialog-status-bar');
|
||||
|
||||
bar.html('<text class="run-status-icon"></text>'+
|
||||
'<span class="dialog-status-bar-state"></span>'+
|
||||
'<span class="dialog-status-bar-threads" count="0"></span>'+
|
||||
'<div class="dialog-status-bar-bulletins fa fa-sticky-note-o" count="0">'+
|
||||
'<div class="dialog-status-bar-bulletins-content"></div>'+
|
||||
'</div>'+
|
||||
'<div class="dialog-status-bar-buttons"></div>');
|
||||
return bar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the status bar.
|
||||
*/
|
||||
show: function () {
|
||||
var bar = $(this);
|
||||
if (bar.is(':visible')) {
|
||||
bar.show();
|
||||
}
|
||||
return bar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the status bar.
|
||||
*/
|
||||
hide: function () {
|
||||
var bar = $(this);
|
||||
if (bar.is(':visible')) {
|
||||
bar.hide();
|
||||
}
|
||||
return bar;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the synchronization process to the canvas element
|
||||
*
|
||||
* @param id - id value of the processor to observe
|
||||
* @param cb - callback to execute when a mutation is detected
|
||||
*/
|
||||
observe: function(id,cb) {
|
||||
var bar = $(this);
|
||||
var g = document.querySelector('g[id="id-'+id+'"]');
|
||||
|
||||
//perform the initial set
|
||||
bar.statusbar('set',id);
|
||||
|
||||
//create and store an observer
|
||||
bar.data('observer',new MutationObserver(function(mutations){
|
||||
bar.statusbar('set',id);
|
||||
if(typeof cb == 'function'){
|
||||
cb();
|
||||
}
|
||||
}));
|
||||
|
||||
//initialize the observer
|
||||
bar.data('observer').observe(g,{attributes:true,childList:true,subtree:true});
|
||||
|
||||
return bar.data('observer');
|
||||
},
|
||||
|
||||
/**
|
||||
* Terminates the synchronization process
|
||||
*/
|
||||
disconnect: function () {
|
||||
var bar = $(this);
|
||||
if(isDefinedAndNotNull(bar.data('observer'))){
|
||||
bar.data('observer').disconnect();
|
||||
bar.data('observer',null);
|
||||
}
|
||||
if(isDefinedAndNotNull(bar.data('buttonModel'))){
|
||||
bar.data('buttonModel', []);
|
||||
bar.statusbar('refreshButtons',[]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the buttons with the existing button model.
|
||||
*/
|
||||
refreshButtons: function () {
|
||||
var bar = $(this);
|
||||
bar.statusbar('buttons',bar.data('buttonModel'));
|
||||
return bar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides all buttons
|
||||
*/
|
||||
hideButtons: function () {
|
||||
var bar = $(this);
|
||||
bar.find('.dialog-status-bar-buttons').hide();
|
||||
return bar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows all buttons.
|
||||
*/
|
||||
showButtons: function () {
|
||||
var bar = $(this);
|
||||
bar.find('.dialog-status-bar-buttons').show(250);
|
||||
return bar;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets/Retrieves the buttons on the status bar
|
||||
*
|
||||
* @param [{object}] button objects to apply
|
||||
*/
|
||||
buttons : function(buttons){
|
||||
var bar = $(this),
|
||||
buttonWrapper = bar.find('.dialog-status-bar-buttons');
|
||||
|
||||
if(isDefinedAndNotNull(buttons)){
|
||||
//remove any existing buttons
|
||||
buttonWrapper.children().remove();
|
||||
|
||||
//add in new buttons
|
||||
$.each(buttons, function (i, buttonConfig) {
|
||||
var isDisabled = function () {
|
||||
return typeof buttonConfig.disabled === 'function' && buttonConfig.disabled.call() === true;
|
||||
};
|
||||
|
||||
// create the button
|
||||
var button = $('<div class="button"></div>');
|
||||
if(buttonConfig.buttonText){
|
||||
button.append($('<span></span>').text(buttonConfig.buttonText));
|
||||
}
|
||||
else if(buttonConfig.buttonHtml){
|
||||
button.html(buttonConfig.buttonHtml);
|
||||
}
|
||||
|
||||
// add the class if specified
|
||||
if (isDefinedAndNotNull(buttonConfig.clazz)) {
|
||||
button.addClass(buttonConfig.clazz);
|
||||
}
|
||||
|
||||
// set the color if specified
|
||||
if (isDefinedAndNotNull(buttonConfig.color)) {
|
||||
button.css({
|
||||
'background': buttonConfig.color.base,
|
||||
'color': buttonConfig.color.text
|
||||
});
|
||||
}
|
||||
|
||||
// check if the button should be disabled
|
||||
if (isDisabled()) {
|
||||
button.addClass('disabled-button');
|
||||
} else {
|
||||
// enable custom hover if specified
|
||||
if (isDefinedAndNotNull(buttonConfig.color)) {
|
||||
button.hover(function () {
|
||||
$(this).css("background-color", buttonConfig.color.hover);
|
||||
}, function () {
|
||||
$(this).css("background-color", buttonConfig.color.base);
|
||||
});
|
||||
}
|
||||
|
||||
button.click(function () {
|
||||
var handler = $(this).data('handler');
|
||||
if (isDefinedAndNotNull(handler) && typeof handler.click === 'function') {
|
||||
handler.click.call(bar);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// add the button to the wrapper
|
||||
button.data('handler', buttonConfig.handler).appendTo(buttonWrapper);
|
||||
});
|
||||
|
||||
// store the button model to refresh later
|
||||
bar.data('buttonModel', buttons);
|
||||
}
|
||||
|
||||
//return the buttons as an array object
|
||||
buttons = [];
|
||||
$.each(buttonWrapper.find('.button'),function(i, button){
|
||||
buttons.push($(button));
|
||||
});
|
||||
return buttons;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the status bar display values
|
||||
*
|
||||
* @param id - processor id to evaluate
|
||||
*/
|
||||
set : function(id) {
|
||||
var bar = $(this),
|
||||
obj = d3.select('#id-' + id).datum(),
|
||||
bulletinList = $("<ul></ul>"),
|
||||
runStatus = getKeyValue(obj,RUN_STATUS_KEY),
|
||||
activeThreadCount = getKeyValue(obj,ACTIVE_THREAD_COUNT_KEY),
|
||||
bulletins = getKeyValue(obj,BULLETINS_KEY);
|
||||
|
||||
//set the values
|
||||
if(isDefinedAndNotNull(runStatus) &&
|
||||
isDefinedAndNotNull(activeThreadCount) &&
|
||||
isDefinedAndNotNull(bulletins) &&
|
||||
Array.isArray(bulletins)) {
|
||||
|
||||
bar.attr('state',runStatus.toUpperCase());
|
||||
bar.find('.dialog-status-bar-state').text(runStatus);
|
||||
bar.find('.dialog-status-bar-threads').attr('count',activeThreadCount);
|
||||
bar.find('.dialog-status-bar-threads').attr('title',activeThreadCount+' active threads');
|
||||
bar.find('.dialog-status-bar-threads').text('('+activeThreadCount+')');
|
||||
$.each(bulletins, function(i,item){
|
||||
if(item.canRead){
|
||||
bulletinList.append($('<li>'+item.bulletin.timestamp+' '+item.bulletin.level+'<br/>'+item.bulletin.message+'<br> </li>'));
|
||||
}
|
||||
});
|
||||
var bulletinCount = bulletinList.find('li').length;
|
||||
bar.find('.dialog-status-bar-bulletins-content').html((bulletinCount > 0)?bulletinList:'');
|
||||
bar.find('.dialog-status-bar-bulletins').attr('count',bulletinCount);
|
||||
|
||||
//update the button state
|
||||
bar.statusbar('refreshButtons');
|
||||
}
|
||||
return bar;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.statusbar = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else {
|
||||
return methods.init.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -701,8 +701,9 @@
|
|||
* Stops the components in the specified selection.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
* @argument {cb} callback The function to call when request is processed
|
||||
*/
|
||||
stop: function (selection) {
|
||||
stop: function (selection,cb) {
|
||||
if (selection.empty()) {
|
||||
// build the entity
|
||||
var entity = {
|
||||
|
@ -753,18 +754,41 @@
|
|||
if (stopRequests.length > 0) {
|
||||
$.when.apply(window, stopRequests).always(function () {
|
||||
nfNgBridge.digest();
|
||||
if(typeof cb == 'function'){
|
||||
cb();
|
||||
}
|
||||
});
|
||||
} else if(typeof cb == 'function'){
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the component and displays the processor configuration dialog
|
||||
*
|
||||
* @param {selection} selection The selection
|
||||
* @param {cb} callback The function to call when complete
|
||||
*/
|
||||
stopAndConfigure: function (selection,cb) {
|
||||
if(selection.size() === 1 &&
|
||||
nfCanvasUtils.isProcessor(selection) &&
|
||||
nfCanvasUtils.canModify(selection)){
|
||||
|
||||
nfActions.stop(selection,function(){
|
||||
nfProcessorConfiguration.showConfiguration(selection,cb);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Terminates active threads for the selected component.
|
||||
*
|
||||
* @param {selection} selection
|
||||
* @param {selection} selection
|
||||
* @param {cb} callback The function to call when complete
|
||||
*/
|
||||
terminate: function (selection) {
|
||||
terminate: function (selection,cb) {
|
||||
if (selection.size() === 1 && nfCanvasUtils.isProcessor(selection)) {
|
||||
var selectionData = selection.datum();
|
||||
|
||||
|
@ -774,6 +798,9 @@
|
|||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
nfProcessor.set(response);
|
||||
if(typeof cb == 'function'){
|
||||
cb();
|
||||
}
|
||||
}).fail(nfErrorHandler.handleAjaxError);
|
||||
}
|
||||
},
|
||||
|
@ -831,14 +858,15 @@
|
|||
* Shows the configuration dialog for the specified selection.
|
||||
*
|
||||
* @param {selection} selection Selection of the component to be configured
|
||||
* @param {fn} callback Callback
|
||||
*/
|
||||
showConfiguration: function (selection) {
|
||||
showConfiguration: function (selection,cb) {
|
||||
if (selection.empty()) {
|
||||
nfProcessGroupConfiguration.showConfiguration(nfCanvasUtils.getGroupId());
|
||||
} else if (selection.size() === 1) {
|
||||
var selectionData = selection.datum();
|
||||
if (nfCanvasUtils.isProcessor(selection)) {
|
||||
nfProcessorConfiguration.showConfiguration(selection);
|
||||
nfProcessorConfiguration.showConfiguration(selection,cb);
|
||||
} else if (nfCanvasUtils.isLabel(selection)) {
|
||||
nfLabelConfiguration.showConfiguration(selection);
|
||||
} else if (nfCanvasUtils.isProcessGroup(selection)) {
|
||||
|
@ -871,7 +899,11 @@
|
|||
} else if (selection.size() === 1) {
|
||||
var selectionData = selection.datum();
|
||||
if (nfCanvasUtils.isProcessor(selection)) {
|
||||
nfProcessorDetails.showDetails(nfCanvasUtils.getGroupId(), selectionData.id);
|
||||
if(!nfCanvasUtils.isStoppable(selection) && nfCanvasUtils.canModify(selection)){
|
||||
nfProcessorConfiguration.showConfiguration(selection);
|
||||
} else {
|
||||
nfProcessorDetails.showDetails(nfCanvasUtils.getGroupId(), selectionData.id);
|
||||
}
|
||||
} else if (nfCanvasUtils.isProcessGroup(selection)) {
|
||||
nfProcessGroupConfiguration.showConfiguration(selectionData.id);
|
||||
} else if (nfCanvasUtils.isRemoteProcessGroup(selection)) {
|
||||
|
|
|
@ -365,14 +365,22 @@
|
|||
nfControllerService.init(nfControllerServices, nfReportingTask);
|
||||
nfReportingTask.init(nfSettings);
|
||||
nfPolicyManagement.init();
|
||||
nfProcessorConfiguration.init();
|
||||
nfProcessorConfiguration.init({
|
||||
supportsStatusBar : true,
|
||||
nfActions : nfActions
|
||||
});
|
||||
// initialize the PG config and invert control of the controllerServices
|
||||
nfProcessGroupConfiguration.init(nfControllerServices);
|
||||
nfRemoteProcessGroupConfiguration.init();
|
||||
nfRemoteProcessGroupPorts.init();
|
||||
nfPortConfiguration.init();
|
||||
nfLabelConfiguration.init();
|
||||
nfProcessorDetails.init(true);
|
||||
nfProcessorDetails.init({
|
||||
supportsGoTo : true,
|
||||
supportsStatusBar : true,
|
||||
nfCanvasUtils : nfCanvasUtils,
|
||||
nfActions : nfActions
|
||||
});
|
||||
nfPortDetails.init();
|
||||
nfConnectionDetails.init();
|
||||
nfRemoteProcessGroupDetails.init();
|
||||
|
|
|
@ -574,6 +574,16 @@
|
|||
return d3.selectAll('g.component.selected, g.connection.selected');
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the selection object of the id passed.
|
||||
*
|
||||
* @param {id} The uuid of the component to retrieve
|
||||
* @returns {selection} The selection object of the component id passed
|
||||
*/
|
||||
getSelectionById: function(id){
|
||||
return d3.select('#id-' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the coordinates neccessary to center a bounding box on the screen.
|
||||
*
|
||||
|
|
|
@ -61,7 +61,15 @@
|
|||
* @param {selection} selection The selection of currently selected components
|
||||
*/
|
||||
var isConfigurable = function (selection) {
|
||||
return nfCanvasUtils.isConfigurable(selection);
|
||||
if(selection.size() == 1 &&
|
||||
nfCanvasUtils.isProcessor(selection) &&
|
||||
nfCanvasUtils.canModify(selection) &&
|
||||
(nfCanvasUtils.isConfigurable(selection) ||
|
||||
canTerminate(selection))){
|
||||
return true;
|
||||
} else {
|
||||
return nfCanvasUtils.isConfigurable(selection);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -79,7 +87,13 @@
|
|||
* @param {selection} selection The selection of currently selected components
|
||||
*/
|
||||
var hasDetails = function (selection) {
|
||||
return nfCanvasUtils.hasDetails(selection);
|
||||
if(selection.size() == 1 &&
|
||||
nfCanvasUtils.isProcessor(selection) &&
|
||||
nfCanvasUtils.canModify(selection)){
|
||||
return !isConfigurable(selection);
|
||||
} else {
|
||||
return nfCanvasUtils.hasDetails(selection);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,9 +68,19 @@
|
|||
}(this, function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfUniversalCapture, nfConnection) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Configuration option variable for the nfProcessorDetails dialog
|
||||
*/
|
||||
var config;
|
||||
|
||||
// possible values for a processor's run duration (in millis)
|
||||
var RUN_DURATION_VALUES = [0, 25, 50, 100, 250, 500, 1000, 2000];
|
||||
|
||||
// key paths to the status objects
|
||||
var ACTIVE_THREAD_COUNT_KEY = 'status.aggregateSnapshot.activeThreadCount',
|
||||
RUN_STATUS_KEY = 'status.aggregateSnapshot.runStatus',
|
||||
BULLETINS_KEY = 'bulletins';
|
||||
|
||||
/**
|
||||
* Gets the available scheduling strategies based on the specified processor.
|
||||
*
|
||||
|
@ -492,8 +502,13 @@
|
|||
return {
|
||||
/**
|
||||
* Initializes the processor properties tab.
|
||||
*
|
||||
* @param {options} The configuration options object for the dialog
|
||||
*/
|
||||
init: function () {
|
||||
init: function (options) {
|
||||
//set the configuration options
|
||||
config = options;
|
||||
|
||||
// initialize the properties tabs
|
||||
$('#processor-configuration-tabs').tabbs({
|
||||
tabStyle: 'tab',
|
||||
|
@ -546,6 +561,11 @@
|
|||
|
||||
// removed the cached processor details
|
||||
$('#processor-configuration').removeData('processorDetails');
|
||||
|
||||
//stop any synchronization
|
||||
if(config.supportsStatusBar){
|
||||
$('#processor-configuration-status-bar').statusbar('disconnect');
|
||||
}
|
||||
},
|
||||
open: function () {
|
||||
nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0));
|
||||
|
@ -553,6 +573,11 @@
|
|||
}
|
||||
});
|
||||
|
||||
//if the status bar is supported, initialize it.
|
||||
if(config.supportsStatusBar){
|
||||
$('#processor-configuration-status-bar').statusbar();
|
||||
}
|
||||
|
||||
// initialize the bulletin combo
|
||||
$('#bulletin-level-combo').combo({
|
||||
options: [{
|
||||
|
@ -612,8 +637,9 @@
|
|||
* Shows the configuration dialog for the specified processor.
|
||||
*
|
||||
* @argument {selection} selection The selection
|
||||
* @argument {cb} callback The callback function to execute after the dialog is displayed
|
||||
*/
|
||||
showConfiguration: function (selection) {
|
||||
showConfiguration: function (selection, cb) {
|
||||
if (nfCanvasUtils.isProcessor(selection)) {
|
||||
var selectionData = selection.datum();
|
||||
|
||||
|
@ -773,6 +799,9 @@
|
|||
hover: '#004849',
|
||||
text: '#ffffff'
|
||||
},
|
||||
disabled : function() {
|
||||
return !nfCanvasUtils.supportsModification(selection);
|
||||
},
|
||||
handler: {
|
||||
click: function () {
|
||||
// close all fields currently being edited
|
||||
|
@ -792,19 +821,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
buttonText: 'Cancel',
|
||||
color: {
|
||||
base: '#E3E8EB',
|
||||
hover: '#C7D2D7',
|
||||
text: '#004849'
|
||||
},
|
||||
handler: {
|
||||
click: function () {
|
||||
$('#processor-configuration').modal('hide');
|
||||
}
|
||||
{
|
||||
buttonText: 'Cancel',
|
||||
color: {
|
||||
base: '#E3E8EB',
|
||||
hover: '#C7D2D7',
|
||||
text: '#004849'
|
||||
},
|
||||
handler: {
|
||||
click: function () {
|
||||
$('#processor-configuration').modal('hide');
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
|
||||
// determine if we should show the advanced button
|
||||
if (nfCommon.isDefinedAndNotNull(processor.config.customUiUrl) && processor.config.customUiUrl !== '') {
|
||||
|
@ -858,6 +887,55 @@
|
|||
});
|
||||
}
|
||||
|
||||
//Synchronize the current component canvas attributes in the status bar
|
||||
if(config.supportsStatusBar){
|
||||
|
||||
//initialize the canvas synchronization
|
||||
$("#processor-configuration-status-bar").statusbar('observe',processor.id, function(){
|
||||
$('#processor-configuration').modal('refreshButtons');
|
||||
});
|
||||
|
||||
//if there are active threads, add the terminate button to the status bar
|
||||
if(nfCommon.isDefinedAndNotNull(config.nfActions) &&
|
||||
nfCommon.getKeyValue(processorResponse,ACTIVE_THREAD_COUNT_KEY) != 0){
|
||||
|
||||
$("#processor-configuration-status-bar").statusbar('buttons',[{
|
||||
buttonText: 'Terminate',
|
||||
clazz: 'fa fa-hourglass-end button-icon',
|
||||
color: {
|
||||
hover: '#C7D2D7',
|
||||
base: 'transparent',
|
||||
text: '#004849'
|
||||
},
|
||||
disabled : function() {
|
||||
return nfCanvasUtils.supportsModification(selection);
|
||||
},
|
||||
handler: {
|
||||
click: function() {
|
||||
var cb = function(){
|
||||
var p = nfProcessor.get(processor.id);
|
||||
if(nfCommon.getKeyValue(p,ACTIVE_THREAD_COUNT_KEY) != 0){
|
||||
nfDialog.showOkDialog({
|
||||
dialogContent: 'Terminate threads request was processed, but active threads still persist. Please try again later.',
|
||||
headerText: 'Unable to Terminate'
|
||||
});
|
||||
}
|
||||
else {
|
||||
//refresh the dialog
|
||||
$('#processor-configuration-status-bar').statusbar('refreshButtons');
|
||||
$('#processor-configuration').modal('refreshButtons');
|
||||
}
|
||||
$('#processor-configuration-status-bar').statusbar('showButtons');
|
||||
};
|
||||
|
||||
//execute the terminate call
|
||||
$('#processor-configuration-status-bar').statusbar('hideButtons');
|
||||
config.nfActions.terminate(selection,cb);
|
||||
}
|
||||
}
|
||||
}]);
|
||||
}
|
||||
}
|
||||
// set the button model
|
||||
$('#processor-configuration').modal('setButtonModel', buttons);
|
||||
|
||||
|
@ -877,6 +955,17 @@
|
|||
if (processorRelationships.is(':visible') && processorRelationships.get(0).scrollHeight > Math.round(processorRelationships.innerHeight())) {
|
||||
processorRelationships.css('border-width', '1px');
|
||||
}
|
||||
|
||||
// Ensure the properties table has rendered correctly if initially selected
|
||||
if ($('#processor-configuration-tabs').find('.selected-tab').text() === 'Properties' &&
|
||||
$('#processor-properties').find('.slick-viewport').height() == 0) {
|
||||
$('#processor-properties').propertytable('resetTableSize');
|
||||
}
|
||||
|
||||
//execute the callback if one was provided
|
||||
if(typeof cb == 'function'){
|
||||
cb();
|
||||
}
|
||||
}).fail(nfErrorHandler.handleAjaxError);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1714,6 +1714,19 @@
|
|||
*/
|
||||
throttle: function (func, wait) {
|
||||
return _.throttle(func, wait);
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the corresponding value of the object key passed
|
||||
*
|
||||
* @param {object} obj The obj to search
|
||||
* @param {string} key The key path to return
|
||||
* @returns {object/literal} The value of the key passed or undefined/null
|
||||
*/
|
||||
getKeyValue : function(obj,key){
|
||||
return key.split('.').reduce(function(o,x){
|
||||
return(typeof o === undefined || o === null)? o : (typeof o[x] == 'function')?o[x]():o[x];
|
||||
}, obj);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
}(this, function ($, nfCommon, nfUniversalCapture, nfDialog, nfErrorHandler, nfCustomUi, nfClusterSummary) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Configuration option variable for the nfProcessorDetails dialog
|
||||
*/
|
||||
var config;
|
||||
|
||||
/**
|
||||
* Creates an option for the specified relationship name.
|
||||
*
|
||||
|
@ -76,8 +81,13 @@
|
|||
return {
|
||||
/**
|
||||
* Initializes the processor details dialog.
|
||||
*
|
||||
* @param {options} The configuration options object for the dialog
|
||||
*/
|
||||
init: function (supportsGoTo) {
|
||||
init: function (options) {
|
||||
|
||||
//set the dialog window configuration options.
|
||||
config = options;
|
||||
|
||||
// initialize the properties tabs
|
||||
$('#processor-details-tabs').tabbs({
|
||||
|
@ -143,6 +153,11 @@
|
|||
// removed the cached processor details
|
||||
$('#processor-details').removeData('processorDetails');
|
||||
$('#processor-details').removeData('processorHistory');
|
||||
|
||||
//stop any synchronization on the status bar
|
||||
if(config.supportsStatusBar){
|
||||
$("#processor-details-status-bar").statusbar('disconnect');
|
||||
}
|
||||
},
|
||||
open: function () {
|
||||
nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0));
|
||||
|
@ -150,9 +165,14 @@
|
|||
}
|
||||
});
|
||||
|
||||
//apply the status bar if indicated
|
||||
if(config.supportsStatusBar){
|
||||
$("#processor-details-status-bar").statusbar();
|
||||
}
|
||||
|
||||
// initialize the properties
|
||||
$('#read-only-processor-properties').propertytable({
|
||||
supportsGoTo: supportsGoTo,
|
||||
supportsGoTo: config.supportsGoTo,
|
||||
readOnly: true
|
||||
});
|
||||
},
|
||||
|
@ -255,6 +275,7 @@
|
|||
var processor = processorResponse.component;
|
||||
var historyResponse = historyResult[0];
|
||||
var history = historyResponse.componentHistory;
|
||||
var selection;
|
||||
|
||||
// load the properties
|
||||
$('#read-only-processor-properties').propertytable('loadProperties', processor.config.properties, processor.config.descriptors, history.propertyHistory);
|
||||
|
@ -296,6 +317,70 @@
|
|||
});
|
||||
}
|
||||
|
||||
//Populate the status bar if the feature is enabled
|
||||
if (config.supportsStatusBar && nfCommon.isDefinedAndNotNull(config.nfCanvasUtils)){
|
||||
|
||||
//initialize the canvas synchronization
|
||||
$("#processor-details-status-bar").statusbar('observe',processor.id);
|
||||
|
||||
//Fetch the component as a selection from the canvas
|
||||
selection = config.nfCanvasUtils.getSelectionById(processor.id);
|
||||
|
||||
//Add the stop & configure button if appropriate
|
||||
if(nfCommon.isDefinedAndNotNull(config.nfActions) &&
|
||||
config.nfCanvasUtils.isProcessor(selection) &&
|
||||
config.nfCanvasUtils.canModify(selection)){
|
||||
|
||||
//Declare a callback handler to perform should ProcessorConfiguration be invoked
|
||||
var cb = function(){
|
||||
var selectedTab = $('#processor-details-tabs').find('.selected-tab').text();
|
||||
$('#processor-configuration-tabs').find('.tab:contains("'+selectedTab+'")').trigger('click');
|
||||
$('#processor-details').modal('hide');
|
||||
$("#processor-details-status-bar").statusbar('showButtons');
|
||||
};
|
||||
|
||||
$("#processor-details-status-bar").statusbar('buttons',[{
|
||||
buttonHtml: '<i class="fa fa-stop stop-configure-icon" aria-hidden="true"></i><span>Stop & Configure</span>',
|
||||
clazz: 'button button-icon auto-width',
|
||||
color: {
|
||||
hover: '#C7D2D7',
|
||||
base: 'transparent',
|
||||
text: '#004849'
|
||||
},
|
||||
disabled : function() {
|
||||
return !config.nfCanvasUtils.isStoppable(selection);
|
||||
},
|
||||
handler: {
|
||||
click: function() {
|
||||
//execute the stop and open the configuration modal
|
||||
$("#processor-details-status-bar").statusbar('hideButtons');
|
||||
config.nfActions.stopAndConfigure(selection,cb);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
buttonText: 'Configure',
|
||||
clazz: 'fa fa-cog button-icon',
|
||||
color: {
|
||||
hover: '#C7D2D7',
|
||||
base: 'transparent',
|
||||
text: '#004849'
|
||||
},
|
||||
disabled : function() {
|
||||
return config.nfCanvasUtils.isStoppable(selection);
|
||||
},
|
||||
handler: {
|
||||
click: function() {
|
||||
//execute the stop and open the configuration modal
|
||||
$("#processor-details-status-bar").statusbar('hideButtons');
|
||||
config.nfActions.showConfiguration(selection,cb);
|
||||
}
|
||||
}
|
||||
}]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// show the dialog
|
||||
$('#processor-details').modal('setButtonModel', buttons).modal('show');
|
||||
|
||||
|
|
|
@ -3041,7 +3041,10 @@
|
|||
nfStatusHistory.init(configDetails.timeOffset);
|
||||
|
||||
// initialize the processor/connection details dialog
|
||||
nfProcessorDetails.init(false);
|
||||
nfProcessorDetails.init({
|
||||
supportsGoTo : false,
|
||||
supportsStatusBar : false
|
||||
});
|
||||
nfConnectionDetails.init();
|
||||
initSummaryTable(isClustered);
|
||||
|
||||
|
|
Loading…
Reference in New Issue