When a feature or row is submitted to the Reviewer workspace it becomes a Reviewer result. Data Reviewer provides a defined data quality control workflow that helps you review a result, correct any problems with the result, and then verify the fix to the result. Lifecycle status represents the state of a Reviewer result in the workflow. This sample updates Lifecycle Status of Reviewer results to Data Reviewer for Server using the updateLifecycleStatus function. This sample also demonstrates the use of ReviewerLifecycle class. This class has a function getLifecycleInfo which determines the next appropriate lifecycle status and phase that the result(s) will advance to. Select the Records per page, Session Name and Return Fields. The Reviewer Results will be displayed in a grid. To update Lifecycle status, select results from the grid and click on Update Status button. The live sample updates Lifecycle status to a hosted instance of Data Reviewer for Server.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Reviewer Results UpdateLifecycleStatus Sample</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.29/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.29/dojox/grid/resources/claroGrid.css">
<script src="https://js.arcgis.com/3.29/"></script>
<style>
.reviewerForm {
width: 530px;
font-size: .7em;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
}
.reviewerForm input, .reviewerForm textarea{
padding: 5px;
width: 371px;
margin: 0px 0px 10px 0px;
border: 2px solid #CCC;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
}
.submitButton {
float: right;
padding: 5px;
width: 150px;
font-size: 1.1em;
border: 2px solid #CCC;
margin: 0px 0px 10px 0px;
}
.reviewerMultiSelect{
height:205px;
vertical-align: top;
font-size: 1.0em;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
}
.reviewerForm select{
padding: 5px;
width: 385px;
margin: 0px 0px 10px 0px;
border: 2px solid #CCC;
}
.reviewerForm label {
float: left;
text-align: right;
margin-right: 15px;
width: 130px;
padding-top: 5px;
}
.button {
float: right;
padding: 4px;
width: 100px;
font-size: 0.8em;
border: 1px solid #CCC;
}
.reviewerGrid {
font-size: 0.75em;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
}
</style>
<script>
//This should point to the Data Reviewer soe
var drsSoeUrl = "https://datareviewer.arcgisonline.com/arcgis/rest/services/Samples/reviewerWriteResults/MapServer/exts/DataReviewerServer";
//array of return fields
var returnFields = [];
//Records per page
var recordsPerPage;
require(
[
"dojo/parser",
"dojo/dom",
"dojo/on",
"dojo/_base/array",
"dojo/data/ItemFileReadStore",
"dojox/grid/DataGrid", "dijit/Dialog",
"dijit/form/MultiSelect",
"esri/tasks/datareviewer/ReviewerResultsTask",
"esri/tasks/datareviewer/GetResultsQueryParameters",
"esri/tasks/datareviewer/ReviewerFilters",
"esri/tasks/datareviewer/ReviewerLifecycle",
"dijit/registry",
"dojo/domReady!"
], function(parser, dom, on, array, ItemFileReadStore, DataGrid,Dialog, MultiSelect,
ReviewerResultsTask, GetResultsQueryParameters, ReviewerFilters, ReviewerLifecycle, registry) {
parser.parse();
// specify proxy for request with URL lengths > 2k characters
esriConfig.defaults.io.proxyUrl = "/proxy/";
var reviewerResultsTask,selectedItems;
// create ReviewerResultsTask instance
var reviewerResultsTask = new ReviewerResultsTask(drsSoeUrl);
//get list of return field names
var fieldNames = reviewerResultsTask.getResultsFieldNames();
//Populate field names to be returned by Get Results operation
var i=0;
array.forEach(fieldNames, function(field) {
//Removing mandatory fields from the list. These fields will be added in the datagrid manually
if (field !== "recordId" && field !== "sessionId" && field !== "lifecycleStatus"){
dom.byId("fieldNamesCombo")[i] = new Option(field,i);
i+=1;
}
});
//Click event of previousButton button
on(dom.byId("previousButton"), "click", loadPreviousPage);
//Click event of nextButton button
on(dom.byId("nextButton"), "click", loadNextPage);
//Click event of getResultsButton button
on(dom.byId("getResultsButton"), "click", populateDataGrid);
//Click event of Update Status button
on(dom.byId("displayDialogButton"), "click", displayStatusDialog);
//Click event of Update button
on(dom.byId("updateStatusButton"), "click", updateStatus);
getReviewerSessions();
function getReviewerSessions(){
reviewerResultsTask = new ReviewerResultsTask(drsSoeUrl);
var deferred=reviewerResultsTask.getReviewerSessions();
deferred.then(function(response) {
var reviewerSessions = response.reviewerSessions;
for (var i = 0; i < reviewerSessions.length; i++) {
dom.byId("sessionIdCombo")[i+1] = new Option(reviewerSessions[i].toString(), reviewerSessions[i].sessionId);
}
}, function(error) {
alert(error.message);
});
}
function populateDataGrid() {
// Get the number of records per page
recordsPerPage = parseInt(dom.byId("RecordsPerPage").value);
//Get Selected fields from the list box
var selectItem = registry.byId('fieldNamesCombo').getSelected();
if(isNaN(recordsPerPage) || recordsPerPage < 1){
alert("Please fill out records per page.");
return;
}
if(recordsPerPage>1000){
alert("Records per page can not be greater than 1000.");
return;
}
if(selectItem.length < 1){
alert("Please select return fields.");
return;
}
//Generate grid layout and returnFields based on fields selected in the list box
var layout = [];
returnFields = [];
// adding mandatory fields for updating lifecycle status in the layout.
layout.push({ field:'recordId', name:'recordId' });
layout.push({ field:'sessionId',name:'sessionId' });
layout.push({ field:'lifecycleStatus',name:'lifecycleStatus', 'formatter':getFormattedString });
//adding field in return fields list
returnFields.push("recordId");
returnFields.push("sessionId");
returnFields.push("lifecycleStatus");
array.forEach(selectItem, function(option) {
layout.push({ field:option.text,name:option.text });
returnFields.push(option.text);
});
//show the grid with a loading message and populate it
loadDataInGrid("",layout);
}
function loadDataInGrid(moveType,layout) {
showGrid(true, 'loading');
// create ReviewerResultsTask instance
var queryParameters=GetQueryParameters(moveType);
// call getResults to retrieve the results stored in the reviewer workspace.
var reviewerFilters = new ReviewerFilters();
reviewerFilters.addAttributeFilter("SESSIONID", dom.byId("sessionIdCombo").value);
var deferred = reviewerResultsTask.getResults(queryParameters,reviewerFilters);
// we're using dojo deferred 'then' function to set callback and errback functions
deferred.then(function(response) {
// map attributes from features to items array to populate dataGrid
var items = array.map(response.featureSet.features, function(feature) {
return feature.attributes;
});
// create a dojo ReadStore
var store = new ItemFileReadStore({
data : {
items : items
}
});
// set the store in the DataGrid, this will populate the datagrid with the reviewer results
reviewerResultsGrid.setStore(store);
reviewerResultsGrid.setStructure(layout);
//update current page number label
if(moveType == "previous" && (parseInt(dom.byId('lblPageNumber').innerHTML) > 1)){
dom.byId('lblPageNumber').innerHTML = parseInt(dom.byId('lblPageNumber').innerHTML) - 1;
}
else if(moveType == "next"){
dom.byId('lblPageNumber').innerHTML = parseInt(dom.byId('lblPageNumber').innerHTML) + 1;
}
}, function(err) {
if(moveType == "next" && (err.message.indexOf("No results returned for specified query:") === 0)){
showGrid(true);
alert("You are already at the last page.");
}
else{
showGrid(false);
reviewerResultsGrid.setStore(null);
alert("Error retrieving reviewer results: " + err.message);
}
return;
});
}
function getFormattedString(value, obj,column){
if (value===null){
return "";
}
if(column.field=="lifecycleStatus"){
if (value===null){
return null;
}
return ReviewerLifecycle.toLifecycleStatusString(value);
}
else if (column.field=="verificationDateUtc" ||
column.field=="correctionDateUtc" || column.field=="reviewDateUtc"){
var date = new Date(value);
var localDate = new Date(date.toLocaleString());
return localDate.toDateString();
}
}
function GetQueryParameters(moveType){
var queryParameters = new GetResultsQueryParameters();
queryParameters.pageSize = recordsPerPage;
if(moveType == "previous" && (parseInt(dom.byId('lblPageNumber').innerHTML) > 1)){
queryParameters.pageNumber = parseInt(dom.byId('lblPageNumber').innerHTML) - 2;
}
else if(moveType == "next"){
queryParameters.pageNumber = parseInt(dom.byId('lblPageNumber').innerHTML);
}
else if (moveType===""){
queryParameters.pageNumber = parseInt(dom.byId('lblPageNumber').innerHTML) - 1;
}
else{
queryParameters.pageNumber = 0;
}
queryParameters.returnFields = returnFields;
return queryParameters;
}
//load next page
function loadNextPage() {
loadDataInGrid("next","");
}
//load previous page
function loadPreviousPage(){
if(parseInt(dom.byId('lblPageNumber').innerHTML) == 1){
alert("You are already at the first page.");
return;
}
else{
loadDataInGrid("previous", "");
}
}
//Displays the next lifecycle status that the selected results can move to in a dialog
function displayStatusDialog(){
selectedItems = reviewerResultsGrid.selection.getSelected();
if (selectedItems.length>0){
var lifecycleList = [];
//get an array of unique lifecycle status values of selected records
for (i = 0; i < selectedItems.length; i++){
if (lifecycleList.indexOf(selectedItems[i].lifecycleStatus[0]) == -1){
lifecycleList.push(selectedItems[i].lifecycleStatus[0]);
}
}
lifecycleList.sort();
//get lifecycle information from the ReviewerLifecycle helper class
var lifecycleInfo = ReviewerLifecycle.getLifecycleInfo(lifecycleList);
if (lifecycleInfo !== null){
// clear out any previous values
dom.byId("technicianName").value="";
for(i=dom.byId("statusSelect").options.length-1;i>=1;i--){
dom.byId("statusSelect").remove(i);
}
array.forEach (lifecycleInfo.nextLifecycleStatus,function(status,i){
dom.byId("statusSelect")[i+1] = new Option(ReviewerLifecycle.toLifecycleStatusString(status), status);
});
}
else{
alert("The selected records cannot be updated to a common lifecycle status");
return;
}
var statusDialog = registry.byId("statusDialog");
statusDialog.show();
}
else{
alert("Please select records to update");
}
}
//calls the update lifecycleStatus method from the ReviewerResults task. If selected results are updated successfully a message will be displayed
function updateStatus(){
var reviewerFilters = new ReviewerFilters();
array.forEach(selectedItems, function(selectedItem){
reviewerFilters.addAttributeFilter("RECORDID", selectedItem.recordId);
});
var deferred=reviewerResultsTask.updateLifecycleStatus(dom.byId("sessionIdCombo").value,dom.byId("statusSelect").value,dom.byId("technicianName").value,reviewerFilters);
deferred.then(function(response){
registry.byId("statusDialog").hide();
//refresh datagrid
populateDataGrid();
array.forEach(response.featureEditResults, function(featureEditResult){
if (featureEditResult.success===false){
alert("Error updating records from the selection");
return;
}
});
alert("Lifecycle Status updated");
}, function(error){
alert(error.message);
});
}
//handle grid visibility
function showGrid(show,message) {
reviewerResultsGrid.showMessage(message || "");
dom.byId('gridDiv').style.visibility = show ? "visible" : "hidden";
}
});
</script>
</head>
<body class="claro">
<h2 align="center">Update Lifecycle Status Sample</h2>
<div style="width:100%; overflow-x: auto;" >
<div style="padding: 0px 20px 0px 20px; float:left;">
<div class="reviewerForm" >
<label for="RecordsPerPage">Records per page:</label>
<input type="number" id="RecordsPerPage" placeholder="valid values are from 1 to 1000"/>
<label for="sessionIdCombo">Session Name:</label>
<select id="sessionIdCombo" ><option value="">Select Session</option>
</select>
<label for="fieldNamesCombo">Return fields:</label>
<select class ="reviewerMultiSelect" id="fieldNamesCombo" data-dojo-type="dijit/form/MultiSelect"></select>
<label for="getResultsButton"></label>
<button id="getResultsButton" class="submitButton">Get Results</button>
</div>
</div>
</div>
<div id = "gridDiv" style="width: 100%; overflow-x: auto;visibility: hidden" class="reviewerGrid">
<button id="previousButton"> < </button>
<label id = "lblPageNumber" >1</label>
<button id="nextButton"> > </button>
<button id="displayDialogButton"> Update Status </button>
<table data-dojo-id="reviewerResultsGrid" data-dojo-type="dojox/grid/DataGrid" autoheight="true" autowidth="true"></table>
</div>
<div data-dojo-type="dijit/Dialog" data-dojo-id="statusDialog" title="Update Status" id="statusDialog" class="reviewerForm" style="width:350px;height: 160px">
<table>
<tr>
<td><label for="name">Reviewer Technician:</label></td>
<td><input id="technicianName" placeholder="Technician Name" style="width:170px"/></td>
</tr>
<tr>
<td><label for="address">Lifecycle Status:</label></td>
<td> <select id="statusSelect" style="width: 176px" ><option value="">Select Status</option></td>
</tr>
</table>
<div>
<button id="cancelButton" onclick="statusDialog.onCancel();" style="width:80px; float: right;"> Cancel </button>
<button id="updateStatusButton" style="width:80px; float: right;"> Update</button>
</div>
</div>
</body>
</html>