mirror of https://github.com/apache/nifi.git
NIFI-259:
- Initial implementation of viewing and clearing state for a processor.
This commit is contained in:
parent
d39067ede6
commit
d05314c54b
|
@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlType;
|
|||
public class ComponentStateDTO {
|
||||
|
||||
private String componentId;
|
||||
private String stateDescription;
|
||||
private StateMapDTO clusterState;
|
||||
private StateMapDTO localState;
|
||||
|
||||
|
@ -44,6 +45,20 @@ public class ComponentStateDTO {
|
|||
this.componentId = componentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Description of the state this component persists.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Description of the state this component persists."
|
||||
)
|
||||
public String getStateDescription() {
|
||||
return stateDescription;
|
||||
}
|
||||
|
||||
public void setStateDescription(String stateDescription) {
|
||||
this.stateDescription = stateDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The cluster state for this component, or null if this NiFi is a standalone instance
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,7 @@ public class ControllerServiceDTO extends NiFiComponentDTO {
|
|||
private String comments;
|
||||
private String availability;
|
||||
private String state;
|
||||
private Boolean persistsState;
|
||||
|
||||
private Map<String, String> properties;
|
||||
private Map<String, PropertyDescriptorDTO> descriptors;
|
||||
|
@ -101,6 +102,20 @@ public class ControllerServiceDTO extends NiFiComponentDTO {
|
|||
this.availability = availability;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this controller service persists state
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Whether the controller service persists state."
|
||||
)
|
||||
public Boolean getPersistsState() {
|
||||
return persistsState;
|
||||
}
|
||||
|
||||
public void setPersistsState(Boolean persistsState) {
|
||||
this.persistsState = persistsState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The state of this controller service. Possible values are ENABLED, ENABLING, DISABLED, DISABLING
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@ public class ProcessorDTO extends NiFiComponentDTO {
|
|||
private Boolean supportsParallelProcessing;
|
||||
private Boolean supportsEventDriven;
|
||||
private Boolean supportsBatching;
|
||||
private Boolean persistsState;
|
||||
private String inputRequirement;
|
||||
|
||||
private ProcessorConfigDTO config;
|
||||
|
@ -122,6 +123,20 @@ public class ProcessorDTO extends NiFiComponentDTO {
|
|||
this.supportsParallelProcessing = supportsParallelProcessing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this processor persists state
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Whether the processor persists state."
|
||||
)
|
||||
public Boolean getPersistsState() {
|
||||
return persistsState;
|
||||
}
|
||||
|
||||
public void setPersistsState(Boolean persistsState) {
|
||||
this.persistsState = persistsState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the input requirement of this processor
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,7 @@ public class ReportingTaskDTO extends NiFiComponentDTO {
|
|||
private String state;
|
||||
private String availability;
|
||||
private String comments;
|
||||
private Boolean persistsState;
|
||||
|
||||
private String schedulingPeriod;
|
||||
private String schedulingStrategy;
|
||||
|
@ -105,6 +106,20 @@ public class ReportingTaskDTO extends NiFiComponentDTO {
|
|||
this.schedulingPeriod = schedulingPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this reporting task persists state
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "Whether the reporting task persists state."
|
||||
)
|
||||
public Boolean getPersistsState() {
|
||||
return persistsState;
|
||||
}
|
||||
|
||||
public void setPersistsState(Boolean persistsState) {
|
||||
this.persistsState = persistsState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current scheduling state of the reporting task
|
||||
*/
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.web;
|
|||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.lf5.util.Resource;
|
||||
import org.apache.nifi.action.Action;
|
||||
import org.apache.nifi.action.Component;
|
||||
import org.apache.nifi.action.FlowChangeAction;
|
||||
|
@ -2168,23 +2169,32 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
|
||||
@Override
|
||||
public ComponentStateDTO getProcessorState(String groupId, String processorId) {
|
||||
final StateMap clusterState = processorDAO.getState(groupId, processorId, Scope.CLUSTER);
|
||||
final StateMap clusterState = isClustered() ? processorDAO.getState(groupId, processorId, Scope.CLUSTER) : null;
|
||||
final StateMap localState = processorDAO.getState(groupId, processorId, Scope.LOCAL);
|
||||
return dtoFactory.createComponentStateDTO(processorId, localState, clusterState);
|
||||
|
||||
// processor will be non null as it was already found when getting the state
|
||||
final ProcessorNode processor = processorDAO.getProcessor(groupId, processorId);
|
||||
return dtoFactory.createComponentStateDTO(processorId, processor.getProcessor().getClass(), localState, clusterState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentStateDTO getControllerServiceState(String controllerServiceId) {
|
||||
final StateMap clusterState = controllerServiceDAO.getState(controllerServiceId, Scope.CLUSTER);
|
||||
final StateMap clusterState = isClustered() ? controllerServiceDAO.getState(controllerServiceId, Scope.CLUSTER) : null;
|
||||
final StateMap localState = controllerServiceDAO.getState(controllerServiceId, Scope.LOCAL);
|
||||
return dtoFactory.createComponentStateDTO(controllerServiceId, localState, clusterState);
|
||||
|
||||
// controller service will be non null as it was already found when getting the state
|
||||
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId);
|
||||
return dtoFactory.createComponentStateDTO(controllerServiceId, controllerService.getControllerServiceImplementation().getClass(), localState, clusterState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentStateDTO getReportingTaskState(String reportingTaskId) {
|
||||
final StateMap clusterState = reportingTaskDAO.getState(reportingTaskId, Scope.CLUSTER);
|
||||
final StateMap clusterState = isClustered() ? reportingTaskDAO.getState(reportingTaskId, Scope.CLUSTER) : null;
|
||||
final StateMap localState = reportingTaskDAO.getState(reportingTaskId, Scope.LOCAL);
|
||||
return dtoFactory.createComponentStateDTO(reportingTaskId, localState, clusterState);
|
||||
|
||||
// reporting task will be non null as it was already found when getting the state
|
||||
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskId);
|
||||
return dtoFactory.createComponentStateDTO(reportingTaskId, reportingTask.getReportingTask().getClass(), localState, clusterState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.apache.nifi.action.details.FlowChangeMoveDetails;
|
|||
import org.apache.nifi.action.details.FlowChangePurgeDetails;
|
||||
import org.apache.nifi.action.details.MoveDetails;
|
||||
import org.apache.nifi.action.details.PurgeDetails;
|
||||
import org.apache.nifi.annotation.behavior.Stateful;
|
||||
import org.apache.nifi.annotation.documentation.CapabilityDescription;
|
||||
import org.apache.nifi.annotation.documentation.Tags;
|
||||
import org.apache.nifi.authorization.Authority;
|
||||
|
@ -279,14 +280,30 @@ public final class DtoFactory {
|
|||
* @param clusterState cluster state
|
||||
* @return dto
|
||||
*/
|
||||
public ComponentStateDTO createComponentStateDTO(final String componentId, final StateMap localState, final StateMap clusterState) {
|
||||
public ComponentStateDTO createComponentStateDTO(final String componentId, final Class<?> componentClass, final StateMap localState, final StateMap clusterState) {
|
||||
final ComponentStateDTO dto = new ComponentStateDTO();
|
||||
dto.setComponentId(componentId);
|
||||
dto.setStateDescription(getStateDescription(componentClass));
|
||||
dto.setLocalState(createStateMapDTO(Scope.LOCAL, localState));
|
||||
dto.setClusterState(createStateMapDTO(Scope.CLUSTER, clusterState));
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the description of the state this component persists.
|
||||
*
|
||||
* @param componentClass the component class
|
||||
* @return state description
|
||||
*/
|
||||
private String getStateDescription(final Class<?> componentClass) {
|
||||
final Stateful capabilityDesc = componentClass.getAnnotation(Stateful.class);
|
||||
if (capabilityDesc != null) {
|
||||
return capabilityDesc.description();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a StateMapDTO for the given scope and state map.
|
||||
*
|
||||
|
@ -295,6 +312,10 @@ public final class DtoFactory {
|
|||
* @return dto
|
||||
*/
|
||||
public StateMapDTO createStateMapDTO(final Scope scope, final StateMap stateMap) {
|
||||
if (stateMap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StateMapDTO dto = new StateMapDTO();
|
||||
dto.setScope(scope.toString());
|
||||
|
||||
|
@ -1066,6 +1087,7 @@ public final class DtoFactory {
|
|||
dto.setActiveThreadCount(reportingTaskNode.getActiveThreadCount());
|
||||
dto.setAnnotationData(reportingTaskNode.getAnnotationData());
|
||||
dto.setComments(reportingTaskNode.getComments());
|
||||
dto.setPersistsState(reportingTaskNode.getReportingTask().getClass().isAnnotationPresent(Stateful.class));
|
||||
|
||||
final Map<String, String> defaultSchedulingPeriod = new HashMap<>();
|
||||
defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod());
|
||||
|
@ -1133,6 +1155,7 @@ public final class DtoFactory {
|
|||
dto.setState(controllerServiceNode.getState().name());
|
||||
dto.setAnnotationData(controllerServiceNode.getAnnotationData());
|
||||
dto.setComments(controllerServiceNode.getComments());
|
||||
dto.setPersistsState(controllerServiceNode.getControllerServiceImplementation().getClass().isAnnotationPresent(Stateful.class));
|
||||
|
||||
// sort a copy of the properties
|
||||
final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
|
||||
|
@ -1610,6 +1633,7 @@ public final class DtoFactory {
|
|||
dto.setStyle(node.getStyle());
|
||||
dto.setParentGroupId(node.getProcessGroup().getIdentifier());
|
||||
dto.setInputRequirement(node.getInputRequirement().name());
|
||||
dto.setPersistsState(node.getProcessor().getClass().isAnnotationPresent(Stateful.class));
|
||||
|
||||
dto.setType(node.getProcessor().getClass().getCanonicalName());
|
||||
dto.setName(node.getName());
|
||||
|
|
|
@ -281,6 +281,7 @@
|
|||
<include>${staging.dir}/js/nf/canvas/nf-canvas-toolbox.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-custom-ui.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-queue-listing.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-component-state.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-controller-service.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-reporting-task.js</include>
|
||||
<include>${staging.dir}/js/nf/canvas/nf-processor-configuration.js</include>
|
||||
|
|
|
@ -22,6 +22,7 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-namespace.js?
|
|||
<script type="text/javascript" src="js/nf/nf-storage.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-snippet.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-queue-listing.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-component-state.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-canvas-toolbox.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-custom-ui.js?${project.version}"></script>\n\
|
||||
<script type="text/javascript" src="js/nf/canvas/nf-controller-service.js?${project.version}"></script>\n\
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
<jsp:include page="/WEB-INF/partials/canvas/flowfile-details-dialog.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/canvas/component-state-dialog.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/connection-details.jsp"/>
|
||||
<div id="faded-background"></div>
|
||||
<div id="glass-pane"></div>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<%--
|
||||
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="component-state-dialog">
|
||||
<div class="dialog-content">
|
||||
<div class="setting">
|
||||
<div class="setting-name">Name</div>
|
||||
<div class="setting-field">
|
||||
<span id="component-state-name"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<div class="setting-name">Description</div>
|
||||
<div class="setting-field">
|
||||
<span id="component-state-description"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="component-state-filter-controls">
|
||||
<div id="component-state-filter-container">
|
||||
<input type="text" id="component-state-filter"/>
|
||||
</div>
|
||||
<div id="component-state-filter-status">
|
||||
Displaying <span id="displayed-component-state-entries"></span> of <span id="total-component-state-entries"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="component-state-table"></div>
|
||||
<div id="clear-link-container">
|
||||
<span id="clear-link" class="link">Clear state</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -22,6 +22,7 @@
|
|||
@import url(queue-listing.css);
|
||||
@import url(remote-process-group-configuration.css);
|
||||
@import url(controller-service.css);
|
||||
@import url(component-state.css);
|
||||
@import url(reporting-task.css);
|
||||
@import url(port-configuration.css);
|
||||
@import url(port-details.css);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Component state
|
||||
*/
|
||||
|
||||
#component-state-dialog {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
width: 600px;
|
||||
height: 500px;
|
||||
font-size: 10px;
|
||||
z-index: 1301;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#component-state-description {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
/*
|
||||
Component state filter
|
||||
*/
|
||||
|
||||
#component-state-filter-controls {
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
margin-right: 2px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
#component-state-filter-status {
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
color: #9f6000;
|
||||
clear: left;
|
||||
line-height: normal;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#component-state-filter {
|
||||
padding: 3px 0px 1px 3px;
|
||||
font-size: 12px;
|
||||
height: 18px;
|
||||
line-height: 20px;
|
||||
width: 173px;
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/*
|
||||
Component state table
|
||||
*/
|
||||
|
||||
#component-state-table {
|
||||
width: 578px;
|
||||
height: 235px;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
/*
|
||||
Clear
|
||||
*/
|
||||
|
||||
#clear-link-container {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
#clear-link.disabled {
|
||||
color: #bbb;
|
||||
font-style: italic;
|
||||
text-decoration: none !important;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -1063,6 +1063,23 @@ nf.Actions = (function () {
|
|||
nf.QueueListing.listQueue(connection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Views the state for the specified processor.
|
||||
*
|
||||
* @param {selection} selection
|
||||
*/
|
||||
viewState: function (selection) {
|
||||
if (selection.size() !== 1 || !nf.CanvasUtils.isProcessor(selection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the processor data
|
||||
var processor = selection.datum();
|
||||
|
||||
// view the state for the selected processor
|
||||
nf.ComponentState.showState(processor.component, nf.CanvasUtils.supportsModification(selection));
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens the fill color dialog for the component in the specified selection.
|
||||
*
|
||||
|
|
|
@ -1151,6 +1151,7 @@ nf.Canvas = (function () {
|
|||
nf.Settings.init();
|
||||
nf.Actions.init();
|
||||
nf.QueueListing.init();
|
||||
nf.ComponentState.init();
|
||||
|
||||
// initialize the component behaviors
|
||||
nf.Draggable.init();
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* global nf */
|
||||
|
||||
/**
|
||||
* Views state for a given component.
|
||||
*/
|
||||
nf.ComponentState = (function () {
|
||||
|
||||
var config = {
|
||||
filterText: 'Filter',
|
||||
styles: {
|
||||
filterList: 'filter-list'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters the component state table.
|
||||
*/
|
||||
var applyFilter = function () {
|
||||
// get the dataview
|
||||
var componentStateTable = $('#component-state-table').data('gridInstance');
|
||||
|
||||
// ensure the grid has been initialized
|
||||
if (nf.Common.isDefinedAndNotNull(componentStateTable)) {
|
||||
var componentStateData = componentStateTable.getData();
|
||||
|
||||
// update the search criteria
|
||||
componentStateData.setFilterArgs({
|
||||
searchString: getFilterText()
|
||||
});
|
||||
componentStateData.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the item matches the filter.
|
||||
*
|
||||
* @param {object} item The item to filter
|
||||
* @param {object} args The filter criteria
|
||||
* @returns {boolean} Whether the item matches the filter
|
||||
*/
|
||||
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 matchesKey = item['key'].search(filterExp) >= 0;
|
||||
var matchesValue = item['value'].search(filterExp) >= 0;
|
||||
|
||||
// conditionally consider the scope
|
||||
var matchesScope = false;
|
||||
if (nf.Common.isDefinedAndNotNull(item['scope'])) {
|
||||
matchesScope = item['scope'].search(filterExp) >= 0;
|
||||
}
|
||||
|
||||
return matchesKey || matchesValue || matchesScope;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts the specified data using the specified sort details.
|
||||
*
|
||||
* @param {object} sortDetails
|
||||
* @param {object} data
|
||||
*/
|
||||
var sort = function (sortDetails, data) {
|
||||
// defines a function for sorting
|
||||
var comparer = function (a, b) {
|
||||
var aString = nf.Common.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : '';
|
||||
var bString = nf.Common.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : '';
|
||||
return aString === bString ? 0 : aString > bString ? 1 : -1;
|
||||
};
|
||||
|
||||
// perform the sort
|
||||
data.sort(comparer, sortDetails.sortAsc);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text out of the filter field. If the filter field doesn't
|
||||
* have any text it will contain the text 'filter list' so this method
|
||||
* accounts for that.
|
||||
*/
|
||||
var getFilterText = function () {
|
||||
var filterText = '';
|
||||
var filterField = $('#component-state-filter');
|
||||
if (!filterField.hasClass(config.styles.filterList)) {
|
||||
filterText = filterField.val();
|
||||
}
|
||||
return filterText;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the component state table.
|
||||
*/
|
||||
var clearTable = function () {
|
||||
var componentStateGrid = $('#component-state-table').data('gridInstance');
|
||||
var componentStateData = componentStateGrid.getData();
|
||||
componentStateData.setItems([]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the table with the component state.
|
||||
*
|
||||
* @param {object} componentState
|
||||
*/
|
||||
var loadComponentState = function (localState, clusterState) {
|
||||
var count = 0;
|
||||
|
||||
var componentStateGrid = $('#component-state-table').data('gridInstance');
|
||||
var componentStateData = componentStateGrid.getData();
|
||||
|
||||
// begin the update
|
||||
componentStateData.beginUpdate();
|
||||
|
||||
// local state
|
||||
if (nf.Common.isDefinedAndNotNull(localState)) {
|
||||
$.each(localState.state, function (i, stateEntry) {
|
||||
componentStateData.addItem($.extend({
|
||||
id: count++,
|
||||
scope: stateEntry.nodeAddress
|
||||
}, stateEntry));
|
||||
});
|
||||
}
|
||||
|
||||
if (nf.Common.isDefinedAndNotNull(clusterState)) {
|
||||
$.each(clusterState.state, function (i, stateEntry) {
|
||||
componentStateData.addItem($.extend({
|
||||
id: count++,
|
||||
scope: 'Cluster'
|
||||
}, stateEntry));
|
||||
});
|
||||
}
|
||||
|
||||
// complete the update
|
||||
componentStateData.endUpdate();
|
||||
|
||||
// update the total number of state entries
|
||||
$('#total-component-state-entries').text(count);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the dialog.
|
||||
*/
|
||||
var resetDialog = function () {
|
||||
// clear the fields
|
||||
$('#component-state-name').text('');
|
||||
$('#component-state-description').text('');
|
||||
$('#total-component-state-entries').text('');
|
||||
|
||||
// clear any filter strings
|
||||
$('#component-state-filter').addClass(config.styles.filterList).val(config.filterText);
|
||||
|
||||
// reset clear link
|
||||
$('#clear-link').removeClass('disabled').attr('title', '');
|
||||
|
||||
// clear the table
|
||||
clearTable();
|
||||
|
||||
// clear the component
|
||||
$('#component-state-table').removeData('component');
|
||||
};
|
||||
|
||||
return {
|
||||
init: function () {
|
||||
// intialize the component state filter
|
||||
$('#component-state-filter').on('focus', function () {
|
||||
if ($(this).hasClass(config.styles.filterList)) {
|
||||
$(this).removeClass(config.styles.filterList).val('');
|
||||
}
|
||||
}).on('blur', function () {
|
||||
if ($(this).val() === '') {
|
||||
$(this).addClass(config.styles.filterList).val(config.filterText);
|
||||
}
|
||||
}).on('keyup', function () {
|
||||
applyFilter();
|
||||
}).addClass(config.styles.filterList).val(config.filterText);
|
||||
|
||||
// initialize the processor configuration dialog
|
||||
$('#component-state-dialog').modal({
|
||||
headerText: 'Component State',
|
||||
overlayBackground: true,
|
||||
buttons: [{
|
||||
buttonText: 'Ok',
|
||||
handler: {
|
||||
click: function () {
|
||||
$(this).modal('hide');
|
||||
}
|
||||
}
|
||||
}],
|
||||
handler: {
|
||||
close: function () {
|
||||
resetDialog();
|
||||
}
|
||||
}
|
||||
}).draggable({
|
||||
containment: 'parent',
|
||||
handle: '.dialog-header'
|
||||
});
|
||||
|
||||
// clear state link
|
||||
$('#clear-link').on('click', function () {
|
||||
if ($(this).hasClass('disabled') === false) {
|
||||
// clear the table
|
||||
clearTable();
|
||||
|
||||
// clear the state
|
||||
var revision = nf.Client.getRevision();
|
||||
var component = $('#component-state-table').data('component');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: component.uri + '/state/clear-requests',
|
||||
data: {
|
||||
version: revision.version,
|
||||
clientId: revision.clientId
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
// update the revision
|
||||
nf.Client.setRevision(response.revision);
|
||||
|
||||
// reload the table with no state
|
||||
loadComponentState()
|
||||
}).fail(nf.Common.handleAjaxError);
|
||||
}
|
||||
});
|
||||
|
||||
// initialize the queue listing table
|
||||
var componentStateColumns = [
|
||||
{id: 'key', field: 'key', name: 'Key', sortable: true, resizable: true},
|
||||
{id: 'value', field: 'value', name: 'Value', sortable: true, resizable: true}
|
||||
];
|
||||
|
||||
// conditionally show the cluster node identifier
|
||||
if (nf.Canvas.isClustered()) {
|
||||
componentStateColumns.push({id: 'scope', field: 'scope', name: 'Scope', sortable: true, resizable: true, formatter: scopeFormatter});
|
||||
}
|
||||
|
||||
var componentStateOptions = {
|
||||
forceFitColumns: true,
|
||||
enableTextSelectionOnCells: true,
|
||||
enableCellNavigation: false,
|
||||
enableColumnReorder: false,
|
||||
autoEdit: false
|
||||
};
|
||||
|
||||
// initialize the dataview
|
||||
var componentStateData = new Slick.Data.DataView({
|
||||
inlineFilters: false
|
||||
});
|
||||
componentStateData.setItems([]);
|
||||
componentStateData.setFilterArgs({
|
||||
searchString: '',
|
||||
property: 'key'
|
||||
});
|
||||
componentStateData.setFilter(filter);
|
||||
|
||||
// initialize the sort
|
||||
sort({
|
||||
columnId: 'key',
|
||||
sortAsc: true
|
||||
}, componentStateData);
|
||||
|
||||
// initialize the grid
|
||||
var componentStateGrid = new Slick.Grid('#component-state-table', componentStateData, componentStateColumns, componentStateOptions);
|
||||
componentStateGrid.setSelectionModel(new Slick.RowSelectionModel());
|
||||
componentStateGrid.registerPlugin(new Slick.AutoTooltips());
|
||||
componentStateGrid.setSortColumn('key', true);
|
||||
componentStateGrid.onSort.subscribe(function (e, args) {
|
||||
sort({
|
||||
columnId: args.sortCol.field,
|
||||
sortAsc: args.sortAsc
|
||||
}, componentStateData);
|
||||
});
|
||||
|
||||
// wire up the dataview to the grid
|
||||
componentStateData.onRowCountChanged.subscribe(function (e, args) {
|
||||
componentStateGrid.updateRowCount();
|
||||
componentStateGrid.render();
|
||||
|
||||
// update the total number of displayed items
|
||||
$('#displayed-component-state-entries').text(args.current);
|
||||
});
|
||||
componentStateData.onRowsChanged.subscribe(function (e, args) {
|
||||
componentStateGrid.invalidateRows(args.rows);
|
||||
componentStateGrid.render();
|
||||
});
|
||||
|
||||
// hold onto an instance of the grid
|
||||
$('#component-state-table').data('gridInstance', componentStateGrid);
|
||||
|
||||
// initialize the number of display items
|
||||
$('#displayed-component-state-entries').text('0');
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the state for a given component.
|
||||
*
|
||||
* @param {object} component
|
||||
* @param {boolean} canClear
|
||||
*/
|
||||
showState: function (component, canClear) {
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url: component.uri + '/state',
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var componentState = response.componentState;
|
||||
var componentStateTable = $('#component-state-table');
|
||||
|
||||
// load the table
|
||||
loadComponentState(componentState.localState, componentState.clusterState);
|
||||
|
||||
// populate the name/description
|
||||
$('#component-state-name').text(component.name);
|
||||
$('#component-state-description').text(componentState.stateDescription);
|
||||
|
||||
// store the component
|
||||
componentStateTable.data('component', component);
|
||||
|
||||
// show the dialog
|
||||
$('#component-state-dialog').modal('show');
|
||||
|
||||
// only activate the link when appropriate
|
||||
if (canClear === false) {
|
||||
$('#clear-link').addClass('disabled').attr('title', 'Component state can only be cleared when the component is not actively running');
|
||||
}
|
||||
|
||||
// reset the grid size
|
||||
var componentStateGrid = componentStateTable.data('gridInstance');
|
||||
componentStateGrid.resizeCanvas();
|
||||
}).fail(nf.Common.handleAjaxError);
|
||||
}
|
||||
};
|
||||
}());
|
|
@ -231,6 +231,25 @@ nf.ContextMenu = (function () {
|
|||
(nf.CanvasUtils.isInputPort(selection) && nf.Canvas.getParentGroupId() !== null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the current selection is a processor.
|
||||
*
|
||||
* @param {selection} selection
|
||||
*/
|
||||
var isStatefulProcessor = function (selection) {
|
||||
// ensure the correct number of components are selected
|
||||
if (selection.size() !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nf.CanvasUtils.isProcessor(selection)) {
|
||||
var processorData = selection.datum();
|
||||
return processorData.component.persistsState === true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the current selection is a process group.
|
||||
*
|
||||
|
@ -399,6 +418,7 @@ nf.ContextMenu = (function () {
|
|||
{condition: canStopTransmission, menuItem: {img: 'images/iconTransmissionInactive.png', text: 'Disable transmission', action: 'disableTransmission'}},
|
||||
{condition: supportsStats, menuItem: {img: 'images/iconChart.png', text: 'Stats', action: 'showStats'}},
|
||||
{condition: canAccessProvenance, menuItem: {img: 'images/iconProvenance.png', imgStyle: 'context-menu-provenance', text: 'Data provenance', action: 'openProvenance'}},
|
||||
{condition: isStatefulProcessor, menuItem: {img: 'images/iconViewState.png', text: 'View state', action: 'viewState'}},
|
||||
{condition: canMoveToFront, menuItem: {img: 'images/iconToFront.png', text: 'Bring to front', action: 'toFront'}},
|
||||
{condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to source', action: 'showSource'}},
|
||||
{condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to destination', action: 'showDestination'}},
|
||||
|
|
|
@ -572,24 +572,33 @@ nf.ProcessorConfiguration = (function () {
|
|||
// get the processor details
|
||||
var processor = selectionData.component;
|
||||
|
||||
var requests = [];
|
||||
|
||||
// reload the processor in case an property descriptors have updated
|
||||
var reloadProcessor = nf.Processor.reload(processor);
|
||||
|
||||
requests.push(nf.Processor.reload(processor));
|
||||
|
||||
// get the processor history
|
||||
var loadHistory = $.ajax({
|
||||
requests.push($.ajax({
|
||||
type: 'GET',
|
||||
url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id),
|
||||
dataType: 'json'
|
||||
});
|
||||
}));
|
||||
|
||||
// get the processor state if we're a DFM
|
||||
if (nf.Common.isDFM()) {
|
||||
requests.push();
|
||||
}
|
||||
|
||||
// once everything is loaded, show the dialog
|
||||
$.when(reloadProcessor, loadHistory).done(function (processorResponse, historyResponse) {
|
||||
$.when.apply(window, requests).done(function (processorResponse, historyResponse, stateResponse) {
|
||||
// get the updated processor
|
||||
processor = processorResponse[0].processor;
|
||||
|
||||
// get the processor history
|
||||
var processorHistory = historyResponse[0].componentHistory;
|
||||
|
||||
|
||||
console.log(stateResponse);
|
||||
|
||||
// record the processor details
|
||||
$('#processor-configuration').data('processorDetails', processor);
|
||||
|
||||
|
|
Loading…
Reference in New Issue