NIFI-9288:

- Allowing the user to submit a verification request for Processors, Controller Services, and Reporting Tasks.
- Tracking progress of verification requests.
- Showing the verification results.

NIFI-9288:
- Fixing class name which prevented styles from being applied.

NIFI-9288:
- Ensuring that previously entered referenced attribute values take precedence.

NIFI-9288:
- Positioning the property listing and verification results based on percentages instead of fixed values.
- Removing the additional dialog height.

NIFI-9288:
- Allowing attribute value entry to be skipped when appropriate.

NIFI-9288:
- Working around an issue caused by css minification.

NIFI-9288:
- Adding some padding to the verifying progress dialog.

This closes #5461

Signed-off-by: Scott Aslan <scottyaslan@gmail.com>
This commit is contained in:
Matt Gilman 2021-10-08 16:50:14 -04:00 committed by Scott Aslan
parent 8e1b762998
commit 1bec905890
17 changed files with 1231 additions and 50 deletions

View File

@ -501,6 +501,7 @@
<include>${staging.dir}/js/nf/canvas/nf-canvas-utils.js</include>
<include>${staging.dir}/js/nf/canvas/nf-go-to.js</include>
<include>${staging.dir}/js/nf/canvas/nf-snippet.js</include>
<include>${staging.dir}/js/nf/canvas/nf-verify.js</include>
<include>${staging.dir}/js/nf/canvas/nf-connection.js</include>
<include>${staging.dir}/js/nf/canvas/nf-funnel.js</include>
<include>${staging.dir}/js/nf/canvas/nf-label.js</include>

View File

@ -31,6 +31,7 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-ng-bridge.js?
<script type="text/javascript" src="js/nf/canvas/nf-canvas-utils.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-go-to.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-snippet.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-verify.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-connection.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-funnel.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-label.js?${project.version}"></script>\n\

View File

@ -158,6 +158,8 @@
<jsp:include page="/WEB-INF/partials/canvas/drop-request-status-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/flowfile-details-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/verification-request-status-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/referenced-attributes-configuration.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/component-state-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/component-version-dialog.jsp"/>

View File

@ -66,6 +66,10 @@
</div>
<div id="controller-service-properties-tab-content" class="configuration-tab">
<div id="controller-service-properties"></div>
<div id="controller-service-properties-verification-results" class="verification-results">
<div class="verification-results-header">Verification Results</div>
<div id="controller-service-properties-verification-results-listing" class="verification-results-listing"></div>
</div>
</div>
<div id="controller-service-comments-tab-content" class="configuration-tab">
<textarea cols="30" rows="4" id="controller-service-comments" name="controller-service-comments" class="controller-service-editable setting-input"></textarea>
@ -79,4 +83,4 @@
</div>
</div>
</div>
<div id="new-controller-service-property-container"></div>
<div id="new-controller-service-property-container"></div>

View File

@ -218,6 +218,10 @@
</div>
<div id="processor-properties-tab-content" class="configuration-tab">
<div id="processor-properties"></div>
<div id="processor-properties-verification-results" class="verification-results">
<div class="verification-results-header">Verification Results</div>
<div id="processor-properties-verification-results-listing" class="verification-results-listing"></div>
</div>
</div>
<div id="processor-comments-tab-content" class="configuration-tab">
<textarea cols="30" rows="4" id="processor-comments" name="processor-comments" class="setting-input"></textarea>

View File

@ -0,0 +1,47 @@
<%--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--%>
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<div id="referenced-attributes-dialog" class="hidden medium-dialog">
<div class="dialog-content">
<div class="setting">
<div id="referenced-attributes-header">
<div id="referenced-attributes-title" class="setting-name">
Enter Attribute Values
<div class="fa fa-question-circle" alt="Info"
title="Supply attribute values that should be considered when performing property verification."></div>
</div>
<div id="add-referenced-attribute">
<button class="button fa fa-plus"></button>
</div>
<div class="clear"></div>
</div>
<div class="setting-field">
<div id="referenced-attributes-table"></div>
</div>
</div>
</div>
</div>
<div id="new-referenced-attribute-dialog" class="dialog cancellable small-dialog hidden">
<div class="dialog-content">
<div>
<div class="setting-name">Attribute name</div>
<div class="setting-field">
<input id="new-referenced-attribute-name" type="text"/>
</div>
</div>
</div>
</div>

View File

@ -83,6 +83,10 @@
</div>
<div id="reporting-task-properties-tab-content" class="configuration-tab">
<div id="reporting-task-properties"></div>
<div id="reporting-task-properties-verification-results" class="verification-results">
<div class="verification-results-header">Verification Results</div>
<div id="reporting-task-properties-verification-results-listing" class="verification-results-listing"></div>
</div>
</div>
<div id="reporting-task-comments-tab-content" class="configuration-tab">
<textarea cols="30" rows="4" id="reporting-task-comments" name="reporting-task-comments" class="reporting-task-editable setting-input"></textarea>
@ -96,4 +100,4 @@
</div>
</div>
</div>
<div id="new-reporting-task-property-container"></div>
<div id="new-reporting-task-property-container"></div>

View File

@ -0,0 +1,29 @@
<%--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--%>
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<div id="verification-request-status-dialog" layout="column" class="hidden small-dialog">
<div class="dialog-content">
<div class="setting">
<div class="setting-field">
<div id="verification-request-status-message"></div>
</div>
<div class="setting-field">
<div id="verification-request-percent-complete"></div>
</div>
</div>
</div>
</div>

View File

@ -284,6 +284,98 @@ div.local-changes-message {
font-size: 13px;
}
/*
Referenced Attributes
*/
#referenced-attributes-table {
position: relative;
height: 240px;
}
#add-referenced-attribute {
float: right;
margin-bottom: 4px;
font-size: 16px;
text-transform: uppercase;
}
#referenced-attributes-title {
font-size: 12px;
float: left;
height: 28px;
line-height: 28px;
margin-left: 6px;
}
#verification-request-percent-complete {
margin-top: 10px;
border-radius: 0;
}
div.verification-results {
display: none;
position: absolute;
top: calc(60% - -10px);
right: 0;
left: 0;
bottom: 0;
}
div.verification-results-header {
color: #728e9b;
font-size: 16px;
font-family: 'Roboto Slab';
font-style: normal;
font-weight: bold;
}
div.verification-results-listing {
border: 0 solid #CCCCCC;
overflow: auto;
position: absolute;
top: 20px;
right: 0;
left: 0;
bottom: 0;
padding: 10px;
}
div.verification-result {
margin-bottom: 8px;
}
div.verification-result-outcome {
float: left;
font-size: 14px;
width: 14px;
margin-right: 10px;
}
div.verification-result-outcome.fa-check {
color: #4fa885;
}
div.verification-result-outcome.fa-times {
color: #e21a1a;
}
div.verification-result-outcome.fa-exclamation {
color: #eB8f11;
}
div.verification-result-step-name {
float: left;
font-size: 14px;
font-weight: 500;
}
div.verification-result-explanation {
font-size: 12px;
margin-left: 24px;
margin-top: 2px;
}
/*
Variable Registry
*/

View File

@ -191,4 +191,4 @@ div.processor-relationship-container {
/* status bar button icon */
#processor-configuration div.dialog-status-bar div.button-icon.fa-hourglass-end {
font-size : 11px !important;
}
}

View File

@ -28,28 +28,20 @@ div.required-property-note {
margin-left: 6px;
}
div.add-property {
div.add-property, div.verify-properties {
float: right;
margin-bottom: 4px;
margin-left: 4px;
font-size: 16px;
text-transform: uppercase;
}
div.add-property-text {
float: left;
margin-left: 5px;
height: 19px;
line-height: 19px;
color: #262626;
}
div.property-table {
position: absolute;
top: 42px;
bottom: 0px;
left: 0px;
right: 0px;
min-height: 150px;
}
.property-table .fa {

View File

@ -105,6 +105,7 @@
_) {
var groupId = null;
var propertyVerificationCallback = null;
var COMBO_MIN_WIDTH = 212;
var EDITOR_MIN_WIDTH = 212;
var EDITOR_MIN_HEIGHT = 100;
@ -1784,6 +1785,22 @@
}
};
var marshalProperties = function (table) {
var properties = {};
var propertyGrid = table.data('gridInstance');
var propertyData = propertyGrid.getData();
$.each(propertyData.getItems(), function () {
if (this.hidden === true && !(this.dependent === true)) {
// hidden properties were removed by the user, clear the value
properties[this.property] = null;
} else if (this.value !== this.previousValue) {
// the value has changed
properties[this.property] = this.value;
}
});
return properties;
};
/**
* Performs the filtering.
*
@ -1954,7 +1971,8 @@
* return $.Deferred(function (deferred) {
* deferred.resolve();
* }).promise;
* }
* },
* propertyVerificationCallback: function () {}
* }
*
* @argument {object} options The options for the tag cloud
@ -2125,7 +2143,7 @@
newPropertyDialog.on('click', 'div.new-property-ok', add).on('click', 'div.new-property-cancel', cancel);
// build the control to open the new property dialog
var addProperty = $('<div class="add-property"></div>').appendTo(header);
var addProperty = $('<div class="add-property" title="Add Property"></div>').appendTo(header);
$('<button class="button fa fa-plus"></button>').on('click', function () {
// close all fields currently being edited
saveRow(table);
@ -2139,6 +2157,21 @@
// set the initial focus
newPropertyNameField.focus();
}).appendTo(addProperty);
// build the control to trigger verification
var verifyProperties = $('<div class="verify-properties hidden" title="Verify Properties"></div>').appendTo(header);
$('<button class="button fa fa-check-circle-o"></button>').on('click', function () {
// close all fields currently being edited
saveRow(table);
// invoke the verification callback with the current properties
propertyVerificationCallback(marshalProperties(table));
}).appendTo(verifyProperties);
// if there is a verification callback registered show the verify button
propertyVerificationCallback = options.propertyVerificationCallback;
var supportsVerification = typeof propertyVerificationCallback === 'function';
verifyProperties.toggleClass('hidden', !supportsVerification);
}
$('<div class="clear"></div>').appendTo(header);
@ -2265,18 +2298,7 @@
this.each(function () {
// get the property grid data
var table = $(this).find('div.property-table');
var propertyGrid = table.data('gridInstance');
var propertyData = propertyGrid.getData();
$.each(propertyData.getItems(), function () {
if (this.hidden === true && !(this.dependent === true)) {
// hidden properties were removed by the user, clear the value
properties[this.property] = null;
} else if (this.value !== this.previousValue) {
// the value has changed
properties[this.property] = this.value;
}
});
properties = marshalProperties(table);
return false;
});
@ -2291,6 +2313,18 @@
return this.each(function () {
groupId = currentGroupId;
});
},
/**
* Sets the property verification callback.
*/
setPropertyVerificationCallback: function (currentPropertyVerificationCallback) {
return this.each(function () {
propertyVerificationCallback = currentPropertyVerificationCallback;
var supportsVerification = typeof currentPropertyVerificationCallback === 'function';
$(this).find('div.verify-properties').toggleClass('hidden', !supportsVerification);
});
}
};

View File

@ -37,6 +37,7 @@
'nf.Snippet',
'nf.Actions',
'nf.QueueListing',
'nf.Verify',
'nf.VariableRegistry',
'nf.ComponentState',
'nf.FlowVersion',
@ -83,8 +84,8 @@
'nf.ng.Canvas.OperateCtrl',
'nf.ng.BreadcrumbsDirective',
'nf.ng.DraggableDirective'],
function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) {
return factory($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective);
function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) {
return factory($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective);
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = factory(require('jquery'),
@ -105,6 +106,7 @@
require('nf.Actions'),
require('nf.Snippet'),
require('nf.QueueListing'),
require('nf.Verify'),
require('nf.VariableRegistry'),
require('nf.ComponentState'),
require('nf.FlowVersion'),
@ -170,6 +172,7 @@
root.nf.Actions,
root.nf.Snippet,
root.nf.QueueListing,
root.nf.Verify,
root.nf.VariableRegistry,
root.nf.ComponentState,
root.nf.FlowVersion,
@ -217,7 +220,7 @@
root.nf.ng.BreadcrumbsDirective,
root.nf.ng.DraggableDirective);
}
}(this, function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) {
}(this, function ($, angular, nfCommon, nfCanvasUtils, nfErrorHandler, nfClient, nfDialog, nfStorage, nfCanvas, nfGraph, nfContextMenu, nfQuickSelect, nfShell, nfParameterContexts, nfSettings, nfActions, nfSnippet, nfQueueListing, nfVerify, nfVariableRegistry, nfComponentState, nfFlowVersion, nfComponentVersion, nfDraggable, nfConnectable, nfStatusHistory, nfBirdseye, nfConnectionConfiguration, nfControllerService, nfReportingTask, nfPolicyManagement, nfProcessorConfiguration, nfProcessGroupConfiguration, nfControllerServices, nfRemoteProcessGroupConfiguration, nfRemoteProcessGroupPorts, nfPortConfiguration, nfLabelConfiguration, nfProcessorDetails, nfPortDetails, nfConnectionDetails, nfRemoteProcessGroupDetails, nfGoto, nfNgBridge, appCtrl, appConfig, serviceProvider, breadcrumbsCtrl, headerCtrl, flowStatusCtrl, globalMenuCtrl, toolboxCtrl, processorComponent, inputPortComponent, outputPortComponent, processGroupComponent, remoteProcessGroupComponent, funnelComponent, templateComponent, labelComponent, graphControlsCtrl, navigateCtrl, operateCtrl, breadcrumbsDirective, draggableDirective) {
var config = {
urls: {
@ -349,6 +352,7 @@
nfParameterContexts.init();
nfActions.init();
nfQueueListing.init();
nfVerify.init();
nfVariableRegistry.init();
nfComponentState.init();
nfFlowVersion.init(configDetails.timeOffset);

View File

@ -29,10 +29,11 @@
'nf.Settings',
'nf.UniversalCapture',
'nf.CustomUi',
'nf.Verify',
'nf.CanvasUtils',
'nf.Processor'],
function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfCanvasUtils, nfProcessor) {
return (nf.ControllerService = factory($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfCanvasUtils, nfProcessor));
function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfVerify, nfCanvasUtils, nfProcessor) {
return (nf.ControllerService = factory($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfVerify, nfCustomUi, nfCanvasUtils, nfProcessor));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.ControllerService =
@ -46,6 +47,7 @@
require('nf.Settings'),
require('nf.UniversalCapture'),
require('nf.CustomUi'),
require('nf.Verify'),
require('nf.CanvasUtils'),
require('nf.Processor')));
} else {
@ -59,10 +61,11 @@
root.nf.Settings,
root.nf.UniversalCapture,
root.nf.CustomUi,
root.nf.Verify,
root.nf.CanvasUtils,
root.nf.Processor);
}
}(this, function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfCanvasUtils, nfProcessor) {
}(this, function ($, d3, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfSettings, nfUniversalCapture, nfCustomUi, nfVerify, nfCanvasUtils, nfProcessor) {
'use strict';
var nfControllerServices, nfReportingTask;
@ -77,6 +80,9 @@
}
};
// the last submitted referenced attributes
var referencedAttributes = null;
/**
* Determines whether the user has made any changes to the controller service configuration
* that needs to be saved.
@ -1696,6 +1702,29 @@
return referencedServices;
};
/**
* Handles verification results.
*/
var handleVerificationResults = function (verificationResults, referencedAttributeMap) {
// record the most recently submitted referenced attributes
referencedAttributes = referencedAttributeMap;
var verificationResultsContainer = $('#controller-service-properties-verification-results');
// expand the dialog to make room for the verification result
if (verificationResultsContainer.is(':visible') === false) {
// show the verification results
$('#controller-service-properties').css('bottom', '40%').propertytable('resetTableSize')
verificationResultsContainer.show();
}
// show borders if appropriate
var verificationResultsListing = $('#controller-service-properties-verification-results-listing');
if (verificationResultsListing.get(0).scrollHeight > Math.round(verificationResultsListing.innerHeight())) {
verificationResultsListing.css('border-width', '1px');
}
};
/**
* Track the current table
*/
@ -1768,6 +1797,14 @@
// removed the cached controller service details
$('#controller-service-configuration').removeData('controllerServiceDetails');
// clean up an shown verification errors
$('#controller-service-properties-verification-results').hide();
$('#controller-service-properties-verification-results-listing').css('border-width', '0').empty();
$('#controller-service-properties').css('bottom', '0');
// clear most recently submitted referenced attributes
referencedAttributes = null;
},
open: function () {
nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0));
@ -2061,7 +2098,10 @@
// load the property table
$('#controller-service-properties')
.propertytable('setGroupId', controllerService.parentGroupId)
.propertytable('loadProperties', controllerService.properties, controllerService.descriptors, controllerServiceHistory.propertyHistory);
.propertytable('loadProperties', controllerService.properties, controllerService.descriptors, controllerServiceHistory.propertyHistory)
.propertytable('setPropertyVerificationCallback', function (proposedProperties) {
nfVerify.verify(controllerService['id'], controllerServiceEntity['uri'], proposedProperties, referencedAttributes, handleVerificationResults, $('#controller-service-properties-verification-results-listing'));
});
// show the details
controllerServiceDialog.modal('show');

View File

@ -30,10 +30,11 @@
'nf.Processor',
'nf.ClusterSummary',
'nf.CustomUi',
'nf.Verify',
'nf.UniversalCapture',
'nf.Connection'],
function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfUniversalCapture, nfConnection) {
return (nf.ProcessorConfiguration = factory($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfUniversalCapture, nfConnection));
function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfVerify, nfUniversalCapture, nfConnection) {
return (nf.ProcessorConfiguration = factory($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfVerify, nfUniversalCapture, nfConnection));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.ProcessorConfiguration =
@ -48,6 +49,7 @@
require('nf.Processor'),
require('nf.ClusterSummary'),
require('nf.CustomUi'),
require('nf.Verify'),
require('nf.UniversalCapture'),
require('nf.Connection')));
} else {
@ -62,10 +64,11 @@
root.nf.Processor,
root.nf.ClusterSummary,
root.nf.CustomUi,
root.nf.Verify,
root.nf.UniversalCapture,
root.nf.Connection);
}
}(this, function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfUniversalCapture, nfConnection) {
}(this, function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfCanvasUtils, nfNgBridge, nfProcessor, nfClusterSummary, nfCustomUi, nfVerify, nfUniversalCapture, nfConnection) {
'use strict';
/**
@ -81,6 +84,9 @@
RUN_STATUS_KEY = 'status.aggregateSnapshot.runStatus',
BULLETINS_KEY = 'bulletins';
// the last submitted referenced attributes
var referencedAttributes = null;
/**
* Gets the available scheduling strategies based on the specified processor.
*
@ -499,6 +505,29 @@
}
};
/**
* Handles verification results.
*/
var handleVerificationResults = function (verificationResults, referencedAttributeMap) {
// record the most recently submitted referenced attributes
referencedAttributes = referencedAttributeMap;
var verificationResultsContainer = $('#processor-properties-verification-results');
// expand the dialog to make room for the verification result
if (verificationResultsContainer.is(':visible') === false) {
// show the verification results
$('#processor-properties').css('bottom', '40%').propertytable('resetTableSize')
verificationResultsContainer.show();
}
// show borders if appropriate
var verificationResultsListing = $('#processor-properties-verification-results-listing');
if (verificationResultsListing.get(0).scrollHeight > Math.round(verificationResultsListing.innerHeight())) {
verificationResultsListing.css('border-width', '1px');
}
};
return {
/**
* Initializes the processor properties tab.
@ -562,8 +591,16 @@
// removed the cached processor details
$('#processor-configuration').removeData('processorDetails');
// clean up an shown verification errors
$('#processor-properties-verification-results').hide();
$('#processor-properties-verification-results-listing').css('border-width', '0').empty();
$('#processor-properties').css('bottom', '0');
// clear most recently submitted referenced attributes
referencedAttributes = null;
//stop any synchronization
if(config.supportsStatusBar){
if (config.supportsStatusBar){
$('#processor-configuration-status-bar').statusbar('disconnect');
}
},
@ -982,7 +1019,10 @@
// load the property table
$('#processor-properties')
.propertytable('setGroupId', processor.parentGroupId)
.propertytable('loadProperties', processor.config.properties, processor.config.descriptors, processorHistory.propertyHistory);
.propertytable('loadProperties', processor.config.properties, processor.config.descriptors, processorHistory.propertyHistory)
.propertytable('setPropertyVerificationCallback', function (proposedProperties) {
nfVerify.verify(processor['id'], processorResponse['uri'], proposedProperties, referencedAttributes, handleVerificationResults, $('#processor-properties-verification-results-listing'));
});
// show the details
$('#processor-configuration').modal('show');
@ -997,13 +1037,12 @@
}
// 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) {
if ($('#processor-configuration-tabs').find('.selected-tab').text() === 'Properties') {
$('#processor-properties').propertytable('resetTableSize');
}
//execute the callback if one was provided
if(typeof cb == 'function'){
// execute the callback if one was provided
if (typeof cb == 'function'){
cb();
}
}).fail(nfErrorHandler.handleAjaxError);

View File

@ -28,9 +28,10 @@
'nf.ControllerService',
'nf.ControllerServices',
'nf.UniversalCapture',
'nf.CustomUi'],
function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi) {
return (nf.ReportingTask = factory($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi));
'nf.CustomUi',
'nf.Verify'],
function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify) {
return (nf.ReportingTask = factory($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.ReportingTask =
@ -43,7 +44,8 @@
require('nf.ControllerService'),
require('nf.ControllerServices'),
require('nf.UniversalCapture'),
require('nf.CustomUi')));
require('nf.CustomUi'),
require('nf.Verify')));
} else {
nf.ReportingTask = factory(root.$,
root.nf.ErrorHandler,
@ -54,9 +56,10 @@
root.nf.ControllerService,
root.nf.ControllerServices,
root.nf.UniversalCapture,
root.nf.CustomUi);
root.nf.CustomUi,
root.nf.Verify);
}
}(this, function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi) {
}(this, function ($, nfErrorHandler, nfCommon, nfDialog, nfStorage, nfClient, nfControllerService, nfControllerServices, nfUniversalCapture, nfCustomUi, nfVerify) {
'use strict';
var nfSettings;
@ -69,6 +72,9 @@
}
};
// the last submitted referenced attributes
var referencedAttributes = null;
// load the controller services
var controllerServicesUri = config.urls.api + '/flow/controller/controller-services';
@ -320,6 +326,30 @@
}).fail(nfErrorHandler.handleAjaxError);
};
/**
* Handles verification results.
*/
var handleVerificationResults = function (verificationResults, referencedAttributeMap) {
// record the most recently submitted referenced attributes
referencedAttributes = referencedAttributeMap;
var verificationResultsContainer = $('#reporting-task-properties-verification-results');
// expand the dialog to make room for the verification result
if (verificationResultsContainer.is(':visible') === false) {
// show the verification results
$('#reporting-task-properties').css('bottom', '40%').propertytable('resetTableSize')
verificationResultsContainer.show();
}
// show borders if appropriate
var verificationResultsListing = $('#reporting-task-properties-verification-results-listing');
if (verificationResultsListing.get(0).scrollHeight > Math.round(verificationResultsListing.innerHeight())) {
verificationResultsListing.css('border-width', '1px');
}
};
var nfReportingTask = {
/**
* Initializes the reporting task configuration dialog.
@ -375,6 +405,14 @@
// removed the cached reporting task details
$('#reporting-task-configuration').removeData('reportingTaskDetails');
// clean up an shown verification errors
$('#reporting-task-properties-verification-results').hide();
$('#reporting-task-properties-verification-results-listing').css('border-width', '0').empty();
$('#reporting-task-properties').css('bottom', '0');
// clear most recently submitted referenced attributes
referencedAttributes = null;
},
open: function () {
nfCommon.toggleScrollable($('#' + this.find('.tab-container').attr('id') + '-content').get(0));
@ -605,7 +643,10 @@
// load the property table
$('#reporting-task-properties')
.propertytable('setGroupId', null)
.propertytable('loadProperties', reportingTask.properties, reportingTask.descriptors, reportingTaskHistory.propertyHistory);
.propertytable('loadProperties', reportingTask.properties, reportingTask.descriptors, reportingTaskHistory.propertyHistory)
.propertytable('setPropertyVerificationCallback', function (proposedProperties) {
nfVerify.verify(reportingTask['id'], reportingTaskEntity['uri'], proposedProperties, referencedAttributes, handleVerificationResults, $('#reporting-task-properties-verification-results-listing'));
});
// show the details
$('#reporting-task-configuration').modal('show');

View File

@ -0,0 +1,847 @@
/*
* 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.
*/
/* global define, module, require, exports */
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery',
'nf.Common',
'nf.Dialog',
'nf.ng.Bridge',
'nf.ErrorHandler'],
function ($, nfCommon, nfDialog, nfNgBridge, nfErrorHandler) {
return (nf.Verify = factory($, nfCommon, nfDialog, nfNgBridge, nfErrorHandler));
});
} else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.Verify =
factory(require('jquery'),
require('nf.Common'),
require('nf.Dialog'),
require('nf.ng.Bridge'),
require('nf.ErrorHandler')));
} else {
nf.Verify = factory(root.$,
root.nf.Common,
root.nf.Dialog,
root.nf.ng.Bridge,
root.nf.ErrorHandler);
}
}(this, function ($, nfCommon, nfDialog, nfNgBridge, nfErrorHandler) {
'use strict';
var gridOptions = {
autosizeColsMode: Slick.GridAutosizeColsMode.LegacyForceFit,
enableTextSelectionOnCells: true,
enableCellNavigation: true,
enableColumnReorder: false,
editable: true,
enableAddRow: false,
autoEdit: false,
multiSelect: false,
rowHeight: 24
};
// text editor
var textEditor = function (args) {
var scope = this;
var initialValue = '';
var previousValue;
var wrapper;
var isEmpty;
var input;
this.init = function () {
var container = $('body');
// record the previous value
previousValue = args.item[args.column.field];
// create the wrapper
wrapper = $('<div></div>').addClass('slickgrid-editor').css({
'z-index': 100000,
'position': 'absolute',
'border-radius': '2px',
'box-shadow': 'rgba(0, 0, 0, 0.247059) 0px 2px 5px',
'background-color': 'rgb(255, 255, 255)',
'overflow': 'hidden',
'padding': '10px 20px',
'cursor': 'move',
'transform': 'translate3d(0px, 0px, 0px)'
}).appendTo(container);
// create the input field
input = $('<textarea hidefocus rows="5"/>').css({
'height': '80px',
'width': args.position.width + 'px',
'min-width': '212px',
'margin-bottom': '5px',
'margin-top': '10px',
'white-space': 'pre'
}).tab().on('keydown', scope.handleKeyDown).appendTo(wrapper);
wrapper.draggable({
cancel: '.button, textarea, .nf-checkbox',
containment: 'parent'
});
// create the button panel
var stringCheckPanel = $('<div class="string-check-container" />');
stringCheckPanel.appendTo(wrapper);
// build the custom checkbox
isEmpty = $('<div class="nf-checkbox string-check" />')
.on('change', function (event, args) {
// if we are setting as an empty string, disable the editor
if (args.isChecked) {
input.prop('disabled', true).val('');
} else {
input.prop('disabled', false).val(previousValue);
}
}).appendTo(stringCheckPanel);
$('<span class="string-check-label nf-checkbox-label">&nbsp;Set empty string</span>').appendTo(stringCheckPanel);
var ok = $('<div class="button">Ok</div>').css({
'color': '#fff',
'background': '#728E9B'
}).hover(
function () {
$(this).css('background', '#004849');
}, function () {
$(this).css('background', '#728E9B');
}).on('click', scope.save);
var cancel = $('<div class="secondary-button">Cancel</div>').css({
'color': '#004849',
'background': '#E3E8EB'
}).hover(
function () {
$(this).css('background', '#C7D2D7');
}, function () {
$(this).css('background', '#E3E8EB');
}).on('click', scope.cancel);
$('<div></div>').css({
'position': 'relative',
'top': '10px',
'left': '20px',
'width': '212px',
'clear': 'both',
'float': 'right'
}).append(ok).append(cancel).append('<div class="clear"></div>').appendTo(wrapper);
// position and focus
scope.position(args.position);
input.focus().select();
};
this.handleKeyDown = function (e) {
if (e.which === $.ui.keyCode.ENTER && !e.shiftKey) {
scope.save();
} else if (e.which === $.ui.keyCode.ESCAPE) {
scope.cancel();
// prevent further propagation or escape press and prevent default behavior
e.stopImmediatePropagation();
e.preventDefault();
}
};
this.save = function () {
args.commitChanges();
};
this.cancel = function () {
input.val(initialValue);
args.cancelChanges();
};
this.hide = function () {
wrapper.hide();
};
this.show = function () {
wrapper.show();
};
this.position = function (position) {
wrapper.css({
'top': position.top - 27,
'left': position.left - 20
});
};
this.destroy = function () {
wrapper.remove();
};
this.focus = function () {
input.focus();
};
this.loadValue = function (item) {
var isEmptyChecked = false;
// determine the value to use when populating the text field
if (nfCommon.isDefinedAndNotNull(item[args.column.field])) {
initialValue = item[args.column.field];
isEmptyChecked = initialValue === '';
}
// determine if its an empty string
var checkboxStyle = isEmptyChecked ? 'checkbox-checked' : 'checkbox-unchecked';
isEmpty.addClass(checkboxStyle);
input.val(initialValue);
input.select();
};
this.serializeValue = function () {
// if the field has been cleared, set the value accordingly
if (input.val() === '') {
// if the user has checked the empty string checkbox, use emtpy string
if (isEmpty.hasClass('checkbox-checked')) {
return '';
} else {
return null;
}
} else {
// if there is text specified, use that value
return input.val();
}
};
this.applyValue = function (item, state) {
item[args.column.field] = state;
};
this.isValueChanged = function () {
return scope.serializeValue() !== previousValue;
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
// initialize the custom long text editor
this.init();
};
/**
* Reset the dialog.
*/
var resetDialog = function () {
var referencedAttributesGrid = $('#referenced-attributes-table').data('gridInstance');
var referencedAttributesData = referencedAttributesGrid.getData();
referencedAttributesGrid.setSelectedRows([]);
referencedAttributesData.setItems([]);
};
/**
* Initialized the referenced attributes dialog.
*/
var initializeReferencedAttributesDialog = function () {
$('#referenced-attributes-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Referenced Attributes',
handler: {
close: function () {
resetDialog();
},
open: function () {
var referencedAttributesGrid = $('#referenced-attributes-table').data('gridInstance');
if (nfCommon.isDefinedAndNotNull(referencedAttributesGrid)) {
referencedAttributesGrid.resizeCanvas();
}
}
}
});
};
var verify = function (componentId, componentUri, proposedProperties, referencedAttributeMap, handleVerificationResults, verificationResultsContainer) {
// submit verification
performVerification(componentId, componentUri, proposedProperties, referencedAttributeMap).done(function (verificationResults) {
// empty the previous listing
verificationResultsContainer.empty();
// render the verification results
$.each(verificationResults, function (i, result) {
var verificationResultContainer = $('<div class="verification-result"></div>').appendTo(verificationResultsContainer);
// determine the icon for this result
var outcomeClass;
switch (result.outcome) {
case 'SUCCESSFUL':
outcomeClass = 'fa-check';
break;
case 'FAILED':
outcomeClass = 'fa-times';
break;
case 'SKIPPED':
outcomeClass = 'fa-exclamation';
break;
}
// build the header
var verificationHeader = $('<div class="verification-result-header"></div>').appendTo(verificationResultContainer);
$('<div class="verification-result-outcome fa ' + outcomeClass + '"></div>').appendTo(verificationHeader);
$('<div class="verification-result-step-name"></div>').text(result.verificationStepName).appendTo(verificationHeader);
$('<div class="clear"></div>').appendTo(verificationHeader);
// build the explanation
$('<div class="verification-result-explanation"></div>').text(result.explanation).appendTo(verificationResultContainer);
});
// invoke the verification callback if specified
if (typeof handleVerificationResults === 'function') {
handleVerificationResults(verificationResults, referencedAttributeMap);
}
});
}
/**
* Updates the button model for the verification of this component and proposed properties.
*
* @param componentId the component id
* @param componentUri the component uri
* @param proposedProperties the proposed properties
* @param handleVerificationResults verification results callback
* @param verificationResultsContainer container where verification results should be rendered
*/
var updateReferencedAttributesButtonModel = function (componentId, componentUri, proposedProperties, handleVerificationResults, verificationResultsContainer) {
$('#referenced-attributes-dialog').modal('setButtonModel', [{
buttonText: 'Verify',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
// get the referenced attributes name/values
var referencedAttributesGrid = $('#referenced-attributes-table').data('gridInstance');
var referencedAttributesData = referencedAttributesGrid.getData();
var referencedAttributes = referencedAttributesData.getItems();
// map the referenced attributes
var referencedAttributeMap = referencedAttributes.reduce(function(map, referencedAttribute) {
map[referencedAttribute.name] = referencedAttribute.value;
return map;
}, {});
// hide the referenced attributes dialog prior to performing the verification
$('#referenced-attributes-dialog').modal('hide');
// verify
verify(componentId, componentUri, proposedProperties, referencedAttributeMap, handleVerificationResults, verificationResultsContainer);
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$('#referenced-attributes-dialog').modal('hide');
}
}
}]);
};
/**
* Initializes the verification request status dialog.
*/
var initializeVerificationRequestStatusDialog = function () {
// configure the verification request status dialog
$('#verification-request-status-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Verifying Properties',
handler: {
close: function () {
// clear the current button model
$('#verification-request-status-dialog').modal('setButtonModel', []);
}
}
});
};
/**
* Initialized the new referenced attribute dialog.
*/
var initializeNewAttributeDialog = function () {
$('#new-referenced-attribute-dialog').modal({
headerText: 'New Attribute',
buttons: [{
buttonText: 'Ok',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
addNewReferencedAttribute();
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$('#new-referenced-attribute-dialog').modal('hide');
}
}
}],
handler: {
close: function () {
$('#new-referenced-attribute-name').val('');
},
open: function () {
$('#new-referenced-attribute-name').focus();
}
}
});
$('#new-referenced-attribute-name').on('keydown', function (e) {
var code = e.keyCode ? e.keyCode : e.which;
if (code === $.ui.keyCode.ENTER) {
addNewReferencedAttribute();
// prevents the enter from propagating into the field for editing the new property value
e.stopImmediatePropagation();
e.preventDefault();
}
});
$('#add-referenced-attribute').on('click', function () {
$('#new-referenced-attribute-dialog').modal('show');
});
}
/**
* Adds a new referenced attribute.
*/
var addNewReferencedAttribute = function () {
var attributeName = $.trim($('#new-referenced-attribute-name').val());
// ensure the property name is specified
if (attributeName !== '') {
var referencedAttributeGrid = $('#referenced-attributes-table').data('gridInstance');
var referencedAttributeData = referencedAttributeGrid.getData();
// ensure the property name is unique
var matchingAttribute = null;
$.each(referencedAttributeData.getItems(), function (_, item) {
if (attributeName === item.name) {
matchingAttribute = item;
}
});
if (matchingAttribute === null) {
referencedAttributeData.beginUpdate();
// add a row for the new attribute
referencedAttributeData.addItem({
id: attributeName,
name: attributeName,
value: null,
});
referencedAttributeData.endUpdate();
// sort the data
referencedAttributeData.reSort();
// select the new variable row
var row = referencedAttributeData.getRowById(attributeName);
referencedAttributeGrid.setActiveCell(row, referencedAttributeGrid.getColumnIndex('value'));
referencedAttributeGrid.editActiveCell();
} else {
// if this row is currently hidden, clear the value and show it
nfDialog.showOkDialog({
headerText: 'Attribute Exists',
dialogContent: 'An attribute with this name already exists.'
});
// select the existing properties row
var matchingRow = referencedAttributeData.getRowById(matchingAttribute.id);
referencedAttributeGrid.setSelectedRows([matchingRow]);
referencedAttributeGrid.scrollRowIntoView(matchingRow);
}
// close the new variable dialog
$('#new-referenced-attribute-dialog').modal('hide');
} else {
nfDialog.showOkDialog({
headerText: 'Attribute Error',
dialogContent: 'The name of the attribute must be specified.'
});
}
};
/**
* Sorts the specified data using the specified sort details.
*
* @param {object} sortDetails
* @param {object} data
*/
var sortReferencedAttributes = function (sortDetails, data) {
// defines a function for sorting
var comparer = function (a, b) {
var aString = nfCommon.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : '';
var bString = nfCommon.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : '';
return aString === bString ? 0 : aString > bString ? 1 : -1;
};
// perform the sort
data.sort(comparer, sortDetails.sortAsc);
};
/**
* Initializes the referenced attributes table
*/
var initializeReferencedAttributesTable = function () {
var referencedAttributesGridElement = $('#referenced-attributes-table');
var nameFormatter = function (row, cell, value, columnDef, dataContext) {
return nfCommon.escapeHtml(value);
};
var valueFormatter = function (row, cell, value, columnDef, dataContext) {
if (value === '') {
return '<span class="table-cell blank">Empty string set</span>';
} else if (value === null) {
return '<span class="unset">No value set</span>';
} else {
return nfCommon.escapeHtml(value);
}
};
// define the column model for the referenced attributes table
var referencedAttributesColumns = [
{
id: 'name',
name: 'Name',
field: 'name',
formatter: nameFormatter,
sortable: true,
resizable: true
},
{
id: 'value',
name: 'Value',
field: 'value',
formatter: valueFormatter,
sortable: true,
resizable: true,
cssClass: 'pointer'
}
];
// initialize the dataview
var referencedAttributesData = new Slick.Data.DataView({
inlineFilters: false
});
referencedAttributesData.getItemMetadata = function (index) {
return {
columns: {
value: {
editor: textEditor
}
}
};
};
// initialize the sort
sortReferencedAttributes({
columnId: 'name',
sortAsc: true
}, referencedAttributesData);
// initialize the grid
var referencedAttributesGrid = new Slick.Grid(referencedAttributesGridElement, referencedAttributesData, referencedAttributesColumns, gridOptions);
referencedAttributesGrid.setSelectionModel(new Slick.RowSelectionModel());
referencedAttributesGrid.registerPlugin(new Slick.AutoTooltips());
referencedAttributesGrid.setSortColumn('name', true);
referencedAttributesGrid.onSort.subscribe(function (e, args) {
sortReferencedAttributes({
columnId: args.sortCol.id,
sortAsc: args.sortAsc
}, referencedAttributesData);
});
referencedAttributesGrid.onClick.subscribe(function (e, args) {
if (referencedAttributesGrid.getColumns()[args.cell].id === 'value') {
referencedAttributesGrid.gotoCell(args.row, args.cell, true);
// prevents standard edit logic
e.stopImmediatePropagation();
}
});
referencedAttributesGrid.onBeforeCellEditorDestroy.subscribe(function (e, args) {
setTimeout(function() {
referencedAttributesGrid.resizeCanvas();
}, 50);
});
// wire up the dataview to the grid
referencedAttributesData.onRowCountChanged.subscribe(function (e, args) {
referencedAttributesGrid.updateRowCount();
referencedAttributesGrid.render();
});
referencedAttributesData.onRowsChanged.subscribe(function (e, args) {
referencedAttributesGrid.invalidateRows(args.rows);
referencedAttributesGrid.render();
});
referencedAttributesData.syncGridSelection(referencedAttributesGrid, true);
// hold onto an instance of the grid
referencedAttributesGridElement.data('gridInstance', referencedAttributesGrid);
};
/**
* Performs verification for the specific configuration and referenced attributes.
*
* @param id the component id
* @param componentUrl the component url
* @param proposedProperties the proposed properties
* @param attributes the attributes names/values
*/
var performVerification = function (id, componentUrl, proposedProperties, attributes) {
var MAX_DELAY = 4;
var cancelled = false;
var verificationRequest = null;
var verificationRequestTimer = null;
return $.Deferred(function (deferred) {
// updates the progress bar
var updateProgress = function (percentComplete) {
// remove existing labels
var progressBar = $('#verification-request-percent-complete');
progressBar.find('div.progress-label').remove();
progressBar.find('md-progress-linear').remove();
// update the progress
var label = $('<div class="progress-label"></div>').text(percentComplete + '%');
(nfNgBridge.injector.get('$compile')($('<md-progress-linear ng-cloak ng-value="' + percentComplete + '" class="md-hue-2" md-mode="determinate" aria-label="Searching Queue"></md-progress-linear>'))(nfNgBridge.rootScope)).appendTo(progressBar);
progressBar.append(label);
};
// update the button model of the drop request status dialog
$('#verification-request-status-dialog').modal('setButtonModel', [{
headerText: 'Verifying Properties',
buttonText: 'Stop',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
cancelled = true;
// we are waiting for the next poll attempt
if (verificationRequestTimer !== null) {
// cancel it
clearTimeout(verificationRequestTimer);
// cancel the verification request
completeVerificationRequest();
}
}
}
}]);
// completes the verification request by removing it
var completeVerificationRequest = function () {
$('#verification-request-status-dialog').modal('hide');
var reject = cancelled;
// ensure the verification requests are present
if (nfCommon.isDefinedAndNotNull(verificationRequest)) {
$.ajax({
type: 'DELETE',
url: verificationRequest.uri,
dataType: 'json'
});
// use the verification request from when the verification completed
if (nfCommon.isEmpty(verificationRequest.results)) {
if (cancelled === false) {
reject = true;
// show the dialog
nfDialog.showOkDialog({
headerText: 'Verifying Properties',
dialogContent: 'There are no results.'
});
}
}
} else {
reject = true;
}
if (reject) {
deferred.reject();
} else {
deferred.resolve(verificationRequest.results);
}
};
// process the verification request
var processVerificationRequest = function (delay) {
// update the percent complete
updateProgress(verificationRequest.percentCompleted);
// update the status of the verification request
$('#verification-request-status-message').text(verificationRequest.state);
// close the dialog if the
if (verificationRequest.complete === true || cancelled === true) {
completeVerificationRequest();
} else {
// wait delay to poll again
verificationRequestTimer = setTimeout(function () {
// clear the verification request timer
verificationRequestTimer = null;
// schedule to poll the status again in nextDelay
pollVerificationRequest(Math.min(MAX_DELAY, delay * 2));
}, delay * 1000);
}
};
// schedule for the next poll iteration
var pollVerificationRequest = function (nextDelay) {
$.ajax({
type: 'GET',
url: verificationRequest.uri,
dataType: 'json'
}).done(function (response) {
verificationRequest = response.request;
processVerificationRequest(nextDelay);
}).fail(completeVerificationRequest).fail(nfErrorHandler.handleAjaxError);
};
// initialize the progress bar value
updateProgress(0);
// show the progress dialog
$('#verification-request-status-dialog').modal('show');
// issue the request to verify the properties
$.ajax({
type: 'POST',
url: componentUrl + '/config/verification-requests',
data: JSON.stringify({
request: {
componentId: id,
properties: proposedProperties,
attributes: attributes
}
}),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
// process the verification request
verificationRequest = response.request;
processVerificationRequest(1);
}).fail(completeVerificationRequest).fail(nfErrorHandler.handleAjaxError);
}).promise();
};
return {
/**
* Initialize the verification component.
*/
init: function () {
initializeVerificationRequestStatusDialog();
initializeReferencedAttributesDialog();
initializeReferencedAttributesTable();
initializeNewAttributeDialog();
},
/**
* Peforms verification for a given component.
*
* @param id the component id
* @param componentUrl the component url
* @param proposedProperties the proposed attributes
* @param referencedAttributes the most recently submitted referenced attributes, null if not submitted previously
* @param handleVerificationResults callback for handling verification results
* @param verificationResultsContainer container where verification results should be rendered
*/
verify: function (id, componentUrl, proposedProperties, referencedAttributes, handleVerificationResults, verificationResultsContainer) {
// get the referenced attributes
$.ajax({
type: 'POST',
url: componentUrl + '/config/analysis',
data: JSON.stringify({
configurationAnalysis: {
componentId: id,
properties: proposedProperties
}
}),
dataType: 'json',
contentType: 'application/json'
}).done(function(response) {
var configurationAnalysis = response.configurationAnalysis;
// if the component does not support additional verification there is no need to prompt for attribute values
if (configurationAnalysis.supportsVerification === false) {
verify(id, componentUrl, proposedProperties, {}, handleVerificationResults, verificationResultsContainer);
} else {
// combine the previously entered referenced attributes with the updated attributes from the configuration analysis
var combinedReferencedAttributes = $.extend({}, configurationAnalysis.referencedAttributes, referencedAttributes);
var referencedAttributesGrid = $('#referenced-attributes-table').data('gridInstance');
var referencedAttributesData = referencedAttributesGrid.getData();
// begin the update
referencedAttributesData.beginUpdate();
$.each(combinedReferencedAttributes, function (name, value) {
referencedAttributesData.addItem({
id: name,
name: name,
value: value
});
});
// complete the update
referencedAttributesData.endUpdate();
referencedAttributesData.reSort();
// update the button model for this verification
updateReferencedAttributesButtonModel(id, componentUrl, proposedProperties, handleVerificationResults, verificationResultsContainer);
// show the dialog
$('#referenced-attributes-dialog').modal('show');
}
}).fail(nfErrorHandler.handleAjaxError);
}
};
}));