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:
Alex Aversa 2019-01-30 21:09:56 +00:00 committed by Matt Gilman
parent 31463c5dad
commit c5c9425989
No known key found for this signature in database
GPG Key ID: DF61EC19432AEE37
16 changed files with 756 additions and 27 deletions

View File

@ -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">

View File

@ -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">

View File

@ -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">

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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>&nbsp;</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);

View File

@ -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)) {

View File

@ -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();

View File

@ -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.
*

View File

@ -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);
}
};
/**

View File

@ -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);
}
}

View File

@ -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);
}
};

View File

@ -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');

View File

@ -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);