NIFI-4436:

- Adding the version number to the start version control, commit, and change version dialog.
- Showing a loading item in the combo's while querying for the registries, buckets, and flows.
- Adding tooltips to display version control information on the canvas.
- Adding progress bar dialogs for changing version and reverting local changes.
- Updating canvas and breadcrumb according to the version control state.
- Updating to use registry name, bucket name, and flow name where appropriate.
This commit is contained in:
Matt Gilman 2017-11-10 15:58:59 -05:00 committed by Bryan Bende
parent 6b00dff1a8
commit d6e54f19ee
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
15 changed files with 652 additions and 175 deletions

View File

@ -32,7 +32,7 @@ public class VersionedFlowUpdateRequestDTO {
private Date lastUpdated;
private boolean complete = false;
private String failureReason;
private int percentComplete;
private int percentCompleted;
private String state;
private VersionControlInformationDTO versionControlInformation;
@ -110,11 +110,11 @@ public class VersionedFlowUpdateRequestDTO {
}
@ApiModelProperty(value = "The percentage complete for the request, between 0 and 100", readOnly = true)
public int getPercentComplete() {
return percentComplete;
public int getPercentCompleted() {
return percentCompleted;
}
public void setPercentComplete(int percentComplete) {
this.percentComplete = percentComplete;
public void setPercentCompleted(int percentCompleted) {
this.percentCompleted = percentCompleted;
}
}

View File

@ -17,37 +17,12 @@
package org.apache.nifi.web.api;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.ProcessGroupAuthorizable;
@ -94,12 +69,35 @@ import org.apache.nifi.web.util.Pause;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Authorization;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@Path("/versions")
@Api(value = "/versions", description = "Endpoint for managing version control for a flow")
@ -776,7 +774,7 @@ public class VersionsResource extends ApplicationResource {
updateRequestDto.setRequestId(requestId);
updateRequestDto.setUri(generateResourceUri("versions", requestType, requestId));
updateRequestDto.setState(asyncRequest.getState());
updateRequestDto.setPercentComplete(asyncRequest.getPercentComplete());
updateRequestDto.setPercentCompleted(asyncRequest.getPercentComplete());
if (updateRequestDto.isComplete()) {
final VersionControlInformationEntity vciEntity = serviceFacade.getVersionControlInformation(asyncRequest.getProcessGroupId());
@ -858,7 +856,7 @@ public class VersionsResource extends ApplicationResource {
updateRequestDto.setProcessGroupId(asyncRequest.getProcessGroupId());
updateRequestDto.setRequestId(requestId);
updateRequestDto.setUri(generateResourceUri("versions", requestType, requestId));
updateRequestDto.setPercentComplete(asyncRequest.getPercentComplete());
updateRequestDto.setPercentCompleted(asyncRequest.getPercentComplete());
updateRequestDto.setState(asyncRequest.getState());
if (updateRequestDto.isComplete()) {
@ -1040,7 +1038,7 @@ public class VersionsResource extends ApplicationResource {
updateRequestDto.setProcessGroupId(groupId);
updateRequestDto.setRequestId(requestId);
updateRequestDto.setUri(generateResourceUri("versions", "update-requests", requestId));
updateRequestDto.setPercentComplete(request.getPercentComplete());
updateRequestDto.setPercentCompleted(request.getPercentComplete());
updateRequestDto.setState(request.getState());
final VersionedFlowUpdateRequestEntity updateRequestEntity = new VersionedFlowUpdateRequestEntity();
@ -1192,7 +1190,7 @@ public class VersionsResource extends ApplicationResource {
updateRequestDto.setRequestId(requestId);
updateRequestDto.setVersionControlInformation(currentVersion);
updateRequestDto.setUri(generateResourceUri("versions", "revert-requests", requestId));
updateRequestDto.setPercentComplete(100);
updateRequestDto.setPercentCompleted(100);
updateRequestDto.setState(request.getState());
final VersionedFlowUpdateRequestEntity updateRequestEntity = new VersionedFlowUpdateRequestEntity();
@ -1231,6 +1229,8 @@ public class VersionsResource extends ApplicationResource {
updateRequestDto.setLastUpdated(request.getLastUpdated());
updateRequestDto.setProcessGroupId(groupId);
updateRequestDto.setRequestId(requestId);
updateRequestDto.setState(request.getState());
updateRequestDto.setPercentCompleted(request.getPercentComplete());
updateRequestDto.setUri(generateResourceUri("versions", "revert-requests", requestId));
final VersionedFlowUpdateRequestEntity updateRequestEntity = new VersionedFlowUpdateRequestEntity();

View File

@ -2230,8 +2230,8 @@ public final class DtoFactory {
dto.setFlowName(versionControlInfo.getFlowName());
dto.setFlowDescription(versionControlInfo.getFlowDescription());
dto.setVersion(versionControlInfo.getVersion());
dto.setCurrent(versionControlInfo.getCurrent().orElse(null));
dto.setModified(versionControlInfo.getModified().orElse(null));
dto.setCurrent(versionControlInfo.getCurrent().orElse(true));
dto.setModified(versionControlInfo.getModified().orElse(false));
return dto;
}

View File

@ -39,6 +39,24 @@
<div id="import-flow-version-name" class="hidden"></div>
</div>
</div>
<div id="import-flow-version-container" class="setting hidden">
<div class="setting-name">Current Version</div>
<div class="setting-field">
<div id="import-flow-version-label"></div>
</div>
</div>
<div id="import-flow-version-table"></div>
</div>
</div>
<div id="change-version-status-dialog" layout="column" class="hidden small-dialog">
<div class="dialog-content">
<div class="setting">
<div class="setting-field">
<div id="change-version-status-message"></div>
</div>
<div class="setting-field">
<div id="change-version-percent-complete"></div>
</div>
</div>
</div>
</div>

View File

@ -19,7 +19,11 @@
breadcrumbs="appCtrl.serviceProvider.breadcrumbsCtrl.getBreadcrumbs();"
click-func="appCtrl.nf.CanvasUtils.getComponentByType('ProcessGroup').enterGroup"
highlight-crumb-id="appCtrl.nf.CanvasUtils.getGroupId();"
separator-func="appCtrl.nf.Common.isDefinedAndNotNull">
separator-func="appCtrl.nf.Common.isDefinedAndNotNull"
is-tracking="appCtrl.serviceProvider.breadcrumbsCtrl.isTracking"
is-current="appCtrl.serviceProvider.breadcrumbsCtrl.isCurrent"
is-modified="appCtrl.serviceProvider.breadcrumbsCtrl.isModified"
get-version-control-tooltip="appCtrl.serviceProvider.breadcrumbsCtrl.getVersionControlTooltip">
</nf-breadcrumbs>
<div id="graph-controls">
<div id="navigation-control" class="graph-control">

View File

@ -19,9 +19,10 @@
<div class="dialog-content">
<div class="setting">
<div class="setting-name">Registry</div>
<div class="setting-field">
<div id="save-flow-version-registry-container" class="setting-field">
<div id="save-flow-version-registry-combo" class="hidden"></div>
<div id="save-flow-version-registry" class="hidden"></div>
<div id="save-flow-version-label"></div>
</div>
</div>
<div class="setting">

View File

@ -216,10 +216,30 @@ div.progress-label {
Save Flow Version
*/
#save-flow-version-registry-container {
display: flex;
}
#save-flow-version-description-field, #save-flow-version-change-comments {
height: 85px;
}
#save-flow-version-registry-combo, #save-flow-version-registry {
width: 100%;
margin-right: 10px;
}
#save-flow-version-label {
flex: 0 0 30px;
background-color: #728E9B;
color: #fff;
height: 30px;
line-height: 30px;
text-align: center;
border-radius: 50%;
padding: 0 1px;
}
/*
Import Flow Version
*/
@ -227,13 +247,22 @@ div.progress-label {
#import-flow-version-table {
overflow: hidden;
position: absolute;
top: 202px;
top: 190px;
left: 0px;
right: 0px;
bottom: 0px;
height: 225px;
}
#change-version-percent-complete {
margin-top: 10px;
border-radius: 0;
}
#change-version-percent-complete .ui-progressbar-value {
border-radius: 0;
}
/*
Variable Registry
*/

View File

@ -425,8 +425,7 @@ text.process-group-name {
text.version-control {
font-family: FontAwesome;
font-size: 18px;
fill: rgba(0, 255, 0, 0.65);
stroke: rgba(0, 0, 0, 0.65);
text-shadow: 0 0 4px rgba(255,255,255,1);
visibility: hidden;
}

View File

@ -278,9 +278,16 @@ rect.birdseye-brush {
top: 8px;
}
span.breadcrumb-version-control {
color: #0f0;
text-shadow: 0px 0px 1px #000;
span.breadcrumb-version-control-green {
color: #1a9964;
}
span.breadcrumb-version-control-red {
color: #ba554a;
}
span.breadcrumb-version-control-gray {
color: #666666;
}
#breadcrumbs-left-border {

View File

@ -96,6 +96,57 @@
this.breadcrumbs = [];
},
/**
* Whether this crumb is tracking.
*
* @param breadcrumbEntity
* @returns {*}
*/
isTracking: function (breadcrumbEntity) {
return nfCommon.isDefinedAndNotNull(breadcrumbEntity.breadcrumb.versionControlInformation);
},
/**
* Returns whether the specified version control information is current.
*
* @param breadcrumbEntity
* @returns {boolean}
*/
isCurrent: function (breadcrumbEntity) {
if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.breadcrumb.versionControlInformation)) {
return breadcrumbEntity.breadcrumb.versionControlInformation.current === true;
}
return false;
},
/**
* Returns whether the specified version control information is current.
*
* @param versionControlInformation
* @returns {boolean}
*/
isModified: function (breadcrumbEntity) {
if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.breadcrumb.versionControlInformation)) {
return breadcrumbEntity.breadcrumb.versionControlInformation.modified === true;
}
return false;
},
/**
* Gets the content for the version control tooltip for the specified breadcrumb.
*
* @param breadcrumbEntity
*/
getVersionControlTooltip: function (breadcrumbEntity) {
if (nfCommon.isDefinedAndNotNull(breadcrumbEntity.breadcrumb.versionControlInformation)) {
return nfCommon.getVersionControlTooltip(breadcrumbEntity.breadcrumb.versionControlInformation);
} else {
return 'This Process Group is not under version control.'
}
},
/**
* Get the breadcrumbs.
*/

View File

@ -40,7 +40,11 @@
'breadcrumbs': '=',
'clickFunc': '=',
'highlightCrumbId': '=',
'separatorFunc': '='
'separatorFunc': '=',
'isTracking': '=',
'isCurrent': '=',
'isModified': '=',
'getVersionControlTooltip': '='
},
link: function (scope, element, attrs) {
breadcrumbsCtrl.registerMouseWheelEvent(element);

View File

@ -81,6 +81,8 @@
$('#save-flow-version-registry-combo').combo('destroy').hide();
$('#save-flow-version-bucket-combo').combo('destroy').hide();
$('#save-flow-version-label').text('');
$('#save-flow-version-registry').text('').hide();
$('#save-flow-version-bucket').text('').hide();
@ -98,6 +100,8 @@
* Reset the import flow version dialog.
*/
var resetImportFlowVersionDialog = function () {
$('#import-flow-version-dialog').removeData('pt');
$('#import-flow-version-registry-combo').combo('destroy').hide();
$('#import-flow-version-bucket-combo').combo('destroy').hide();
$('#import-flow-version-name-combo').combo('destroy').hide();
@ -108,11 +112,17 @@
var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
if (nfCommon.isDefinedAndNotNull(importFlowVersionGrid)) {
importFlowVersionGrid.setSelectedRows([]);
importFlowVersionGrid.resetActiveCell();
var importFlowVersionData = importFlowVersionGrid.getData();
importFlowVersionData.setItems([]);
}
$('#import-flow-version-process-group-id').removeData('versionControlInformation').removeData('revision').text('');
$('#import-flow-version-container').hide();
$('#import-flow-version-label').text('');
};
/**
@ -392,9 +402,13 @@
$('#import-flow-version-dialog').modal('refreshButtons');
});
importFlowVersionGrid.onDblClick.subscribe(function (e, args) {
changeFlowVersion().done(function () {
$('#import-flow-version-dialog').modal('hide');
});
if ($('#import-flow-version-label').is(':visible')) {
changeFlowVersion();
} else {
importFlowVersion().always(function () {
$('#import-flow-version-dialog').modal('hide');
});
}
});
// wire up the dataview to the grid
@ -417,19 +431,35 @@
*/
var showImportFlowVersionDialog = function () {
var pt = $('#new-process-group-dialog').data('pt');
$('#import-flow-version-dialog').data('pt', pt);
// update the registry and bucket visibility
var registryCombo = $('#import-flow-version-registry-combo').show();
var bucketCombo = $('#import-flow-version-bucket-combo').show();
$('#import-flow-version-name-combo').show();
var registryCombo = $('#import-flow-version-registry-combo').combo('destroy').combo({
options: [{
text: 'Loading registries...',
value: null,
optionClass: 'unset',
disabled: true
}]
}).show();
var bucketCombo = $('#import-flow-version-bucket-combo').combo('destroy').combo({
options: [{
text: 'Loading buckets...',
value: null,
optionClass: 'unset',
disabled: true
}]
}).show();
$('#import-flow-version-name-combo').combo('destroy').combo({
options: [{
text: 'Loading flows...',
value: null,
optionClass: 'unset',
disabled: true
}]
}).show();
loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, selectBucketImportVersion).done(function () {
// reposition the version table
$('#import-flow-version-table').css({
'top': '202px',
'height': '225px'
});
// show the import dialog
$('#import-flow-version-dialog').modal('setHeaderText', 'Import Version').modal('setButtonModel', [{
buttonText: 'Import',
@ -441,8 +471,7 @@
disabled: disableImportOrChangeButton,
handler: {
click: function () {
importFlowVersion(pt).always(function (response) {
// close the dialog
importFlowVersion().always(function () {
$('#import-flow-version-dialog').modal('hide');
});
}
@ -599,7 +628,9 @@
/**
* Imports the selected flow version.
*/
var importFlowVersion = function (pt) {
var importFlowVersion = function () {
var pt = $('#import-flow-version-dialog').data('pt');
var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
var selectedBucket = $('#import-flow-version-bucket-combo').combo('getSelectedOption');
var selectedFlow = $('#import-flow-version-name-combo').combo('getSelectedOption');
@ -673,6 +704,8 @@
*/
var changeFlowVersion = function () {
var changeTimer = null;
var changeRequest = null;
var cancelled = false;
var processGroupId = $('#import-flow-version-process-group-id').text();
var processGroupRevision = $('#import-flow-version-process-group-id').data('revision');
@ -682,7 +715,34 @@
var selectedVersionIndex = importFlowVersionGrid.getSelectedRows();
var selectedVersion = importFlowVersionGrid.getDataItem(selectedVersionIndex[0]);
// TODO - introduce dialog to show current state with option to cancel once available
// update the button model of the change version status dialog
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Stop',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
cancelled = true;
$('#change-version-status-dialog').modal('setButtonModel', []);
// we are waiting for the next poll attempt
if (changeTimer !== null) {
// cancel it
clearTimeout(changeTimer);
// cancel the change request
completeChangeRequest();
}
}
}
}]);
// hide the import dialog immediately
$('#import-flow-version-dialog').modal('hide');
var submitChangeRequest = function () {
var changeVersionRequest = {
@ -706,69 +766,116 @@
url: '../nifi-api/versions/update-requests/process-groups/' + encodeURIComponent(processGroupId),
dataType: 'json',
contentType: 'application/json'
}).done(function (response) {
console.log(response);
}).done(function () {
// initialize the progress bar value
updateProgress(0);
// show the progress dialog
$('#change-version-status-dialog').modal('show');
}).fail(nfErrorHandler.handleAjaxError);
};
var pollChangeRequest = function (changeRequest) {
getChangeRequest(changeRequest).done(function (response) {
processChangeResponse(response);
})
var pollChangeRequest = function () {
getChangeRequest().done(processChangeResponse);
};
var getChangeRequest = function (changeRequest) {
var getChangeRequest = function () {
return $.ajax({
type: 'GET',
url: changeRequest.uri,
dataType: 'json'
}).fail(nfErrorHandler.handleAjaxError);
}).fail(completeChangeRequest).fail(nfErrorHandler.handleAjaxError);
};
var deleteChangeRequest = function (changeRequest) {
var deleteXhr = $.ajax({
type: 'DELETE',
url: changeRequest.uri,
dataType: 'json'
}).fail(nfErrorHandler.handleAjaxError);
var completeChangeRequest = function () {
if (cancelled === true) {
// update the message to indicate successful completion
$('#change-version-status-message').text('The change version request has been cancelled.');
updateProcessGroup(processGroupId);
// update the button model
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Close',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}]);
}
nfDialog.showOkDialog({
headerText: 'Change Version',
dialogContent: 'This Process Group version has changed.'
});
if (nfCommon.isDefinedAndNotNull(changeRequest)) {
$.ajax({
type: 'DELETE',
url: changeRequest.uri,
dataType: 'json'
}).done(function (response) {
changeRequest = response.request;
return deleteXhr;
// update the component that was changing
updateProcessGroup(processGroupId);
if (nfCommon.isDefinedAndNotNull(changeRequest.failureReason)) {
// hide the progress dialog
$('#change-version-status-dialog').modal('hide');
nfDialog.showOkDialog({
headerText: 'Change Version',
dialogContent: nfCommon.escapeHtml(changeRequest.failureReason)
});
} else {
// update the percent complete
updateProgress(changeRequest.percentCompleted);
// update the message to indicate successful completion
$('#change-version-status-message').text('This Process Group version has changed.');
// update the button model
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Close',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}]);
}
});
}
};
var processChangeResponse = function (response) {
var changeRequest = response.request;
changeRequest = response.request;
if (nfCommon.isDefinedAndNotNull(changeRequest.failureReason)) {
nfDialog.showOkDialog({
headerText: 'Change Version',
dialogContent: nfCommon.escapeHtml(changeRequest.failureReason)
});
}
if (changeRequest.complete === true) {
deleteChangeRequest(changeRequest);
if (changeRequest.complete === true || cancelled === true) {
completeChangeRequest();
} else {
// update the percent complete
updateProgress(changeRequest.percentCompleted);
// update the status of the listing request
$('#change-version-status-message').text(changeRequest.state);
changeTimer = setTimeout(function () {
// clear the timer since we've been invoked
changeTimer = null;
// poll revert request
pollChangeRequest(changeRequest);
pollChangeRequest();
}, 2000);
}
};
submitChangeRequest().done(function (response) {
processChangeResponse(response);
});
submitChangeRequest().done(processChangeResponse);
};
/**
@ -826,7 +933,7 @@
*/
var updateProcessGroup = function (processGroupId) {
if (nfCanvasUtils.getGroupId() === processGroupId) {
// if reverting current PG... reload/refresh this group/canvas
// if reverting/changing current PG... reload/refresh this group/canvas
// TODO consider implementing this differently
$.ajax({
@ -842,6 +949,23 @@
}
};
/**
* Updates the progress bar to the specified percent complete.
*
* @param percentComplete
*/
var updateProgress = function (percentComplete) {
// remove existing labels
var progressBar = $('#change-version-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);
};
return {
init: function (timeOffset) {
serverTimeOffset = timeOffset;
@ -913,6 +1037,18 @@
}
});
// configure the drop request status dialog
$('#change-version-status-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Change Flow Version',
handler: {
close: function () {
// clear the current button model
$('#change-version-status-dialog').modal('setButtonModel', []);
}
}
});
// handle the click for the process group import
$('#import-process-group-link').on('click', function() {
showImportFlowVersionDialog();
@ -939,26 +1075,50 @@
var versionControlInformation = groupVersionControlInformation.versionControlInformation;
// update the registry and bucket visibility
$('#save-flow-version-registry').text(versionControlInformation.registryId).show();
$('#save-flow-version-bucket').text(versionControlInformation.bucketId).show();
$('#save-flow-version-registry').text(versionControlInformation.registryName).show();
$('#save-flow-version-bucket').text(versionControlInformation.bucketName).show();
$('#save-flow-version-label').text(versionControlInformation.version + 1);
$('#save-flow-version-name').text(versionControlInformation.flowName).show();
$('#save-flow-version-description').text('Flow description goes here').show();
$('#save-flow-version-description').text(versionControlInformation.flowDescription).show();
// record the versionControlInformation
$('#save-flow-version-process-group-id').data('versionControlInformation', versionControlInformation);
// reposition the version label
$('#save-flow-version-label').css('margin-top', '-15px');
focusName = false;
deferred.resolve();
} else {
// update the registry and bucket visibility
$('#save-flow-version-registry-combo').show();
$('#save-flow-version-bucket-combo').show();
var registryCombo = $('#save-flow-version-registry-combo').combo('destroy').combo({
options: [{
text: 'Loading registries...',
value: null,
optionClass: 'unset',
disabled: true
}]
}).show();
var bucketCombo = $('#save-flow-version-bucket-combo').combo('destroy').combo({
options: [{
text: 'Loading buckets...',
value: null,
optionClass: 'unset',
disabled: true
}]
}).show();
// set the initial version
$('#save-flow-version-label').text(1);
$('#save-flow-version-name-field').show();
$('#save-flow-version-description-field').show();
loadRegistries($('#save-flow-version-dialog'), $('#save-flow-version-registry-combo'), $('#save-flow-version-bucket-combo'), selectBucketSaveFlowVersion).done(function () {
// reposition the version label
$('#save-flow-version-label').css('margin-top', '0');
loadRegistries($('#save-flow-version-dialog'), registryCombo, bucketCombo, selectBucketSaveFlowVersion).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();
@ -996,8 +1156,37 @@
getVersionControlInformation(processGroupId).done(function (response) {
if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) {
var revertTimer = null;
var revertRequest = null;
var cancelled = false;
// TODO - introduce dialog to show current state once available
// update the button model of the revert status dialog
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Stop',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
cancelled = true;
$('#change-version-status-dialog').modal('setButtonModel', []);
// we are waiting for the next poll attempt
if (revertTimer !== null) {
// cancel it
clearTimeout(revertTimer);
// cancel the revert request
completeRevertRequest();
}
}
}
}]);
// hide the import dialog immediately
$('#import-flow-version-dialog').modal('hide');
var submitRevertRequest = function () {
var revertFlowVersionRequest = {
@ -1015,66 +1204,116 @@
url: '../nifi-api/versions/revert-requests/process-groups/' + encodeURIComponent(processGroupId),
dataType: 'json',
contentType: 'application/json'
}).done(function () {
// initialize the progress bar value
updateProgress(0);
// show the progress dialog
$('#change-version-status-dialog').modal('show');
}).fail(nfErrorHandler.handleAjaxError);
};
var pollRevertRequest = function (revertRequest) {
getRevertRequest(revertRequest).done(function (response) {
processRevertResponse(response);
})
var pollRevertRequest = function () {
getRevertRequest().done(processRevertResponse);
};
var getRevertRequest = function (revertRequest) {
var getRevertRequest = function () {
return $.ajax({
type: 'GET',
url: revertRequest.uri,
dataType: 'json'
}).fail(nfErrorHandler.handleAjaxError);
}).fail(completeRevertRequest).fail(nfErrorHandler.handleAjaxError);
};
var deleteRevertRequest = function (revertRequest) {
var deleteXhr = $.ajax({
type: 'DELETE',
url: revertRequest.uri,
dataType: 'json'
}).fail(nfErrorHandler.handleAjaxError);
var completeRevertRequest = function () {
if (cancelled === true) {
// update the message to indicate successful completion
$('#change-version-status-message').text('The revert request has been cancelled.');
updateProcessGroup(processGroupId);
// update the button model
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Close',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}]);
}
nfDialog.showOkDialog({
headerText: 'Revert Changes',
dialogContent: 'This Process Group has been reverted.'
});
if (nfCommon.isDefinedAndNotNull(revertRequest)) {
$.ajax({
type: 'DELETE',
url: revertRequest.uri,
dataType: 'json'
}).done(function (response) {
revertRequest = response.request;
return deleteXhr;
// update the component that was changing
updateProcessGroup(processGroupId);
if (nfCommon.isDefinedAndNotNull(revertRequest.failureReason)) {
// hide the progress dialog
$('#change-version-status-dialog').modal('hide');
nfDialog.showOkDialog({
headerText: 'Revert Local Changes',
dialogContent: nfCommon.escapeHtml(changeRequest.failureReason)
});
} else {
// update the percent complete
updateProgress(revertRequest.percentCompleted);
// update the message to indicate successful completion
$('#change-version-status-message').text('This Process Group version has changed.');
// update the button model
$('#change-version-status-dialog').modal('setButtonModel', [{
buttonText: 'Close',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}]);
}
});
}
};
var processRevertResponse = function (response) {
var revertRequest = response.request;
revertRequest = response.request;
if (nfCommon.isDefinedAndNotNull(revertRequest.failureReason)) {
nfDialog.showOkDialog({
headerText: 'Revert Changes',
dialogContent: nfCommon.escapeHtml(revertRequest.failureReason)
});
}
if (revertRequest.complete === true) {
deleteRevertRequest(revertRequest);
if (revertRequest.complete === true || cancelled === true) {
completeRevertRequest();
} else {
// update the percent complete
updateProgress(revertRequest.percentCompleted);
// update the status of the revert request
$('#change-version-status-message').text(revertRequest.state);
revertTimer = setTimeout(function () {
// clear the timer since we've been invoked
revertTimer = null;
// poll revert request
pollRevertRequest(revertRequest);
pollRevertRequest();
}, 2000);
}
};
submitRevertRequest().done(function (response) {
processRevertResponse(response);
});
submitRevertRequest().done(processRevertResponse);
} else {
nfDialog.showOkDialog({
headerText: 'Revert Changes',
@ -1098,9 +1337,13 @@
var versionControlInformation = groupVersionControlInformation.versionControlInformation;
// update the registry and bucket visibility
$('#import-flow-version-registry').text(versionControlInformation.registryId).show();
$('#import-flow-version-bucket').text(versionControlInformation.bucketId).show();
$('#import-flow-version-name').text(versionControlInformation.flowId).show();
$('#import-flow-version-registry').text(versionControlInformation.registryName).show();
$('#import-flow-version-bucket').text(versionControlInformation.bucketName).show();
$('#import-flow-version-name').text(versionControlInformation.flowName).show();
// show the current version information
$('#import-flow-version-container').show();
$('#import-flow-version-label').text(versionControlInformation.version);
// record the versionControlInformation
$('#import-flow-version-process-group-id').data('versionControlInformation', versionControlInformation).data('revision', groupVersionControlInformation.processGroupRevision).text(processGroupId);
@ -1126,12 +1369,6 @@
}
}).fail(nfErrorHandler.handleAjaxError);
}).done(function () {
// reposition the version table
$('#import-flow-version-table').css({
'top': '150px',
'height': '277px'
});
// show the dialog
$('#import-flow-version-dialog').modal('setHeaderText', 'Change Version').modal('setButtonModel', [{
buttonText: 'Change',
@ -1143,9 +1380,7 @@
disabled: disableImportOrChangeButton,
handler: {
click: function () {
changeFlowVersion().done(function () {
$('#import-flow-version-dialog').modal('hide');
});
changeFlowVersion();
}
}
}, {

View File

@ -98,6 +98,15 @@
}
};
/**
* Determines whether the specified process group is under version control.
*
* @param d
*/
var isUnderVersionControl = function (d) {
return nfCommon.isDefinedAndNotNull(d.component.versionControlInformation);
};
/**
* Selects the process group elements against the current process group map.
*/
@ -183,11 +192,10 @@
// process group name
processGroup.append('text')
.attr({
'x': 3,
'y': 17,
'x': 10,
'y': 21,
'class': 'version-control'
})
.text('\uf00c');
});
// always support selecting and navigation
processGroup.on('dblclick', function (d) {
@ -848,6 +856,77 @@
});
if (processGroupData.permissions.canRead) {
// update version control information
var versionControl = processGroup.select('text.version-control')
.style({
'visibility': isUnderVersionControl(processGroupData) ? 'visible' : 'hidden',
'fill': function () {
if (isUnderVersionControl(processGroupData)) {
var modified = processGroupData.component.versionControlInformation.modified;
var current = processGroupData.component.versionControlInformation.current;
if (modified === true && current === false) {
return '#BA554A';
} else if (current === false) {
return '#BA554A';
} else if (modified === true) {
return '#666666';
} else {
return '#1A9964';
}
} else {
return '#000';
}
}
})
.text(function () {
if (isUnderVersionControl(processGroupData)) {
var modified = processGroupData.component.versionControlInformation.modified;
var current = processGroupData.component.versionControlInformation.current;
if (modified === true && current === false) {
return '\uf06a';
} else if (current === false) {
return '\uf0aa';
} else if (modified === true) {
return '\uf069';
} else {
return '\uf00c';
}
} else {
return '';
}
}).each(function () {
// get the tip
var tip = d3.select('#version-control-tip-' + processGroupData.id);
// if there are validation errors generate a tooltip
if (isUnderVersionControl(processGroupData)) {
// create the tip if necessary
if (tip.empty()) {
tip = d3.select('#process-group-tooltips').append('div')
.attr('id', function () {
return 'version-control-tip-' + processGroupData.id;
})
.attr('class', 'tooltip nifi-tooltip');
}
// update the tip
tip.html(function () {
var vci = processGroupData.component.versionControlInformation;
var versionControlTip = $('<div></div>').text('Tracking to "' + vci.flowName + '" version ' + vci.version + ' in "' + vci.registryName + ' - ' + vci.bucketName + '"');
var versionControlStateTip = $('<div></div>').text(nfCommon.getVersionControlTooltip(vci));
return $('<div></div>').append(versionControlTip).append('<br/>').append(versionControlStateTip).html();
});
// add the tooltip
nfCanvasUtils.canvasTooltip(tip, d3.select(this));
} else {
// remove the tip if necessary
if (!tip.empty()) {
tip.remove();
}
}
});
// update the process group comments
details.select('text.process-group-comments')
.each(function (d) {
@ -866,6 +945,25 @@
// update the process group name
processGroup.select('text.process-group-name')
.attr({
'x': function () {
if (isUnderVersionControl(processGroupData)) {
var versionControlX = parseInt(versionControl.attr('x'), 10);
return versionControlX + Math.round(versionControl.node().getComputedTextLength()) + CONTENTS_VALUE_SPACER;
} else {
return 10;
}
},
'width': function () {
if (isUnderVersionControl(processGroupData)) {
var versionControlX = parseInt(versionControl.attr('x'), 10);
var processGroupNameX = parseInt(d3.select(this).attr('x'), 10);
return 316 - (processGroupNameX - versionControlX);
} else {
return 316;
}
}
})
.each(function (d) {
var processGroupName = d3.select(this);
@ -874,21 +972,25 @@
// apply ellipsis to the process group name as necessary
nfCanvasUtils.ellipsis(processGroupName, d.component.name);
}).append('title').text(function (d) {
return d.component.name;
});
// update version control information
processGroup.select('text.version-control').style('visibility', nfCommon.isDefinedAndNotNull(processGroupData.component.versionControlInformation) ? 'visible' : 'hidden');
})
.append('title')
.text(function (d) {
return d.component.name;
});
} else {
// update version control information
processGroup.select('text.version-control').style('visibility', false).text('');
// clear the process group comments
details.select('text.process-group-comments').text(null);
// clear the process group name
processGroup.select('text.process-group-name').text(null);
// update version control information
processGroup.select('text.version-control').style('visibility', false);
processGroup.select('text.process-group-name')
.attr({
'x': 10,
'width': 316
})
.text(null);
}
// populate the stats
@ -1033,6 +1135,7 @@
removed.each(function (d) {
// remove any associated tooltips
$('#bulletin-tip-' + d.id).remove();
$('#version-control-tip-' + d.id).remove();
});
};

View File

@ -419,6 +419,25 @@
return nfCommon.typeBundleFormatter(row, cell, value, columnDef, dataContext.component);
},
/**
* Gets the version control tooltip.
*
* @param versionControlInformation
*/
getVersionControlTooltip: function (versionControlInformation) {
var modified = versionControlInformation.modified;
var current = versionControlInformation.current;
if (modified === true && current === false) {
return 'Local changes have been made and a newer version of this flow is available';
} else if (current === false) {
return 'A newer version of this flow is available';
} else if (modified === true) {
return 'Local changes have been made';
} else {
return 'Flow version is current';
}
},
/**
* Formats the class name of this component.
*

View File

@ -22,7 +22,14 @@ limitations under the License.
<span ng-if="separatorFunc(crumb.parentBreadcrumb)" style="margin: 0 12px;">
&raquo;
</span>
<span ng-if="separatorFunc(crumb.breadcrumb.versionControlInformation)" class="breadcrumb-version-control fa fa-check" style="margin: 0 6px;"></span>
<span ng-if="isTracking(crumb) && isCurrent(crumb) && !isModified(crumb)" title="{{getVersionControlTooltip(crumb)}}"
class="breadcrumb-version-control-green fa fa-check" style="margin: 0 6px;"></span>
<span ng-if="isTracking(crumb) && isCurrent(crumb) && isModified(crumb)" title="{{getVersionControlTooltip(crumb)}}"
class="breadcrumb-version-control-gray fa fa-asterisk" style="margin: 0 6px;"></span>
<span ng-if="isTracking(crumb) && !isCurrent(crumb) && !isModified(crumb)" title="{{getVersionControlTooltip(crumb)}}"
class="breadcrumb-version-control-red fa fa-arrow-circle-up" style="margin: 0 6px;"></span>
<span ng-if="isTracking(crumb) && !isCurrent(crumb) && isModified(crumb)" title="{{getVersionControlTooltip(crumb)}}"
class="breadcrumb-version-control-red fa fa-exclamation-circle" style="margin: 0 6px;"></span>
<span class="link"
ng-class="(highlightCrumbId === crumb.id) ? 'link-bold' : ''"
ng-click="clickFunc(crumb.id)">