NIFI-4436:

- Clearing bucket/flow/versions when changing the selected registry/bucket.
- Using the versioned flow to get the group name when importing.
- Adding menu items for viewing local changes.
- Showing local changes during revert request.
This commit is contained in:
Matt Gilman 2017-11-16 14:41:41 -05:00 committed by Bryan Bende
parent f6cc5b6cdc
commit 3d8b1e4890
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
13 changed files with 1008 additions and 321 deletions

View File

@ -17,12 +17,11 @@
package org.apache.nifi.web.api.dto; package org.apache.nifi.web.api.dto;
import java.util.List; import io.swagger.annotations.ApiModelProperty;
import java.util.Objects;
import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlType;
import java.util.List;
import io.swagger.annotations.ApiModelProperty; import java.util.Objects;
@XmlType(name = "componentDifference") @XmlType(name = "componentDifference")
public class ComponentDifferenceDTO { public class ComponentDifferenceDTO {
@ -30,7 +29,7 @@ public class ComponentDifferenceDTO {
private String componentId; private String componentId;
private String componentName; private String componentName;
private String processGroupId; private String processGroupId;
private List<String> differences; private List<DifferenceDTO> differences;
@ApiModelProperty("The type of component") @ApiModelProperty("The type of component")
public String getComponentType() { public String getComponentType() {
@ -69,11 +68,11 @@ public class ComponentDifferenceDTO {
} }
@ApiModelProperty("The differences in the component between the two flows") @ApiModelProperty("The differences in the component between the two flows")
public List<String> getDifferences() { public List<DifferenceDTO> getDifferences() {
return differences; return differences;
} }
public void setDifferences(List<String> differences) { public void setDifferences(List<DifferenceDTO> differences) {
this.differences = differences; this.differences = differences;
} }

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.
*/
package org.apache.nifi.web.api.dto;
import io.swagger.annotations.ApiModelProperty;
import javax.xml.bind.annotation.XmlType;
@XmlType(name = "difference")
public class DifferenceDTO {
private String differenceType;
private String difference;
@ApiModelProperty("The type of difference")
public String getDifferenceType() {
return differenceType;
}
public void setDifferenceType(String differenceType) {
this.differenceType = differenceType;
}
@ApiModelProperty("Description of the difference")
public String getDifference() {
return difference;
}
public void setDifference(String difference) {
this.difference = difference;
}
}

View File

@ -16,57 +16,12 @@
*/ */
package org.apache.nifi.web.api; package org.apache.nifi.web.api;
import java.io.IOException; import io.swagger.annotations.Api;
import java.io.InputStream; import io.swagger.annotations.ApiOperation;
import java.net.URI; import io.swagger.annotations.ApiParam;
import java.net.URISyntaxException; import io.swagger.annotations.ApiResponse;
import java.util.Collection; import io.swagger.annotations.ApiResponses;
import java.util.Collections; import io.swagger.annotations.Authorization;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
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.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.AuthorizableLookup; import org.apache.nifi.authorization.AuthorizableLookup;
import org.apache.nifi.authorization.AuthorizeAccess; import org.apache.nifi.authorization.AuthorizeAccess;
@ -156,12 +111,55 @@ import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import io.swagger.annotations.Api; import javax.servlet.http.HttpServletRequest;
import io.swagger.annotations.ApiOperation; import javax.ws.rs.Consumes;
import io.swagger.annotations.ApiParam; import javax.ws.rs.DELETE;
import io.swagger.annotations.ApiResponse; import javax.ws.rs.DefaultValue;
import io.swagger.annotations.ApiResponses; import javax.ws.rs.GET;
import io.swagger.annotations.Authorization; 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.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* RESTful endpoint for managing a Group. * RESTful endpoint for managing a Group.
@ -341,9 +339,7 @@ public class ProcessGroupResource extends ApplicationResource {
// authorize access // authorize access
serviceFacade.authorizeAccess(lookup -> { serviceFacade.authorizeAccess(lookup -> {
final ProcessGroupAuthorizable groupAuthorizable = lookup.getProcessGroup(groupId); final ProcessGroupAuthorizable groupAuthorizable = lookup.getProcessGroup(groupId);
final Authorizable processGroup = groupAuthorizable.getAuthorizable(); authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.READ, false, false, true, false);
processGroup.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
super.authorizeProcessGroup(groupAuthorizable, authorizer, lookup, RequestAction.READ, false, false, true, false);
}); });
final FlowComparisonEntity entity = serviceFacade.getLocalModifications(groupId); final FlowComparisonEntity entity = serviceFacade.getLocalModifications(groupId);
@ -1625,6 +1621,11 @@ public class ProcessGroupResource extends ApplicationResource {
} }
} }
// if the group name isn't specified, ensure the group is being imported from version control
if (StringUtils.isBlank(requestProcessGroupEntity.getComponent().getName()) && requestProcessGroupEntity.getComponent().getVersionControlInformation() == null) {
throw new IllegalArgumentException("The group name is required when the group is not imported from version control.");
}
if (requestProcessGroupEntity.getComponent().getParentGroupId() != null && !groupId.equals(requestProcessGroupEntity.getComponent().getParentGroupId())) { if (requestProcessGroupEntity.getComponent().getParentGroupId() != null && !groupId.equals(requestProcessGroupEntity.getComponent().getParentGroupId())) {
throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s", throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
requestProcessGroupEntity.getComponent().getParentGroupId(), groupId)); requestProcessGroupEntity.getComponent().getParentGroupId(), groupId));
@ -1688,15 +1689,22 @@ public class ProcessGroupResource extends ApplicationResource {
serviceFacade.verifyComponentTypes(versionedFlowSnapshot.getFlowContents()); serviceFacade.verifyComponentTypes(versionedFlowSnapshot.getFlowContents());
} }
}, },
processGroupGroupEntity -> { processGroupEntity -> {
final ProcessGroupDTO processGroup = processGroupEntity.getComponent();
// set the processor id as appropriate // set the processor id as appropriate
processGroupGroupEntity.getComponent().setId(generateUuid()); processGroup.setId(generateUuid());
// ensure the group name comes from the versioned flow
final VersionedFlowSnapshot flowSnapshot = processGroupEntity.getVersionedFlowSnapshot();
if (flowSnapshot != null && StringUtils.isNotBlank(flowSnapshot.getFlowContents().getName()) && StringUtils.isBlank(processGroup.getName())) {
processGroup.setName(flowSnapshot.getFlowContents().getName());
}
// create the process group contents // create the process group contents
final Revision revision = getRevision(processGroupGroupEntity, processGroupGroupEntity.getComponent().getId()); final Revision revision = getRevision(processGroupEntity, processGroup.getId());
ProcessGroupEntity entity = serviceFacade.createProcessGroup(revision, groupId, processGroupGroupEntity.getComponent()); ProcessGroupEntity entity = serviceFacade.createProcessGroup(revision, groupId, processGroup);
final VersionedFlowSnapshot flowSnapshot = requestProcessGroupEntity.getVersionedFlowSnapshot();
if (flowSnapshot != null) { if (flowSnapshot != null) {
final RevisionDTO revisionDto = entity.getRevision(); final RevisionDTO revisionDto = entity.getRevision();
final String newGroupId = entity.getComponent().getId(); final String newGroupId = entity.getComponent().getId();

View File

@ -16,33 +16,6 @@
*/ */
package org.apache.nifi.web.api.dto; package org.apache.nifi.web.api.dto;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.ws.rs.WebApplicationException;
import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.action.Action; import org.apache.nifi.action.Action;
@ -215,6 +188,32 @@ import org.apache.nifi.web.api.entity.VariableEntity;
import org.apache.nifi.web.controller.ControllerFacade; import org.apache.nifi.web.controller.ControllerFacade;
import org.apache.nifi.web.revision.RevisionManager; import org.apache.nifi.web.revision.RevisionManager;
import javax.ws.rs.WebApplicationException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public final class DtoFactory { public final class DtoFactory {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -2181,15 +2180,20 @@ public final class DtoFactory {
public Set<ComponentDifferenceDTO> createComponentDifferenceDtos(final FlowComparison comparison) { public Set<ComponentDifferenceDTO> createComponentDifferenceDtos(final FlowComparison comparison) {
final Map<ComponentDifferenceDTO, List<String>> differencesByComponent = new HashMap<>(); final Map<ComponentDifferenceDTO, List<DifferenceDTO>> differencesByComponent = new HashMap<>();
for (final FlowDifference difference : comparison.getDifferences()) { for (final FlowDifference difference : comparison.getDifferences()) {
final ComponentDifferenceDTO componentDiff = createComponentDifference(difference); final ComponentDifferenceDTO componentDiff = createComponentDifference(difference);
final List<String> differences = differencesByComponent.computeIfAbsent(componentDiff, key -> new ArrayList<>()); final List<DifferenceDTO> differences = differencesByComponent.computeIfAbsent(componentDiff, key -> new ArrayList<>());
differences.add(difference.getDescription());
final DifferenceDTO dto = new DifferenceDTO();
dto.setDifferenceType(difference.getDifferenceType().getDescription());
dto.setDifference(difference.getDescription());
differences.add(dto);
} }
for (final Map.Entry<ComponentDifferenceDTO, List<String>> entry : differencesByComponent.entrySet()) { for (final Map.Entry<ComponentDifferenceDTO, List<DifferenceDTO>> entry : differencesByComponent.entrySet()) {
entry.getKey().setDifferences(entry.getValue()); entry.getKey().setDifferences(entry.getValue());
} }

View File

@ -61,7 +61,9 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
// create the process group // create the process group
ProcessGroup group = flowController.createProcessGroup(processGroup.getId()); ProcessGroup group = flowController.createProcessGroup(processGroup.getId());
if (processGroup.getName() != null) {
group.setName(processGroup.getName()); group.setName(processGroup.getName());
}
if (processGroup.getPosition() != null) { if (processGroup.getPosition() != null) {
group.setPosition(new Position(processGroup.getPosition().getX(), processGroup.getPosition().getY())); group.setPosition(new Position(processGroup.getPosition().getX(), processGroup.getPosition().getY()));
} }

View File

@ -117,6 +117,8 @@
<jsp:include page="/WEB-INF/partials/canvas/connections-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/connections-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/save-flow-version-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/save-flow-version-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/import-flow-version-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/import-flow-version-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/revert-local-changes-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/show-local-changes-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/registry-configuration-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/registry-configuration-dialog.jsp"/>
<div id="canvas-container" class="unselectable"></div> <div id="canvas-container" class="unselectable"></div>
<div id="canvas-tooltips"> <div id="canvas-tooltips">

View File

@ -0,0 +1,36 @@
<%--
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="revert-local-changes-dialog" layout="column" class="hidden large-dialog">
<div class="dialog-content">
<div class="setting">
<div class="setting-field">
Are you sure you want to revert changes? All flow configuration changes detailed below will be reverted to the last version.
</div>
</div>
<span id="revert-local-changes-process-group-id" class="hidden"></span>
<div id="revert-local-changes-filter-controls">
<div id="revert-local-changes-filter-status" class="filter-status">
Displaying&nbsp;<span id="displayed-revert-local-changes-entries"></span>&nbsp;of&nbsp;<span id="total-revert-local-changes-entries"></span>
</div>
<div id="revert-local-changes-filter-container">
<input type="text" id="revert-local-changes-filter" placeholder="Filter"/>
</div>
</div>
<div id="revert-local-changes-table"></div>
</div>
</div>

View File

@ -0,0 +1,35 @@
<%--
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="show-local-changes-dialog" layout="column" class="hidden large-dialog">
<div class="dialog-content">
<div class="setting">
<div class="setting-field">
The following changes have been made to the flow since the last version.
</div>
</div>
<div id="show-local-changes-filter-controls">
<div id="show-local-changes-filter-status" class="filter-status">
Displaying&nbsp;<span id="displayed-show-local-changes-entries"></span>&nbsp;of&nbsp;<span id="total-show-local-changes-entries"></span>
</div>
<div id="show-local-changes-filter-container">
<input type="text" id="show-local-changes-filter" placeholder="Filter"/>
</div>
</div>
<div id="show-local-changes-table"></div>
</div>
</div>

View File

@ -263,6 +263,23 @@ div.progress-label {
border-radius: 0; border-radius: 0;
} }
/*
Local changes
*/
#revert-local-changes-table, #show-local-changes-table {
position: absolute;
top: 80px;
left: 0px;
right: 0px;
bottom: 0px;
height: 225px;
}
#revert-local-changes-filter, #show-local-changes-filter {
width: 173px;
}
/* /*
Variable Registry Variable Registry
*/ */

View File

@ -25,9 +25,10 @@
'nf.Graph', 'nf.Graph',
'nf.CanvasUtils', 'nf.CanvasUtils',
'nf.ErrorHandler', 'nf.ErrorHandler',
'nf.Common'], 'nf.Common',
function ($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon) { 'nf.Dialog'],
return (nf.ng.GroupComponent = factory($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon)); function ($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon, nfDialog) {
return (nf.ng.GroupComponent = factory($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon, nfDialog));
}); });
} else if (typeof exports === 'object' && typeof module === 'object') { } else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.ng.GroupComponent = module.exports = (nf.ng.GroupComponent =
@ -37,7 +38,8 @@
require('nf.Graph'), require('nf.Graph'),
require('nf.CanvasUtils'), require('nf.CanvasUtils'),
require('nf.ErrorHandler'), require('nf.ErrorHandler'),
require('nf.Common'))); require('nf.Common'),
require('nf.Dialog')));
} else { } else {
nf.ng.GroupComponent = factory(root.$, nf.ng.GroupComponent = factory(root.$,
root.nf.Client, root.nf.Client,
@ -45,9 +47,10 @@
root.nf.Graph, root.nf.Graph,
root.nf.CanvasUtils, root.nf.CanvasUtils,
root.nf.ErrorHandler, root.nf.ErrorHandler,
root.nf.Common); root.nf.Common,
root.nf.Dialog);
} }
}(this, function ($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon) { }(this, function ($, nfClient, nfBirdseye, nfGraph, nfCanvasUtils, nfErrorHandler, nfCommon, nfDialog) {
'use strict'; 'use strict';
return function (serviceProvider) { return function (serviceProvider) {
@ -236,12 +239,22 @@
// hide the dialog // hide the dialog
groupComponent.modal.hide(); groupComponent.modal.hide();
// ensure the group name is specified
if (nfCommon.isBlank(groupName)) {
nfDialog.showOkDialog({
headerText: 'Create Process Group',
dialogContent: 'The group name is required.'
});
deferred.reject();
} else {
// create the group and resolve the deferred accordingly // create the group and resolve the deferred accordingly
createGroup(groupName, pt).done(function (response) { createGroup(groupName, pt).done(function (response) {
deferred.resolve(response.component); deferred.resolve(response.component);
}).fail(function () { }).fail(function () {
deferred.reject(); deferred.reject();
}); });
}
}; };
groupComponent.modal.update('setButtonModel', [{ groupComponent.modal.update('setButtonModel', [{

View File

@ -1265,6 +1265,18 @@
} }
}, },
/**
* Shows local changes.
*/
showLocalChanges: function (selection) {
if (selection.empty()) {
nfFlowVersion.showLocalChanges(nfCanvasUtils.getGroupId());
} else if (selection.size() === 1) {
var selectionData = selection.datum();
nfFlowVersion.showLocalChanges(selectionData.id)
}
},
/** /**
* Changes the flow version. * Changes the flow version.
*/ */

View File

@ -427,6 +427,123 @@
return nfCommon.isUndefinedOrNull(processGroupData.component.versionControlInformation); return nfCommon.isUndefinedOrNull(processGroupData.component.versionControlInformation);
}; };
/**
* Returns whether the process group support supports commit.
*
* @param selection
* @returns {boolean}
*/
var supportsCommitFlowVersion = function (selection) {
// ensure this selection supports flow versioning above
if (supportsFlowVersioning(selection) === false) {
return false;
}
var versionControlInformation;
if (selection.empty()) {
// check bread crumbs for version control information in the current group
var breadcrumbEntities = nfNgBridge.injector.get('breadcrumbsCtrl').getBreadcrumbs();
if (breadcrumbEntities.length > 0) {
var breadcrumbEntity = breadcrumbEntities[breadcrumbEntities.length - 1];
if (breadcrumbEntity.permissions.canRead) {
versionControlInformation = breadcrumbEntity.breadcrumb.versionControlInformation;
} else {
return false;
}
} else {
return false;
}
} else {
var processGroupData = selection.datum();
versionControlInformation = processGroupData.component.versionControlInformation;
}
if (nfCommon.isUndefinedOrNull(versionControlInformation)) {
return false;
}
// check the selection for version control information
return versionControlInformation.current === true && versionControlInformation.modified === true;
};
/**
* Returns whether the process group supports revert local changes.
*
* @param selection
* @returns {boolean}
*/
var hasLocalChanges = function (selection) {
// ensure this selection supports flow versioning above
if (supportsFlowVersioning(selection) === false) {
return false;
}
var versionControlInformation;
if (selection.empty()) {
// check bread crumbs for version control information in the current group
var breadcrumbEntities = nfNgBridge.injector.get('breadcrumbsCtrl').getBreadcrumbs();
if (breadcrumbEntities.length > 0) {
var breadcrumbEntity = breadcrumbEntities[breadcrumbEntities.length - 1];
if (breadcrumbEntity.permissions.canRead) {
versionControlInformation = breadcrumbEntity.breadcrumb.versionControlInformation;
} else {
return false;
}
} else {
return false;
}
} else {
var processGroupData = selection.datum();
versionControlInformation = processGroupData.component.versionControlInformation;
}
if (nfCommon.isUndefinedOrNull(versionControlInformation)) {
return false;
}
// check the selection for version control information
return versionControlInformation.modified === true;
};
/**
* Returns whether the process group supports changing the flow version.
*
* @param selection
* @returns {boolean}
*/
var supportsChangeFlowVersion = function (selection) {
// ensure this selection supports flow versioning above
if (supportsFlowVersioning(selection) === false) {
return false;
}
var versionControlInformation;
if (selection.empty()) {
// check bread crumbs for version control information in the current group
var breadcrumbEntities = nfNgBridge.injector.get('breadcrumbsCtrl').getBreadcrumbs();
if (breadcrumbEntities.length > 0) {
var breadcrumbEntity = breadcrumbEntities[breadcrumbEntities.length - 1];
if (breadcrumbEntity.permissions.canRead) {
versionControlInformation = breadcrumbEntity.breadcrumb.versionControlInformation;
} else {
return false;
}
} else {
return false;
}
} else {
var processGroupData = selection.datum();
versionControlInformation = processGroupData.component.versionControlInformation;
}
if (nfCommon.isUndefinedOrNull(versionControlInformation)) {
return false;
}
// check the selection for version control information
return versionControlInformation.modified === false;
};
/** /**
* Determines whether the current selection supports stopping flow versioning. * Determines whether the current selection supports stopping flow versioning.
* *
@ -640,9 +757,10 @@
{id: 'version-menu-item', groupMenuItem: {clazz: 'fa', text: 'Version'}, menuItems: [ {id: 'version-menu-item', groupMenuItem: {clazz: 'fa', text: 'Version'}, menuItems: [
{id: 'start-version-control-menu-item', condition: supportsStartFlowVersioning, menuItem: {clazz: 'fa fa-upload', text: 'Start version control', action: 'saveFlowVersion'}}, {id: 'start-version-control-menu-item', condition: supportsStartFlowVersioning, menuItem: {clazz: 'fa fa-upload', text: 'Start version control', action: 'saveFlowVersion'}},
{separator: true}, {separator: true},
{id: 'commit-menu-item', condition: supportsStopFlowVersioning, menuItem: {clazz: 'fa fa-upload', text: 'Commit local changes', action: 'saveFlowVersion'}}, {id: 'commit-menu-item', condition: supportsCommitFlowVersion, menuItem: {clazz: 'fa fa-upload', text: 'Commit local changes', action: 'saveFlowVersion'}},
{id: 'revert-menu-item', condition: supportsStopFlowVersioning, menuItem: {clazz: 'fa fa-undo', text: 'Revert local changes', action: 'revertLocalChanges'}}, {id: 'local-changes-menu-item', condition: hasLocalChanges, menuItem: {clazz: 'fa', text: 'Show local changes', action: 'showLocalChanges'}},
{id: 'change-version-menu-item', condition: supportsStopFlowVersioning, menuItem: {clazz: 'fa', text: 'Change version', action: 'changeFlowVersion'}}, {id: 'revert-menu-item', condition: hasLocalChanges, menuItem: {clazz: 'fa fa-undo', text: 'Revert local changes', action: 'revertLocalChanges'}},
{id: 'change-version-menu-item', condition: supportsChangeFlowVersion, menuItem: {clazz: 'fa', text: 'Change version', action: 'changeFlowVersion'}},
{separator: true}, {separator: true},
{id: 'stop-version-control-menu-item', condition: supportsStopFlowVersioning, menuItem: {clazz: 'fa', text: 'Stop version control', action: 'stopVersionControl'}} {id: 'stop-version-control-menu-item', condition: supportsStopFlowVersioning, menuItem: {clazz: 'fa', text: 'Stop version control', action: 'stopVersionControl'}}
]}, ]},

View File

@ -30,10 +30,11 @@
'nf.Client', 'nf.Client',
'nf.CanvasUtils', 'nf.CanvasUtils',
'nf.ProcessGroup', 'nf.ProcessGroup',
'nf.ProcessGroupConfiguration',
'nf.Graph', 'nf.Graph',
'nf.Birdseye'], 'nf.Birdseye'],
function ($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfGraph, nfBirdseye) { function ($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye) {
return (nf.FlowVersion = factory($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfGraph, nfBirdseye)); return (nf.FlowVersion = factory($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye));
}); });
} else if (typeof exports === 'object' && typeof module === 'object') { } else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.FlowVerison = module.exports = (nf.FlowVerison =
@ -45,6 +46,7 @@
require('nf.Client'), require('nf.Client'),
require('nf.CanvasUtils'), require('nf.CanvasUtils'),
require('nf.ProcessGroup'), require('nf.ProcessGroup'),
require('nf.ProcessGroupConfiguration'),
require('nf.Graph'), require('nf.Graph'),
require('nf.Birdseye'))); require('nf.Birdseye')));
} else { } else {
@ -56,10 +58,11 @@
root.nf.Client, root.nf.Client,
root.nf.CanvasUtils, root.nf.CanvasUtils,
root.nf.ProcessGroup, root.nf.ProcessGroup,
root.nf.ProcessGroupConfiguration,
root.nf.Graph, root.nf.Graph,
root.nf.Birdseye); root.nf.Birdseye);
} }
}(this, function ($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfGraph, nfBirdseye) { }(this, function ($, nfNgBridge, nfErrorHandler, nfDialog, nfCommon, nfClient, nfCanvasUtils, nfProcessGroup, nfProcessGroupConfiguration, nfGraph, nfBirdseye) {
'use strict'; 'use strict';
var serverTimeOffset = null; var serverTimeOffset = null;
@ -96,6 +99,55 @@
$('#save-flow-version-process-group-id').removeData('versionControlInformation').removeData('revision').text(''); $('#save-flow-version-process-group-id').removeData('versionControlInformation').removeData('revision').text('');
}; };
/**
* Reset the revert local changes dialog.
*/
var resetRevertLocalChangesDialog = function () {
$('#revert-local-changes-process-group-id').text('');
clearLocalChangesGrid($('#revert-local-changes-table'), $('#revert-local-changes-filter'), $('#displayed-revert-local-changes-entries'), $('#total-revert-local-changes-entries'));
};
/**
* Reset the show local changes dialog.
*/
var resetShowLocalChangesDialog = function () {
clearLocalChangesGrid($('#show-local-changes-table'), $('#show-local-changes-filter'), $('#displayed-show-local-changes-entries'), $('#total-show-local-changes-entries'));
};
/**
* Clears the local changes grid.
*/
var clearLocalChangesGrid = function (localChangesTable, filterInput, displayedLabel, totalLabel) {
var localChangesGrid = localChangesTable.data('gridInstance');
if (nfCommon.isDefinedAndNotNull(localChangesGrid)) {
localChangesGrid.setSelectedRows([]);
localChangesGrid.resetActiveCell();
var localChangesData = localChangesGrid.getData();
localChangesData.setItems([]);
}
filterInput.val('');
displayedLabel.text('0');
totalLabel.text('0');
}
/**
* Clears the version grid
*/
var clearFlowVersionsGrid = function () {
var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance');
if (nfCommon.isDefinedAndNotNull(importFlowVersionGrid)) {
importFlowVersionGrid.setSelectedRows([]);
importFlowVersionGrid.resetActiveCell();
var importFlowVersionData = importFlowVersionGrid.getData();
importFlowVersionData.setItems([]);
}
};
/** /**
* Reset the import flow version dialog. * Reset the import flow version dialog.
*/ */
@ -110,14 +162,7 @@
$('#import-flow-version-bucket').text('').hide(); $('#import-flow-version-bucket').text('').hide();
$('#import-flow-version-name').text('').hide(); $('#import-flow-version-name').text('').hide();
var importFlowVersionGrid = $('#import-flow-version-table').data('gridInstance'); clearFlowVersionsGrid();
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-process-group-id').removeData('versionControlInformation').removeData('revision').text('');
@ -131,9 +176,10 @@
* @param dialog * @param dialog
* @param registryCombo * @param registryCombo
* @param bucketCombo * @param bucketCombo
* @param flowCombo
* @returns {deferred} * @returns {deferred}
*/ */
var loadRegistries = function (dialog, registryCombo, bucketCombo, selectBucket) { var loadRegistries = function (dialog, registryCombo, bucketCombo, flowCombo, selectBucket) {
return $.ajax({ return $.ajax({
type: 'GET', type: 'GET',
url: '../nifi-api/flow/registries', url: '../nifi-api/flow/registries',
@ -167,7 +213,7 @@
registryCombo.combo({ registryCombo.combo({
options: registries, options: registries,
select: function (selectedOption) { select: function (selectedOption) {
selectRegistry(dialog, selectedOption, bucketCombo, selectBucket) selectRegistry(dialog, selectedOption, bucketCombo, flowCombo, selectBucket)
} }
}); });
}).fail(nfErrorHandler.handleAjaxError); }).fail(nfErrorHandler.handleAjaxError);
@ -178,6 +224,7 @@
* *
* @param registryIdentifier * @param registryIdentifier
* @param bucketCombo * @param bucketCombo
* @param selectBucket
* @returns {*} * @returns {*}
*/ */
var loadBuckets = function (registryIdentifier, bucketCombo, selectBucket) { var loadBuckets = function (registryIdentifier, bucketCombo, selectBucket) {
@ -224,9 +271,10 @@
* @param dialog * @param dialog
* @param selectedOption * @param selectedOption
* @param bucketCombo * @param bucketCombo
* @param flowCombo
* @param selectBucket * @param selectBucket
*/ */
var selectRegistry = function (dialog, selectedOption, bucketCombo, selectBucket) { var selectRegistry = function (dialog, selectedOption, bucketCombo, flowCombo, selectBucket) {
var showNoBucketsAvailable = function () { var showNoBucketsAvailable = function () {
bucketCombo.combo('destroy').combo({ bucketCombo.combo('destroy').combo({
options: [{ options: [{
@ -243,6 +291,28 @@
if (selectedOption.disabled === true) { if (selectedOption.disabled === true) {
showNoBucketsAvailable(); showNoBucketsAvailable();
} else { } else {
bucketCombo.combo('destroy').combo({
options: [{
text: 'Loading buckets...',
value: null,
optionClass: 'unset',
disabled: true
}]
});
if (nfCommon.isDefinedAndNotNull(flowCombo)) {
flowCombo.combo('destroy').combo({
options: [{
text: 'Loading flows...',
value: null,
optionClass: 'unset',
disabled: true
}]
});
clearFlowVersionsGrid();
}
loadBuckets(selectedOption.value, bucketCombo, selectBucket).fail(function () { loadBuckets(selectedOption.value, bucketCombo, selectBucket).fail(function () {
showNoBucketsAvailable(); showNoBucketsAvailable();
}); });
@ -344,7 +414,7 @@
return nfCommon.formatDateTime(date); return nfCommon.formatDateTime(date);
}; };
// define the column model for the controller services table // define the column model for flow versions
var importFlowVersionColumns = [ var importFlowVersionColumns = [
{ {
id: 'version', id: 'version',
@ -426,6 +496,185 @@
importFlowVersionTable.data('gridInstance', importFlowVersionGrid); importFlowVersionTable.data('gridInstance', importFlowVersionGrid);
}; };
/**
* Initializes the specified local changes table.
*
* @param localChangesTable
* @param filterInput
* @param displayedLabel
* @param totalLabel
*/
var initLocalChangesTable = function (localChangesTable, filterInput, displayedLabel, totalLabel) {
var getFilterText = function () {
return filterInput.val();
};
var applyFilter = function () {
// get the dataview
var localChangesGrid = localChangesTable.data('gridInstance');
// ensure the grid has been initialized
if (nfCommon.isDefinedAndNotNull(localChangesGrid)) {
var localChangesData = localChangesGrid.getData();
// update the search criteria
localChangesData.setFilterArgs({
searchString: getFilterText()
});
localChangesData.refresh();
}
};
var filter = function (item, args) {
if (args.searchString === '') {
return true;
}
try {
// perform the row filtering
var filterExp = new RegExp(args.searchString, 'i');
} catch (e) {
// invalid regex
return false;
}
// determine if the item matches the filter
var matchesId = item['componentId'].search(filterExp) >= 0;
var matchesComponent = item['componentName'].search(filterExp) >= 0;
var matchesDifferenceType = item['differenceType'].search(filterExp) >= 0;
var matchesDifference = item['difference'].search(filterExp) >= 0;
return matchesId || matchesComponent || matchesDifferenceType || matchesDifference;
};
// initialize the component state filter
filterInput.on('keyup', function () {
applyFilter();
});
var valueFormatter = function (row, cell, value, columnDef, dataContext) {
return nfCommon.escapeHtml(value);
};
var actionsFormatter = function (row, cell, value, columnDef, dataContext) {
var markup = '';
if (dataContext.differenceType !== 'Component Removed' && nfCommon.isDefinedAndNotNull(dataContext.processGroupId)) {
markup += '<div class="pointer go-to-component fa fa-long-arrow-right" title="Go To" style="margin-top: 2px" ></div>';
}
return markup;
};
// define the column model for local changes
var localChangesColumns = [
{
id: 'component',
name: 'Component Name',
field: 'componentName',
formatter: valueFormatter,
sortable: true,
resizable: true
},
{
id: 'differenceType',
name: 'Type',
field: 'differenceType',
formatter: valueFormatter,
sortable: true,
resizable: true
},
{
id: 'difference',
name: 'Difference',
field: 'difference',
formatter: valueFormatter,
sortable: true,
resizable: true,
minWidth: 300
},
{
id: 'actions',
name: '&nbsp;',
formatter: actionsFormatter,
sortable: false,
resizable: false,
width: 25
}
];
// initialize the dataview
var localChangesData = new Slick.Data.DataView({
inlineFilters: false
});
localChangesData.setFilterArgs({
searchString: '',
property: 'component'
});
localChangesData.setFilter(filter);
// initialize the sort
sort({
columnId: 'version',
sortAsc: false
}, localChangesData);
// initialize the grid
var localChangesGrid = new Slick.Grid(localChangesTable, localChangesData, localChangesColumns, gridOptions);
localChangesGrid.setSelectionModel(new Slick.RowSelectionModel());
localChangesGrid.registerPlugin(new Slick.AutoTooltips());
localChangesGrid.setSortColumn('version', false);
localChangesGrid.onSort.subscribe(function (e, args) {
sort({
columnId: args.sortCol.id,
sortAsc: args.sortAsc
}, localChangesData);
});
// configure a click listener
localChangesGrid.onClick.subscribe(function (e, args) {
var target = $(e.target);
// get the node at this row
var componentDifference = localChangesData.getItem(args.row);
// determine the desired action
if (localChangesGrid.getColumns()[args.cell].id === 'actions') {
if (target.hasClass('go-to-component')) {
if (componentDifference.componentType === 'Controller Service') {
nfProcessGroupConfiguration.showConfiguration(componentDifference.processGroupId).done(function () {
nfProcessGroupConfiguration.selectControllerService(componentDifference.componentId);
});
} else {
nfCanvasUtils.showComponent(componentDifference.processGroupId, componentDifference.componentId);
}
}
}
});
// wire up the dataview to the grid
localChangesData.onRowCountChanged.subscribe(function (e, args) {
localChangesGrid.updateRowCount();
localChangesGrid.render();
// update the total number of displayed items
displayedLabel.text(nfCommon.formatInteger(args.current));
});
localChangesData.onRowsChanged.subscribe(function (e, args) {
localChangesGrid.invalidateRows(args.rows);
localChangesGrid.render();
});
localChangesData.syncGridSelection(localChangesGrid, true);
// hold onto an instance of the grid
localChangesTable.data('gridInstance', localChangesGrid);
// initialize the number of display items
displayedLabel.text('0');
totalLabel.text('0');
};
/** /**
* Shows the import flow version dialog. * Shows the import flow version dialog.
*/ */
@ -450,7 +699,7 @@
disabled: true disabled: true
}] }]
}).show(); }).show();
$('#import-flow-version-name-combo').combo('destroy').combo({ var flowCombo = $('#import-flow-version-name-combo').combo('destroy').combo({
options: [{ options: [{
text: 'Loading flows...', text: 'Loading flows...',
value: null, value: null,
@ -459,7 +708,7 @@
}] }]
}).show(); }).show();
loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, selectBucketImportVersion).done(function () { loadRegistries($('#import-flow-version-dialog'), registryCombo, bucketCombo, flowCombo, selectBucketImportVersion).done(function () {
// show the import dialog // show the import dialog
$('#import-flow-version-dialog').modal('setHeaderText', 'Import Version').modal('setButtonModel', [{ $('#import-flow-version-dialog').modal('setHeaderText', 'Import Version').modal('setButtonModel', [{
buttonText: 'Import', buttonText: 'Import',
@ -619,6 +868,19 @@
* @param selectedBucket * @param selectedBucket
*/ */
var selectBucketImportVersion = function (selectedBucket) { var selectBucketImportVersion = function (selectedBucket) {
// mark the flows as loading
$('#import-flow-version-name-combo').combo('destroy').combo({
options: [{
text: 'Loading flows...',
value: null,
optionClass: 'unset',
disabled: true
}]
});
// clear the flow versions grid
clearFlowVersionsGrid();
var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption'); var selectedRegistry = $('#import-flow-version-registry-combo').combo('getSelectedOption');
// load the flows for the currently selected registry and bucket // load the flows for the currently selected registry and bucket
@ -646,7 +908,6 @@
} }
}), }),
'component': { 'component': {
'name': selectedFlow.text, // TODO - name from versioned PG?
'position': { 'position': {
'x': pt.x, 'x': pt.x,
'y': pt.y 'y': pt.y
@ -966,193 +1227,70 @@
progressBar.append(label); progressBar.append(label);
}; };
return {
init: function (timeOffset) {
serverTimeOffset = timeOffset;
// initialize the flow version dialog
$('#save-flow-version-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Save Flow Version',
buttons: [{
buttonText: 'Save',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
disabled: function () {
if ($('#save-flow-version-registry-combo').is(':visible')) {
var selectedRegistry = $('#save-flow-version-registry-combo').combo('getSelectedOption');
var selectedBucket = $('#save-flow-version-bucket-combo').combo('getSelectedOption');
if (nfCommon.isDefinedAndNotNull(selectedRegistry) && nfCommon.isDefinedAndNotNull(selectedBucket)) {
return selectedRegistry.disabled === true || selectedBucket.disabled === true;
} else {
return true;
}
} else {
return false;
}
},
handler: {
click: function () {
var processGroupId = $('#save-flow-version-process-group-id').text();
saveFlowVersion().done(function (response) {
updateVersionControlInformation(processGroupId, response.versionControlInformation);
// close the dialog
$('#save-flow-version-dialog').modal('hide');
});
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}],
handler: {
close: function () {
resetSaveFlowVersionDialog();
}
}
});
// initialize the import flow version dialog
$('#import-flow-version-dialog').modal({
scrollableContentStyle: 'scrollable',
handler: {
close: function () {
resetImportFlowVersionDialog();
}
}
});
// 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();
});
// initialize the import flow version table
initImportFlowVersionTable();
},
/** /**
* Shows the flow version dialog. * Shows local changes for the specified process group.
* *
* @param processGroupId * @param processGroupId
* @param localChangesTable
* @param totalLabel
*/ */
showFlowVersionDialog: function (processGroupId) { var loadLocalChanges = function (processGroupId, localChangesTable, totalLabel) {
var focusName = true; var localChangesGrid = localChangesTable.data('gridInstance');
var localChangesData = localChangesGrid.getData();
return $.Deferred(function (deferred) { // begin the update
getVersionControlInformation(processGroupId).done(function (groupVersionControlInformation) { localChangesData.beginUpdate();
// record the revision
$('#save-flow-version-process-group-id').data('revision', groupVersionControlInformation.processGroupRevision).text(processGroupId);
if (nfCommon.isDefinedAndNotNull(groupVersionControlInformation.versionControlInformation)) { // remove the current versions
var versionControlInformation = groupVersionControlInformation.versionControlInformation; localChangesGrid.setSelectedRows([]);
localChangesGrid.resetActiveCell();
localChangesData.setItems([]);
// update the registry and bucket visibility return $.ajax({
$('#save-flow-version-registry').text(versionControlInformation.registryName).show(); type: 'GET',
$('#save-flow-version-bucket').text(versionControlInformation.bucketName).show(); url: '../nifi-api/process-groups/' + encodeURIComponent(processGroupId) + '/local-modifications',
$('#save-flow-version-label').text(versionControlInformation.version + 1); dataType: 'json'
}).done(function (response) {
if (nfCommon.isDefinedAndNotNull(response.componentDifferences) && response.componentDifferences.length > 0) {
var totalDifferences = 0;
$.each(response.componentDifferences, function (_, componentDifference) {
$.each(componentDifference.differences, function (_, difference) {
localChangesData.addItem({
id: totalDifferences++,
componentId: componentDifference.componentId,
componentName: componentDifference.componentName,
componentType: componentDifference.componentType,
processGroupId: componentDifference.processGroupId,
differenceType: difference.differenceType,
difference: difference.difference
});
});
});
$('#save-flow-version-name').text(versionControlInformation.flowName).show(); // end the update
$('#save-flow-version-description').text(versionControlInformation.flowDescription).show(); localChangesData.endUpdate();
// record the versionControlInformation // resort
$('#save-flow-version-process-group-id').data('versionControlInformation', versionControlInformation); localChangesData.reSort();
localChangesGrid.invalidate();
// reposition the version label // update the total displayed
$('#save-flow-version-label').css('margin-top', '-15px'); totalLabel.text(nfCommon.formatInteger(totalDifferences));
focusName = false;
deferred.resolve();
} else { } else {
// update the registry and bucket visibility nfDialog.showOkDialog({
var registryCombo = $('#save-flow-version-registry-combo').combo('destroy').combo({ headerText: 'Local Changes',
options: [{ dialogContent: 'This Process Group does not have any local changes.'
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();
// 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();
}); });
} }
}).fail(nfErrorHandler.handleAjaxError); }).fail(nfErrorHandler.handleAjaxError);
}).done(function () { };
$('#save-flow-version-dialog').modal('show');
if (focusName) {
$('#save-flow-version-name-field').focus();
} else {
$('#save-flow-version-change-comments').focus();
}
}).fail(function () {
$('#save-flow-version-dialog').modal('refreshButtons');
}).promise();
},
/** /**
* Reverts local changes for the specified Process Group. * Revert local changes for the specified process group.
* *
* @param processGroupId * @param processGroupId
*/ */
revertLocalChanges: function (processGroupId) { var revertLocalChanges = function (processGroupId) {
// TODO update to show user the ramifications of reverting for confirmation
// prompt the user before reverting
nfDialog.showYesNoDialog({
headerText: 'Revert Changes',
dialogContent: 'Are you sure you want to revert changes? All flow configuration changes will be reverted to the last version.',
noText: 'Cancel',
yesText: 'Revert',
yesHandler: function () {
getVersionControlInformation(processGroupId).done(function (response) { getVersionControlInformation(processGroupId).done(function (response) {
if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) { if (nfCommon.isDefinedAndNotNull(response.versionControlInformation)) {
var revertTimer = null; var revertTimer = null;
@ -1321,7 +1459,263 @@
}); });
} }
}).fail(nfErrorHandler.handleAjaxError); }).fail(nfErrorHandler.handleAjaxError);
};
return {
init: function (timeOffset) {
serverTimeOffset = timeOffset;
// initialize the flow version dialog
$('#save-flow-version-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Save Flow Version',
buttons: [{
buttonText: 'Save',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
disabled: function () {
if ($('#save-flow-version-registry-combo').is(':visible')) {
var selectedRegistry = $('#save-flow-version-registry-combo').combo('getSelectedOption');
var selectedBucket = $('#save-flow-version-bucket-combo').combo('getSelectedOption');
if (nfCommon.isDefinedAndNotNull(selectedRegistry) && nfCommon.isDefinedAndNotNull(selectedBucket)) {
return selectedRegistry.disabled === true || selectedBucket.disabled === true;
} else {
return true;
} }
} else {
return false;
}
},
handler: {
click: function () {
var processGroupId = $('#save-flow-version-process-group-id').text();
saveFlowVersion().done(function (response) {
updateVersionControlInformation(processGroupId, response.versionControlInformation);
});
$(this).modal('hide');
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}],
handler: {
close: function () {
resetSaveFlowVersionDialog();
}
}
});
// initialize the import flow version dialog
$('#import-flow-version-dialog').modal({
scrollableContentStyle: 'scrollable',
handler: {
close: function () {
resetImportFlowVersionDialog();
}
}
});
// 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', []);
}
}
});
// init the revert local changes dialog
$('#revert-local-changes-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Revert Local Changes',
buttons: [{
buttonText: 'Revert',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
var processGroupId = $('#revert-local-changes-process-group-id').text();
revertLocalChanges(processGroupId);
$(this).modal('hide');
}
}
}, {
buttonText: 'Cancel',
color: {
base: '#E3E8EB',
hover: '#C7D2D7',
text: '#004849'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}],
handler: {
close: function () {
resetRevertLocalChangesDialog();
}
}
});
// init the show local changes dialog
$('#show-local-changes-dialog').modal({
scrollableContentStyle: 'scrollable',
headerText: 'Local Changes',
buttons: [{
buttonText: 'Close',
color: {
base: '#728E9B',
hover: '#004849',
text: '#ffffff'
},
handler: {
click: function () {
$(this).modal('hide');
}
}
}],
handler: {
close: function () {
resetShowLocalChangesDialog();
}
}
});
// handle the click for the process group import
$('#import-process-group-link').on('click', function() {
showImportFlowVersionDialog();
});
// initialize the import flow version table
initImportFlowVersionTable();
initLocalChangesTable($('#revert-local-changes-table'), $('#revert-local-changes-filter'), $('#displayed-revert-local-changes-entries'), $('#total-revert-local-changes-entries'));
initLocalChangesTable($('#show-local-changes-table'), $('#show-local-changes-filter'), $('#displayed-show-local-changes-entries'), $('#total-show-local-changes-entries'));
},
/**
* Shows the flow version dialog.
*
* @param processGroupId
*/
showFlowVersionDialog: function (processGroupId) {
var focusName = true;
return $.Deferred(function (deferred) {
getVersionControlInformation(processGroupId).done(function (groupVersionControlInformation) {
// record the revision
$('#save-flow-version-process-group-id').data('revision', groupVersionControlInformation.processGroupRevision).text(processGroupId);
if (nfCommon.isDefinedAndNotNull(groupVersionControlInformation.versionControlInformation)) {
var versionControlInformation = groupVersionControlInformation.versionControlInformation;
// update the registry and bucket visibility
$('#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(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
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();
// reposition the version label
$('#save-flow-version-label').css('margin-top', '0');
loadRegistries($('#save-flow-version-dialog'), registryCombo, bucketCombo, null, selectBucketSaveFlowVersion).done(function () {
deferred.resolve();
}).fail(function () {
deferred.reject();
});
}
}).fail(nfErrorHandler.handleAjaxError);
}).done(function () {
$('#save-flow-version-dialog').modal('show');
if (focusName) {
$('#save-flow-version-name-field').focus();
} else {
$('#save-flow-version-change-comments').focus();
}
}).fail(function () {
$('#save-flow-version-dialog').modal('refreshButtons');
}).promise();
},
/**
* Reverts local changes for the specified Process Group.
*
* @param processGroupId
*/
revertLocalChanges: function (processGroupId) {
loadLocalChanges(processGroupId, $('#revert-local-changes-table'), $('#total-revert-local-changes-entries')).done(function () {
$('#revert-local-changes-process-group-id').text(processGroupId);
$('#revert-local-changes-dialog').modal('show');
});
},
/**
* Shows local changes for the specified process group.
*
* @param processGroupId
*/
showLocalChanges: function (processGroupId) {
loadLocalChanges(processGroupId, $('#show-local-changes-table'), $('#total-show-local-changes-entries')).done(function () {
$('#show-local-changes-dialog').modal('show');
}); });
}, },
@ -1407,8 +1801,8 @@
stopVersionControl: function (processGroupId) { stopVersionControl: function (processGroupId) {
// prompt the user before disconnecting // prompt the user before disconnecting
nfDialog.showYesNoDialog({ nfDialog.showYesNoDialog({
headerText: 'Disconnect', headerText: 'Stop Version Control',
dialogContent: 'Are you sure you want to disconnect?', dialogContent: 'Are you sure you want to stop version control?',
noText: 'Cancel', noText: 'Cancel',
yesText: 'Disconnect', yesText: 'Disconnect',
yesHandler: function () { yesHandler: function () {
@ -1434,7 +1828,7 @@
nfDialog.showOkDialog({ nfDialog.showOkDialog({
headerText: 'Disconnect', headerText: 'Disconnect',
dialogContent: 'This Process Group has been disconnected.' dialogContent: 'This Process Group is no longer under version control.'
}); });
}).fail(nfErrorHandler.handleAjaxError); }).fail(nfErrorHandler.handleAjaxError);
} else { } else {