sardell commented on code in PR #8273:
URL: https://github.com/apache/nifi/pull/8273#discussion_r1516856485
##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-canvas-flow-status-controller.js:
##########
@@ -400,6 +406,556 @@
}
}
+ /**
+ * The flow analysis controller.
+ */
+
+ this.flowAnalysis = {
+
+ /**
+ * Create the list of rule violations
+ */
+ buildRuleViolationsList: function(rules, violationsAndRecs) {
+ var ruleViolationCountEl = $('#rule-violation-count');
+ var ruleViolationListEl = $('#rule-violations-list');
+ var ruleWarningCountEl = $('#rule-warning-count');
+ var ruleWarningListEl = $('#rule-warnings-list');
+ var violations = violationsAndRecs.filter(function
(violation) {
+ return violation.enforcementPolicy === 'ENFORCE'
+ });
+ var warnings = violationsAndRecs.filter(function
(violation) {
+ return violation.enforcementPolicy === 'WARN'
+ });
+ ruleViolationCountEl.empty().text('(' + violations.length
+ ')');
+ ruleWarningCountEl.empty().text('(' + warnings.length +
')');
+ ruleViolationListEl.empty();
+ violations.forEach(function(violation) {
+ var rule = rules.find(function(rule) {
+ return rule.id === violation.ruleId;
+ });
+ // create DOM elements
+ var violationListItemEl = $('<li></li>');
+ var violationEl = $('<div
class="violation-list-item"></div>');
+ var violationListItemWrapperEl = $('<div
class="violation-list-item-wrapper"></div>');
+ var violationRuleEl = $('<div
class="rule-violations-list-item-name"></div>');
+ var violationListItemNameEl = $('<div
class="violation-list-item-name"></div>');
+ var violationListItemIdEl = $('<span
class="violation-list-item-id"></span>');
+ var violationInfoButtonEl = $('<button
class="violation-menu-btn"><i class="fa fa-ellipsis-v
rules-list-item-menu-target" aria-hidden="true"></i></button>');
+
+ // add text content and button data
+ $(violationRuleEl).text(rule.name);
+
$(violationListItemNameEl).text(violation.subjectDisplayName);
+ $(violationListItemIdEl).text(violation.subjectId);
+
$(violationListItemEl).append(violationRuleEl).append(violationListItemWrapperEl);
+ $(violationInfoButtonEl).data('violationInfo',
violation);
+
+ // build list DOM structure
+
violationListItemWrapperEl.append(violationListItemNameEl).append(violationListItemIdEl);
+
violationEl.append(violationListItemWrapperEl).append(violationInfoButtonEl);
+
violationListItemEl.append(violationRuleEl).append(violationEl)
+ ruleViolationListEl.append(violationListItemEl);
+ });
+
+ warnings.forEach(function(warning) {
+ var rule = rules.find(function(rule) {
+ return rule.id === warning.ruleId;
+ });
+ // create DOM elements
+ var warningListItemEl = $('<li></li>');
+ var warningEl = $('<div
class="warning-list-item"></div>');
+ var warningListItemWrapperEl = $('<div
class="warning-list-item-wrapper"></div>');
+ var warningRuleEl = $('<div
class="rule-warnings-list-item-name"></div>');
+ var warningListItemNameEl = $('<div
class="warning-list-item-name"></div>');
+ var warningListItemIdEl = $('<span
class="warning-list-item-id"></span>');
+ var warningInfoButtonEl = $('<button
class="violation-menu-btn"><i class="fa fa-ellipsis-v
rules-list-item-menu-target" aria-hidden="true"></i></button>');
+
+ // add text content and button data
+ $(warningRuleEl).text(rule.name);
+
$(warningListItemNameEl).text(warning.subjectDisplayName);
+ $(warningListItemIdEl).text(warning.subjectId);
+
$(warningListItemEl).append(warningRuleEl).append(warningListItemWrapperEl);
+ $(warningInfoButtonEl).data('violationInfo', warning);
+
+ // build list DOM structure
+
warningListItemWrapperEl.append(warningListItemNameEl).append(warningListItemIdEl);
+
warningEl.append(warningListItemWrapperEl).append(warningInfoButtonEl);
+
warningListItemEl.append(warningRuleEl).append(warningEl)
+ ruleWarningListEl.append(warningListItemEl);
+ });
+ },
+
+ /**
+ *
+ * Render a new list when it differs from the previous
violations response
+ */
+ buildRuleViolations: function(rules, violations) {
+ if (Object.keys(previousRulesResponse).length !== 0) {
+ var previousRulesResponseSorted =
_.sortBy(previousRulesResponse.ruleViolations, 'subjectId');
+ var violationsSorted = _.sortBy(violations,
'subjectId');
+ if (!_.isEqual(previousRulesResponseSorted,
violationsSorted)) {
+ this.buildRuleViolationsList(rules, violations);
+ }
+ } else {
+ this.buildRuleViolationsList(rules, violations);
+ }
+ },
+
+ /**
+ * Create the list of flow policy rules
+ */
+ buildRuleList: function(ruleType, violationsMap, rec) {
+ var requiredRulesListEl = $('#required-rules-list');
+ var recommendedRulesListEl = $('#recommended-rules-list');
+ var rule = $('<li
class="rules-list-item"></li>').append($(rec.requirement).append(rec.requirementInfoButton))
+ var violationsListEl = '';
+ var violationCountEl = '';
+
+ var violations = violationsMap.get(rec.id);
+ if (!!violations) {
+ if (violations.length === 1) {
+ violationCountEl = '<div class="rule-' + ruleType
+ 's-count">' + violations.length + ' ' + ruleType + '</div>';
+ } else {
+ violationCountEl = '<div class="rule-' + ruleType
+ 's-count">' + violations.length + ' ' + ruleType + 's</div>';
+ }
+ violationsListEl = $('<ul class="rule-' + ruleType +
's-list"></ul>');
+ violations.forEach(function(violation) {
+ // create DOM elements
+ var violationListItemEl = $('<li class="' +
ruleType + '-list-item"></li>');
+ var violationWrapperEl = $('<div class="' +
ruleType + '-list-item-wrapper"></div>');
+ var violationNameEl = $('<div class="' + ruleType
+ '-list-item-name"></div>');
+ var violationIdEl = $('<span class="' + ruleType +
'-list-item-id"></span>');
+ var violationInfoButtonEl = $('<button
class="violation-menu-btn"><i class="fa fa-ellipsis-v
rules-list-item-menu-target" aria-hidden="true"></i></button>');
+
+ // add text content and button data
+ violationNameEl.text(violation.subjectDisplayName);
+ violationIdEl.text(violation.subjectId);
+
+ // build list DOM structure
+ violationListItemEl.append(violationWrapperEl);
+
violationWrapperEl.append(violationNameEl).append(violationIdEl)
+ violationInfoButtonEl.data('violationInfo',
violation);
+
(violationsListEl).append(violationListItemEl.append(violationInfoButtonEl));
+ });
+ rule.append(violationCountEl).append(violationsListEl);
+ }
+ ruleType === 'violation' ?
requiredRulesListEl.append(rule) : recommendedRulesListEl.append(rule);
+ },
+
+ /**
+ * Loads the current status of the flow.
+ */
+ loadFlowPolicies: function () {
+ var flowAnalysisCtrl = this;
+ var requiredRulesListEl = $('#required-rules-list');
+ var recommendedRulesListEl = $('#recommended-rules-list');
+ var requiredRuleCountEl = $('#required-rule-count');
+ var recommendedRuleCountEl = $('#recommended-rule-count');
+
+ var groupId = nfCanvasUtils.getGroupId();
+ if (groupId !== 'root') {
+ $.ajax({
+ type: 'GET',
+ url: '../nifi-api/flow/flow-analysis/results/' +
groupId,
+ dataType: 'json',
+ context: this
+ }).done(function (response) {
+ var recommendations = [];
+ var requirements = [];
+ var requirementsTotal = 0;
+ var recommendationsTotal = 0;
+
+ if (!_.isEqual(previousRulesResponse, response)) {
+ // clear previous accordion content
+ requiredRulesListEl.empty();
+ recommendedRulesListEl.empty();
+
flowAnalysisCtrl.buildRuleViolations(response.rules, response.ruleViolations);
+
+ // For each ruleViolations:
+ // * group violations by ruleId
+ // * build DOM elements
+ // * get the ruleId and find the matching rule
id
+ // * append violation list to matching rule
list item
+ var violationsMap = new Map();
+
response.ruleViolations.forEach(function(violation) {
+ if (violationsMap.has(violation.ruleId)){
+
violationsMap.get(violation.ruleId).push(violation);
+ } else {
+ violationsMap.set(violation.ruleId,
[violation]);
+ }
+ });
+
+ // build list of recommendations
+ response.rules.forEach(function(rule) {
+ if (rule.enforcementPolicy === 'WARN') {
+ var requirement = '<div
class="rules-list-rule-info"></div>';
+ var requirementName =
$('<div></div>').text(rule.name);
+ var requirementInfoButton = '<button
class="rule-menu-btn"><i class="fa fa-ellipsis-v rules-list-item-menu-target"
aria-hidden="true"></i></button>';
+ recommendations.push(
+ {
+ 'requirement':
$(requirement).append(requirementName),
+ 'requirementInfoButton':
$(requirementInfoButton).data('ruleInfo', rule),
+ 'id': rule.id
+ }
+ )
+ recommendationsTotal++;
+ }
+ });
+
+ // add class to notification icon for
recommended rules
+ var hasRecommendations =
response.ruleViolations.findIndex(function(violation) {
+ return violation.enforcementPolicy ===
'WARN';
+ });
+ if (hasRecommendations !== -1) {
+ $('#flow-analysis
.flow-analysis-notification-icon ').addClass('recommendations');
+ } else {
+ $('#flow-analysis
.flow-analysis-notification-icon ').removeClass('recommendations');
+ }
+
+ // build list of requirements
+ recommendedRuleCountEl.empty().append('(' +
recommendationsTotal + ')');
+ recommendations.forEach(function(rec) {
+
flowAnalysisCtrl.buildRuleList('recommendation', violationsMap, rec);
+ });
+
+ response.rules.forEach(function(rule) {
+ if (rule.enforcementPolicy === 'ENFORCE') {
+ var requirement = '<div
class="rules-list-rule-info"></div>';
+ var requirementName =
$('<div></div>').text(rule.name);
+ var requirementInfoButton = '<button
class="rule-menu-btn"><i class="fa fa-ellipsis-v rules-list-item-menu-target"
aria-hidden="true"></i></button>';
+ requirements.push(
+ {
+ 'requirement':
$(requirement).append(requirementName),
+ 'requirementInfoButton':
$(requirementInfoButton).data('ruleInfo', rule),
+ 'id': rule.id
+ }
+ )
+ requirementsTotal++;
+ }
+ });
+
+ // add class to notification icon for required
rules
+ var hasViolations =
response.ruleViolations.findIndex(function(violation) {
+ return violation.enforcementPolicy ===
'ENFORCE';
+ })
+ if (hasViolations !== -1) {
+ $('#flow-analysis
.flow-analysis-notification-icon ').addClass('violations');
+ } else {
+ $('#flow-analysis
.flow-analysis-notification-icon ').removeClass('violations');
+ }
+
+ requiredRuleCountEl.empty().append('(' +
requirementsTotal + ')');
+
+ // build violations
+ requirements.forEach(function(rec) {
+
flowAnalysisCtrl.buildRuleList('violation', violationsMap, rec);
+ });
+
+ $('#required-rules').accordion('refresh');
+ $('#recommended-rules').accordion('refresh');
+ // report the updated status
+ previousRulesResponse = response;
+
+ // setup rule menu handling
+ flowAnalysisCtrl.setRuleMenuHandling();
+
+ // setup violation menu handling
+
flowAnalysisCtrl.setViolationMenuHandling(response.rules);
+ }
+ }).fail(nfErrorHandler.handleAjaxError);
+ }
+ },
+
+ /**
+ * Set event bindings for rule menus
+ */
+ setRuleMenuHandling: function() {
+ $('.rule-menu-btn').click(function(event) {
+ // stop event from immediately bubbling up to document
and triggering closeRuleWindow
+ event.stopPropagation();
+ // unbind previously bound rule data that may still
exist
+ unbindRuleMenuHandling();
+
+ var ruleInfo = $(this).data('ruleInfo');
+ $('#violation-menu').hide();
+ $('#rule-menu').show();
+ $('#rule-menu').position({
+ my: "left top",
+ at: "left top",
+ of: event
+ });
+
+ // rule menu bindings
+ $('#rule-menu-edit-rule').on('click',
openRuleDetailsDialog);
+ $('#rule-menu-view-documentation').on('click',
viewRuleDocumentation);
+ $(document).on('click', closeRuleWindow);
+
+ function viewRuleDocumentation(e) {
+ nfShell.showPage('../nifi-docs/documentation?' +
$.param({
+ select: ruleInfo.type,
+ group: ruleInfo.bundle.group,
+ artifact: ruleInfo.bundle.artifact,
+ version: ruleInfo.bundle.version
+ })).done(function () {});
+ $("#rule-menu").hide();
+ unbindRuleMenuHandling();
+ }
+
+ function closeRuleWindow(e) {
+ if ($(e.target).parents("#rule-menu").length ===
0) {
+ $("#rule-menu").hide();
+ unbindRuleMenuHandling();
+ }
+ }
+
+ function openRuleDetailsDialog() {
+ $('#rule-menu').hide();
+ nfSettings.showSettings().done(function() {
+ nfSettings.selectFlowAnalysisRule(ruleInfo.id);
+ });
+ unbindRuleMenuHandling();
+ }
+
+ function unbindRuleMenuHandling() {
+ $('#rule-menu-edit-rule').off("click");
+ $('#rule-menu-view-documentation').off("click");
+ $(document).unbind('click', closeRuleWindow);
+ }
+
+ });
+ },
+
+ /**
+ * Set event bindings for violation menus
+ */
+ setViolationMenuHandling: function(rules) {
+ $('.violation-menu-btn').click(function(event) {
+ // stop event from immediately bubbling up to document
and triggering closeViolationWindow
+ event.stopPropagation();
+ var violationInfo = $(this).data('violationInfo');
+ $('#rule-menu').hide();
+ $('#violation-menu').show();
+ $('#violation-menu').position({
+ my: "left top",
+ at: "left top",
+ of: event
+ });
+
+ // violation menu bindings
+ $('#violation-menu-more-info').on( "click",
openRuleViolationMoreInfoDialog);
+ // If the groupId and subjectId are not the same, we
can select the component
+ console.log(violationInfo.groupId !==
violationInfo.subjectId);
+ console.log(violationInfo);
+ if (violationInfo.groupId !== violationInfo.subjectId)
{
+ $('#violation-menu-go-to').removeClass('disabled');
+ $('#violation-menu-go-to
.violation-menu-option-icon').removeClass('disabled');
+ $('#violation-menu-go-to').on('click',
goToComponent);
+ } else {
+ $('#violation-menu-go-to').addClass('disabled');
+ $('#violation-menu-go-to
.violation-menu-option-icon').addClass('disabled');
+ }
+ $(document).on('click', closeViolationWindow);
+
+ function closeViolationWindow(e) {
+ if ($(e.target).parents("#violation-menu").length
=== 0) {
+ $("#violation-menu").hide();
+ unbindViolationMenuHandling();
+ }
+ }
+
+ function openRuleViolationMoreInfoDialog() {
+ var rule = rules.find(function(rule){
+ return rule.id === violationInfo.ruleId;
+ });
+ $('#violation-menu').hide();
+ $('#violation-type-pill').empty()
+ .removeClass()
+
.addClass(violationInfo.enforcementPolicy.toLowerCase() + '
violation-type-pill')
+
.append(violationInfo.enforcementPolicy);
+
$('#violation-description').empty().append(violationInfo.violationMessage);
+ $('#violation-menu-more-info-dialog').modal(
"show" );
+ $('.violation-docs-link').click(function () {
+ // open the documentation for this flow
analysis rule
+ nfShell.showPage('../nifi-docs/documentation?'
+ $.param({
+ select: rule.type,
+ group: rule.bundle.group,
+ artifact: rule.bundle.artifact,
+ version: rule.bundle.version
+ })).done(function () {});
+ });
+ unbindViolationMenuHandling();
+ }
+
+ function goToComponent() {
+ $('#violation-menu').hide();
+ nfCanvasUtils.showComponent(violationInfo.groupId,
violationInfo.subjectId);
+ unbindViolationMenuHandling();
+ }
Review Comment:
I've tested canvas components and those seemed to work fine for me.
Controller Services definitely did not work. @tpalfy added this commit[1] in
another PR as a way of identifying the component type. I added a client-side
check so the Go To Component button is disabled if the violating component is a
CS. As a result, [his PR](https://github.com/apache/nifi/pull/8475) will need
to be merged first before this one.
[1]
https://github.com/apache/nifi/pull/8475/commits/054c39cf4a1155c5932d84b830deee8ed95a40e1
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]