Переглянути джерело

Merge to origin-wiscigt master

tomcat8 @ merlin 3 роки тому
батько
коміт
0c612a8745
5 змінених файлів з 686 додано та 94 видалено
  1. 76 0
      views/review.html
  2. 9 0
      views/review.view.xml
  3. 326 0
      web/crf/crfReview.js
  4. 272 92
      web/crf/crfVisit.js
  5. 3 2
      web/crf/formPortal.js

+ 76 - 0
views/review.html

@@ -0,0 +1,76 @@
+<h3>Title</h3>
+
+
+<p id="participantCode">Loading1b</p>
+<p id="visitCode">Loading2</p>
+
+<div id="organ3">
+	<table>
+	<tr>
+		<td id="CT_organ3"></td>
+		<td id="PET_organ3"></td>
+		<td id="SUV_organ3"></td>
+	</tr>
+	<tr>
+		<td id="CT_organ4"></td>
+		<td id="PET_organ4"></td>
+		<td id="SUV_organ4"></td>
+	</tr>
+	<tr>
+		<td id="CT_organ5"></td>
+		<td id="PET_organ5"></td>
+		<td id="SUV_organ5"></td>
+	</tr>
+	</table>
+</div>
+<div id="debugDiv">
+	<textarea id="debugCode"></textarea>
+</div>
+
+<script type="text/javascript">
+
+let searchParams = new URLSearchParams(window.location.search);
+
+//update this to pick crfRef from url
+let participantCode=searchParams.get('participantCode');
+let visitCode=searchParams.get('visitCode');
+document.getElementById("participantCode").innerHTML=participantCode;
+document.getElementById("visitCode").innerHTML=visitCode;
+let project=LABKEY.ActionURL.getContainer();
+document.getElementById("debugCode").value+='\n'+project;
+
+let server="http://onko-nix.onko-i.si:8080/labkey";
+let basePath=server+"/_webdav/";
+basePath+=project;
+basePath+="/@files/preprocessedImages/";
+basePath+=participantCode+"/"+visitCode+"/";
+document.getElementById("debugCode").value+='\n'+basePath;
+let studyPath=server+project;
+
+//let divImg=document.getElementById("organ3_PET");
+
+let organs=["3","4","5"];
+let im=["PET","CT"];
+for (let i=0;i<organs.length;i++){
+	let organ=organs[i];
+	let type="PET";
+
+	let img=document.createElement('img');
+	let imgSrc=basePath+participantCode+"-"+visitCode+"_"+type+"_"+organ+"_v5.png";
+	img.src=imgSrc;
+	img.width="300";
+	document.getElementById(type+"_organ"+organ).appendChild(img);
+							
+
+	type="CT";
+	let img1=document.createElement('img');
+	let img1Src=basePath+participantCode+"-"+visitCode+"_"+type+"_"+organ+"_v5.png";
+	img1.src=img1Src;
+	img1.width="300";
+	document.getElementById(type+"_organ"+organ).appendChild(img1);
+}
+LABKEY.requiresScript('/vis/genericChart/genericChartHelper.js', 
+      function(){LABKEY.vis.GenericChartHelper.loadVisDependencies(dependencyCallback);});
+
+
+</script>

+ 9 - 0
views/review.view.xml

@@ -0,0 +1,9 @@
+<view xmlns="http://labkey.org/data/xml/view" title="Review">
+	<dependencies>
+			<dependency path="crf/crfReview.js"/>
+		</dependencies>
+	<permissions>
+		<permission name="login"/>
+	</permissions>
+
+</view>

+ 326 - 0
web/crf/crfReview.js

@@ -0,0 +1,326 @@
+
+function renderMessages(id, messages) {
+	if (messages && messages.length > 0) {
+		let errorDiv = document.createElement('div');
+		let style='padding: 10px; background-color: #ffe5e5;' 
+		style+='color: #d83f48; font-weight: bold;';
+		errorDiv.setAttribute('style', style);
+		errorDiv.innerHTML = messages.join('<br/>');
+		document.getElementById(id).appendChild(errorDiv);
+	}
+};
+
+function validateChartConfig(chartConfig, aes, scales, measureStore) {
+	let hasNoDataMsg = LABKEY.vis.GenericChartHelper.validateResponseHasData(measureStore, false);
+	if (hasNoDataMsg != null)
+		return {"success": false, "messages": [hasNoDataMsg]};
+
+	let measureNames = Object.keys(chartConfig.measures);
+	for (let i = 0; i < measureNames.length; i++) {
+		let measureProps = chartConfig.measures[measureNames[i]];
+		if (measureProps && 
+			measureProps.name && 
+			measureStore.records()[0][measureProps.name] == undefined){
+					                    
+			let retVal=new Object();
+			retVal.success=false;
+			retVal.messages=['The measure, ' + 
+				measureProps.label + 
+				', is not available. It may have been renamed or removed.']
+			return retVal;
+		}
+	}
+
+	 let messages = [];
+	 let axisMeasureNames = ['x', 'xSub', 'y'];
+	 for (let i = 0; i < axisMeasureNames.length; i++) {
+		 if (measureNames.indexOf(axisMeasureNames[i]) > 0) {
+			let validation = LABKEY.vis.GenericChartHelper.validateAxisMeasure(
+				chartConfig.renderType, chartConfig, axisMeasureNames[i],
+				aes, scales, measureStore.records());
+			if (validation.message != null)
+				messages.push(validation.message);
+			if (!validation.success)
+				return {"success": false, "messages": messages};
+		 }
+	}
+
+	return {"success": true, "messages": messages};
+
+}
+function selectRowsCallback(renderConfig, measureStore) {
+	let responseMetaData = measureStore.getResponseMetadata();
+
+        // chartConfig is the saved information about the chart (labels, scales, etc.)
+
+	let chartConfig = new Object();
+	chartConfig.renderType="line_plot";
+
+	let mX=new Object();
+	mX.displayFieldJsonType="";
+        mX.hidden=false;
+        mX.fieldKey="percentile";
+        mX.label="Percentile";
+        mX.schemaName="study";
+        mX.type="float";
+        mX.normalizedType="float";
+        mX.measure=true;
+        mX.name="percentile";
+        mX.queryName="SUVQuantiles";
+        mX.alias="percentile";
+        mX.shortCaption="Percentile";
+        mX.dimension=false;
+
+	let mY=new Object();
+        mY.displayFieldJsonType="";
+        mY.hidden=false;
+        mY.fieldKey="value";
+        mY.label="Value";
+        mY.schemaName="study";
+        mY.type="float";
+        mY.normalizedType="float";
+        mY.measure=true;
+        mY.name="value";
+        mY.queryName="SUVQuantiles";
+        mY.alias="value";
+        mY.shortCaption="Value";
+        mY.dimension=false;
+
+
+	let mS=new Object();
+        mS.displayFieldJsonType="";
+        mS.hidden=false;
+        mS.fieldKey="ParticipantId";
+        mS.label="Participant ID";
+        mS.schemaName="study";
+        mS.type="string";
+        mS.normalizedType="string";
+        mS.measure=false;
+        mS.name="ParticipantId";
+        mS.queryName="SUVQuantiles";
+        mS.alias="ParticipantId";
+        mS.shortCaption="Participant ID";
+        mS.dimension=true;
+
+	chartConfig.measures=new Object();
+        chartConfig.measures.x=mX;
+        chartConfig.measures.y=mY;
+        chartConfig.measures.series=mS;
+        chartConfig.measures.pointClickFn=null;
+        chartConfig.scales=new Object();
+        chartConfig.scales.x=new Object();
+        chartConfig.scales.x.trans="linear";
+        chartConfig.scales.y=new Object();
+        chartConfig.scales.y.trans="linear";
+        chartConfig.labels=new Object();
+        chartConfig.labels.main="SUVQuantiles";
+        chartConfig.labels.subtitle="";
+        chartConfig.labels.x="Percentile";
+        chartConfig.labels.y="Value";
+ 	chartConfig.width=null;
+        chartConfig.height=null;
+        chartConfig.pointType="outliers";
+        chartConfig.geomOptions=new Object();
+        chartConfig.geomOptions.label="SUVQuantiles";
+        chartConfig.geomOptions.subtitle="";
+        chartConfig.geomOptions.width=null;
+        chartConfig.geomOptions.height=null;
+        chartConfig.geomOptions.pointType="outliers";
+        chartConfig.geomOptions.pointFillColor="3366FF";
+        chartConfig.geomOptions.lineWidth=2;
+        chartConfig.pointFillColor="3366FF";
+        chartConfig.lineWidth="3";
+        chartConfig.lineColor="000000";
+        chartConfig.boxFillColor="3366FF";
+        chartConfig.hideDataPoints=false;
+        chartConfig.colorPaletteScale="ColorDiscrete";
+        chartConfig.chartLayout="single";
+        chartConfig.chartSubjectSelection="subjects";
+        chartConfig.displayIndividual=true;
+        chartConfig.displayAggregate=false;
+        chartConfig.errorBars="None";
+        chartConfig.pieInnerRadius=0;
+	chartConfig.pieOuterRadius=80;
+        chartConfig.showPiePercentages=true;
+        chartConfig.pieHideWhenLessThanPercentage=5;
+        chartConfig.piePercentagesColor="333333";
+        chartConfig.gradientPercentage=95;
+        chartConfig.gradientColor="FFFFFF";
+        chartConfig.binThreshold=10000;
+        chartConfig.binShapeGroup="hex";
+        chartConfig.binColorGroup="BlueWhite";
+        chartConfig.binSingleColor="000000";
+        chartConfig.showOutliers=true;
+        chartConfig.binShape="hex";
+
+	if (!chartConfig.hasOwnProperty('width') || 
+		chartConfig.width == null) 
+		chartConfig.width = 1000;
+        if (!chartConfig.hasOwnProperty('height') || 
+		chartConfig.height == null) 
+		chartConfig.height = 600;
+	if (renderConfig.hasOwnProperty('width')){
+		chartConfig.width=renderConfig.width;
+		chartConfig.height=0.6*renderConfig.width;
+	}
+
+
+	let xAxisType = chartConfig.measures.x ? (
+		chartConfig.measures.x.normalizedType || 
+		chartConfig.measures.x.type) : null;
+        let chartType = LABKEY.vis.GenericChartHelper.getChartType(
+		chartConfig.renderType, xAxisType);
+        let aes = LABKEY.vis.GenericChartHelper.generateAes(
+                chartType, chartConfig.measures, 
+		responseMetaData.schemaName, responseMetaData.queryName);
+
+        let valueConversionResponse = 
+		LABKEY.vis.GenericChartHelper.doValueConversion(
+			chartConfig, aes, chartType, measureStore.records());
+     	if (!Ext4.Object.isEmpty(valueConversionResponse.processed)) {
+               Ext4.Object.merge(chartConfig.measures, 
+		       valueConversionResponse.processed);
+               aes = LABKEY.vis.GenericChartHelper.generateAes(
+                       chartType, chartConfig.measures, 
+		       responseMetaData.schemaName, responseMetaData.queryName);
+        }
+        let data = measureStore.records();
+        if (chartType == 'scatter_plot' && 
+		data.length > chartConfig.geomOptions.binThreshold) {
+               chartConfig.geomOptions.binned = true;
+        }
+        let scales = LABKEY.vis.GenericChartHelper.generateScales(
+		chartType, chartConfig.measures, chartConfig.scales, 
+		aes, measureStore);
+        let geom = LABKEY.vis.GenericChartHelper.generateGeom(
+		chartType, chartConfig.geomOptions);
+	document.getElementById('debugCode').value+='\n geom color '+geom.color;
+	
+
+        let labels = LABKEY.vis.GenericChartHelper.generateLabels(
+		chartConfig.labels);
+
+	if (chartType == 'bar_chart' || chartType == 'pie_chart') {
+            	let dimName = null, subDimName = null; measureName = null,
+	               aggType = 'COUNT';
+
+        	if (chartConfig.measures.x) {
+			dimName = chartConfig.measures.x.converted ? 
+				chartConfig.measures.x.convertedName : 
+				chartConfig.measures.x.name;
+        	}
+        	if (chartConfig.measures.xSub) {
+	        	subDimName = chartConfig.measures.xSub.converted ? 
+				chartConfig.measures.xSub.convertedName : 
+				chartConfig.measures.xSub.name;
+		}
+	
+		if (chartConfig.measures.y) {
+			measureName = chartConfig.measures.y.converted ? 
+				chartConfig.measures.y.convertedName : 
+				chartConfig.measures.y.name;
+
+			if (Ext4.isDefined(chartConfig.measures.y.aggregate)) {
+				aggType = chartConfig.measures.y.aggregate;
+                	}
+                	else if (measureName != null) {
+				aggType = 'SUM';
+			}
+
+		}
+
+
+		data = LABKEY.vis.getAggregateData(data, dimName, subDimName, 
+			measureName, aggType, '[Blank]', false);
+        }
+
+	let plotConfig = LABKEY.vis.GenericChartHelper.generatePlotConfig(
+		renderConfig.chartId,chartConfig, labels, aes, scales, geom, data);
+	document.getElementById('debugCode').value+='\n plotConfig layers: '+plotConfig.layers.length;
+	for (let i=0;i<plotConfig.layers.length;i++){
+		let l=plotConfig.layers[i];
+		document.getElementById('debugCode').value+='\n color: '+l.aes.color;
+		if (l.data===null)
+			continue;
+		document.getElementById('debugCode').value+='\n data: '+l.data.length;
+
+	}
+        let validation = validateChartConfig(chartConfig, aes, scales, measureStore);
+        renderMessages(renderConfig.chartId, validation.messages);
+        if (!validation.success)
+            return;
+	
+	let plot;
+        if (chartType == 'pie_chart') {
+            new LABKEY.vis.PieChart(plotConfig);
+        }
+        else {
+            plot = new LABKEY.vis.Plot(plotConfig);
+            plot.render();
+        }
+	   
+
+
+
+}
+
+function dependencyCallback() {
+
+	let organs=["3","4","5"];
+		
+	for (let i=0;i < organs.length; i++){
+
+		let renderConfig=new Object();
+        	//all additional configuration stuff goes in here
+
+		renderConfig.chartId='SUV_organ'+organs[i];
+		renderConfig.width=500;
+		renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
+		renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
+
+		// When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
+		// The queryConfig object stores all the information needed to make a selectRows request
+		
+		let queryConfig = new Object;
+	        queryConfig.schemaName="study";
+        	queryConfig.queryName="SUVQuantiles";
+        	queryConfig.viewName=null;
+        	queryConfig.dataRegionName="Dataset";
+	        queryConfig.queryLabel="SUVQuantiles";
+        	queryConfig.parameters= new Object();
+		queryConfig.requiredVersion=13.2;
+	        queryConfig.maxRows=-1;
+        	queryConfig.sort="lsid";
+	        queryConfig.method="POST";
+        	queryConfig.columns=["percentile","value","ParticipantId"];
+	        queryConfig.filterArray=new Array();
+        	//queryConfig.filterArray.push({
+		//	"name":"patientCode",
+		//	"value":renderConfig.participantCode,
+		//	"type":"eq"});
+	        queryConfig.filterArray.push({
+			"name":"visitCode",
+			"value":renderConfig.visitCode,
+			"type":"eq"});
+        	queryConfig.filterArray.push({
+			"name":"organ",
+			"value":organs[i],
+			"type":"eq"});
+
+		if (queryConfig.filterArray && 
+			queryConfig.filterArray.length > 0) {
+            		let filters = [];
+            		for (let i = 0; i < queryConfig.filterArray.length; i++) {
+                		let f = queryConfig.filterArray[i];
+                		filters.push(LABKEY.Filter.create(
+					f.name,  f.value, 
+					LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
+            		}
+            		queryConfig.filterArray = filters;
+        	}
+        	queryConfig.success = function(data){
+			selectRowsCallback(renderConfig,data);};
+        	queryConfig.containerPath = "/IPNUMMprospektiva/Study";
+        	LABKEY.Query.MeasureStore.selectRows(queryConfig);
+	}
+};

+ 272 - 92
web/crf/crfVisit.js

@@ -74,7 +74,7 @@ function generateDebugSection(config){
 
 
 
-function setAdditionalData(config,additionalData,entry){
+function setAdditionalData(config, additionalData,entry){
 	let debug=true;
 	if (debug) print(config,"setAdditionalData");
 	if (entry["showFlag"]==="NONE") {
@@ -115,9 +115,106 @@ function readonlySetup(config){
 	return setup;
 }
 
-function generateSection(config, sectionName, sectionTitle, listName, additionalData){
+function afterFormSetup(config,formConfig,data){
 
-	let formName=config.masterForm;
+	let debug=true;
+	if (debug) print(config,"afterFormSetup ["+data.rows.length+"]");
+	formConfig.formSetup=data;
+
+	//get list of queries
+	let fields=formConfig.formSetup.metaData.fields;
+
+	if (debug) print(config,"generateForm: fields: "+fields);
+	let field="NONE";
+	//if (debug) printTableSetup(config,data);
+	for (f in fields){
+		if (fields[f]['name']!='queryName') continue;
+		field=fields[f];
+		break;
+	}
+	if (debug) print(config,"generateForm: field: "+field);
+	let lookup=field.lookup;
+	if (debug) print(config,"generateForm: lookup: "+lookup);
+	let qconfig=new Object();
+	qconfig.containerPath=config.containerPath;
+	qconfig.schemaName=lookup.schemaName;
+	qconfig.queryName=lookup.queryName;
+		
+	//qconfig.filterArray=[LABKEY.Filter.create(lookup.keyColumn,entry['queryName'])];
+	qconfig.filterArray=[];
+	qconfig.success=function(data){afterFormSetupLookup(config,formConfig,data)};
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function afterFormSetupLookup(config,formConfig,data){
+	//walk through the list of datasets/list and generate tables for each list
+	let debug=true;
+
+	formConfig.formSetupLookup=data;
+
+	let rows=formConfig.formSetup.rows;
+	//extract list of forms from formConfig
+	for (let i=0;i<rows.length;i++){
+
+		//each from has multiple lists associated with it
+		if (debug) print(config,"generateForm ["+i+"/"+rows.length+"]");
+
+		let entry=rows[i];
+		//this is actually a pointer into another list (==lookup)
+		//another selectRows is needed to actually get the name for the queryName
+		
+		//id : entry[queryName]
+		//name: dentry[queryName]
+	
+		let queryId=entry['queryName'];
+
+		//walk over keys to get the right lookup entry
+		let lookupRows=formConfig.formSetupLookup.rows;
+		let dentry=undefined;
+		for (let j=0;j<lookupRows.length;j++){
+			
+			if (lookupRows[j].Key!=queryId)
+				continue;
+			dentry=lookupRows[j];
+			break;
+		}
+		if (dentry===undefined){
+			print(config,"generateForm ["+i+"] no list found");
+			return;
+		}
+		if (debug)
+			for (f in dentry) 
+				print(config,"generateFormLookup field: "+f+" value: "+dentry[f]);
+	
+		let queryName=dentry["queryName"];
+
+		if (debug) print(config,"generateFormLookup: ID: "+queryId+" name: "+queryName);
+	
+		//update fields for review
+		if (!(queryName in config.fields))
+			config.fields[queryName]=new Object();
+		
+		if (!(queryId in config.queryMap))
+			config.queryMap[queryId]=queryName;
+		
+		let field=config.fields[queryName];
+
+		field.title=entry["title"];
+		field.queryId=queryId;
+
+		if (debug) print(config,"entry[showFlag]: "+entry["showFlag"]);
+
+		let additionalData=new Object();
+		setAdditionalData(config,additionalData,entry);
+		//section fits one dataset/list
+		generateSection(config,formConfig,queryName,entry["title"],queryName, additionalData);
+	}
+
+}
+
+function generateSection(config, formConfig, sectionName, sectionTitle, listName, additionalData){
+
+	let formName=config.masterForm;//this is HTML designator of area on page
 	let debug=true;
 	if (debug) print(config,"generateSection "+sectionName);
 	let tb=config.document.createElement('table');
@@ -165,18 +262,28 @@ function generateSection(config, sectionName, sectionTitle, listName, additional
 	}
 	if (debug) print(config,"generate master table");
 
-	
+		
 	let setup=fullAccessSetup(config,listName);
-	if ("reviewMode" in config) 
+	if (formConfig.formStatus=="Submitted")
 		setup=readonlySetup(config);
+	if (formConfig.formStatus=="Approved")
+		setup=readonlySetup(config);
+	
+	
 	//master table is unique per visit
+
+	
 	setup.unique=true;
-	generateTable(config,listName,divTable.id,true,additionalData,setup);
+	generateTable(config,formConfig,listName,divTable.id,true,additionalData,setup);
 	
 	if (debug) print(config,"generate master table: done");
 
 	let generateSubTable=true;
-	if ("reviewMode" in config) generateSubTable=false;
+	if (formConfig.formStatus=="Submitted")
+		generateSubTable=false;
+	if (formConfig.formStatus=="Approved")
+		generateSubTable=false;
+	
 	if (! ("showFlag" in additionalData) ) generateSubTable=false;
 	
 	if (generateSubTable){
@@ -185,11 +292,12 @@ function generateSection(config, sectionName, sectionTitle, listName, additional
 		
 
 		let setup=fullAccessSetup(config,qName);
-		if ("reviewMode" in config)
-			setup=readonlySetup(config);
-		generateTable(config,qName,dName,false,additionalData,setup);
+		//if (readonly) setup=readonlySetup(config);
+		generateTable(config,formConfig,qName,dName,false,additionalData,setup);
 	}
 
+	print(config,"generate review");
+
 	let divReviewList=config.document.createElement('div');
 	divReviewList.id=sectionName+"ReviewList";
 	div.appendChild(divReviewList);
@@ -201,34 +309,16 @@ function generateSection(config, sectionName, sectionTitle, listName, additional
 
 	//assume we already have listId (content of config.setupQueryName is listId)
 	//we need listName also
-	let qconfig=new Object();	
-	qconfig.containerPath=config.containerPath;
-	qconfig.schemaName='lists';
 	//qconfig.queryName=config.setupQueryName;
-	qconfig.queryName="FormSetup";
-	qconfig.filterArray=[LABKEY.Filter.create("formName",config.formId)];
-	
-	qconfig.success=function(data){
-		generateReview(config,data,divReview.id,divReviewList.id,listName)};
-	LABKEY.Query.selectRows(qconfig);
+	generateReview(config,formConfig,divReview.id,divReviewList.id,listName);
 }
 
-function generateReview(config,data,divReviewId,divReviewListId, listName){
+function generateReview(config,formConfig,divReviewId,divReviewListId, listName){
 	let listId=config.fields[listName].queryId;
 
 	let debug=true;
 	if (debug) print(config,"Generate review for: "+listId);
 	
-	//don't need this
-	//let listId=-1;
-	//for (let i=0;i<data.rows.length;i++){
-	//	let entry=data.rows[i];
-	//	if (entry["queryName"]!=listName) continue;
-	//	listId=entry["Key"];
-	//	break;
-	//}
-	//if (debug) print(config,"Review: setting listId: "+listId);	
-
 	let reviewSetup=new Object();
 	reviewSetup.readonlyFlag=function(vName){
 		if (vName=="queryName") return true; 
@@ -238,7 +328,7 @@ function generateReview(config,data,divReviewId,divReviewListId, listName){
 	reviewSetup.addApply="Add Review";
 
 	let generateTableFlag=true;
-	if ("reviewMode" in config && config.reviewMode == "APPROVED" ){
+	if (formConfig.formStatus == "Approved" ){
 		delete reviewSetup.addApply;
 		reviewSetup.readonlyFlag=function(vName){return false;}
 		generateTableFlag=false;
@@ -246,9 +336,10 @@ function generateReview(config,data,divReviewId,divReviewListId, listName){
 	
 	reviewSetup.filters=new Object();
 	reviewSetup.filters["crfRef"]=getCRFref(config);
-	reviewSetup.filters["queryName"]=listId;//entry in reviewComments list is queryname, all in small caps
-	//reviewSetup.filters["ModifiedBy"]=LABKEY.Security.currentUser.id;
+	
+ 	reviewSetup.filters["queryName"]=listId;//entry in reviewComments list is queryname, all in small caps
 	//needs listName, in argument
+	
 	reviewSetup.getInputId=function(vName){return listName+"_add"+vName};
 	reviewSetup.divReviewListId=divReviewListId;
 		
@@ -262,10 +353,11 @@ function generateReview(config,data,divReviewId,divReviewListId, listName){
 	
 	if (! generateTableFlag) return;
 
-	generateTable(config,"reviewComments",divReviewId,false,new Object(),reviewSetup);
+	
+	generateTable(config, formConfig,"reviewComments",divReviewId,false,new Object(),reviewSetup);
 }	
 
-function setListVisibility(config,setup,additionalData,readonlyFlag){
+function setListVisibility(config, setup,additionalData,readonlyFlag){
 	let debug=true;
 	if (debug){
 		print(config,"Set list visibility ");
@@ -289,16 +381,18 @@ function setListVisibility(config,setup,additionalData,readonlyFlag){
 		let filters=new Object();
 		if ("filters" in additionalData) filters=additionalData.filters;
 		x.style.display = "block";
-		updateListDisplay(config,additionalData.divQueryName,additionalData.queryName,filters,readonlyFlag);
+		updateListDisplay(config, 
+			additionalData.divQueryName,additionalData.queryName,filters,readonlyFlag);
 	}
 }
 
-function updateListDisplay(config,divName,queryName,filters,readonlyFlag){
+function updateListDisplay(config, divName,queryName,filters,readonlyFlag){
 	let debug=true;
 
 	if (debug) print(config,"UpdateListDisplay: Query - "+queryName+" div - "+divName);
 
 	if (divName=="NONE") return;
+
 	let crfRef=getCRFref(config);
 	let div=config.document.getElementById(divName);
 
@@ -382,12 +476,14 @@ function generateButton(config,divName,title,buttonName,callback,callbackParamet
 	
 }
 
-function generateTable(config,listName,divName,unique,additionalData,setup){
+function generateTable(config,formConfig,listName,divName,unique,additionalData,setup){
 	let debug=true;
 	
 	if (debug) print(config,"generateTable: "+listName);
+	//these objects will contain respective data for the entry
 
 	//add temp variables
+	//this will capture the state of the data prior to updating
 	let qconfig=new Object();
 	qconfig.containerPath=config.containerPath;
 	qconfig.schemaName='lists';
@@ -397,7 +493,7 @@ function generateTable(config,listName,divName,unique,additionalData,setup){
 	for (f in setup.filters){
 		qconfig.filterArray.push(LABKEY.Filter.create(f,setup.filters[f]));
 	}
-	qconfig.success=function(data){populateTable(config,data,divName,unique,additionalData,setup)};
+	qconfig.success=function(data){populateTable(config,formConfig, data,divName,unique,additionalData,setup)};
 	LABKEY.Query.selectRows(qconfig);
 }
 
@@ -417,11 +513,14 @@ function printTableSetup(config,data){
 }
 
 
-function populateTable(config,data,divName,unique,additionalData,setup){
+function populateTable(config,formConfig, data,divName,unique,additionalData,setup){
 	//generate and populate table with the first suitable entry
 	let debug=true;
+	//avoid resetting of values
+	if (!(data.queryName in formConfig.dataFields))
+		formConfig.dataFields[data.queryName]=data.metaData.fields;
+
 
-	
 	if (debug){
 		print(config,"populateTable Query: "+data.queryName+" divName: "+divName+" setup: "+setup);
 
@@ -434,14 +533,21 @@ function populateTable(config,data,divName,unique,additionalData,setup){
 
 	if (debug)
 		print(config,"Data: nrows "+data.rows.length);
-
-	if (data.rows.length > 0) entry=data.rows[0];
+	
+	//copy values from queryName to formConfig.entries
+	if (data.rows.length > 0) formConfig.entries[data.queryName]=data.rows[0];
+	
+	//this is the current data snapshot
+	if (data.queryName in formConfig.entries)
+		entry=formConfig.entries[data.queryName];
+	
 	
 	let tb=config.document.createElement('table');
 	tb.className="t2";
 	config.document.getElementById(divName).appendChild(tb);
 
-	let fields=data.metaData.fields;
+	//this are the fields (probably constant)
+	let fields=formConfig.dataFields[data.queryName];
 	for (f in fields){
 		let field=fields[f];
 		if (field.hidden) continue;
@@ -803,7 +909,22 @@ function onDatabaseUpload(config){
 	//figure out the participantId
 	
 	let qconfig=new Object();
-	qconfig.queryName=config.queryMap[config.registrationQueryId];
+
+	qconfig.schemaName="lists";
+	qconfig.queryName="Forms";
+	qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
+	
+	//qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
+	qconfig.success=function(data){afterForms(config,configUpload,data)};
+	LABKEY.Query.selectRows(qconfig);
+
+}
+
+function afterForms(config,configUpload,data){	
+	let formEntry=data.rows[0];
+	configUpload.registrationQueryId=formEntry["masterQuery"];
+	let qconfig=new Object();
+	qconfig.queryName=config.queryMap[configUpload.registrationQueryId];
 	//queryMap holds mapping for queries in visit; 
 	//masterQuery should be one of them, so this is safe.
 	qconfig.schemaName='lists';
@@ -1087,7 +1208,7 @@ function completeWithFlag(config,data,flag){
 	if (debug){
 		if (flag==4) print(config,"complete with review");
 	}
-	//redirect(config);
+	redirect(config);
 
 	
 	
@@ -1127,7 +1248,8 @@ function finalValidation(config){
 		finalRedirect(config);
 	}
 	else{
-		updateSubmitStatus(config,"Form invalid");
+		let el=document.getElementById(config.submitReportId);
+		el.innerHTML="Form invalid";
 	}
 }
 
@@ -1137,27 +1259,25 @@ function finalRedirect(config){
 	c1.schemaName='lists';
 	c1.queryName='crfEntry';
 	c1.filterArray=[LABKEY.Filter.create('entryId',getCRFref(config))];
-	c1.success=function(data){setSubmitStatus(config,data)};
+	c1.success=function(data){uploadData(config,data)};
 	LABKEY.Query.selectRows(c1);
 }
 
-function setSubmitStatus(config,data){
+function uploadData(config,data){
 	let entry=data.rows[0];
 	entry.formStatus=2;//Submitted
+	let el=document.getElementById(config.submitReportId);
+	el.innerHTML="Submitting form";
 	let c1=new Object();
 	c1.schemaName=data.schemaName;
 	c1.queryName=data.queryName;
 	c1.containerPath=config.containerPath;
 	c1.rows=[entry];
-	c1.success=function(data){updateSubmitStatus(config,"Form submitted")};
+	//close window upon success
+	c1.success=function(data){redirect(config)};
 	LABKEY.Query.updateRows(c1);
 }
 
-function updateSubmitStatus(config,msg){
-	let el=document.getElementById(config.submitReportId);
-	el.innerHTML=msg;
-}
-
 function hideErr(config){
 	let el=config.document.getElementById("errorDiv");
 	el.style.display="none";
@@ -1455,54 +1575,114 @@ function afterConfig(config){
 
 	if (debug)
 		print(config,"generateMasterForm");	
+	
+	let selectRows=new Object();
+	selectRows.containerPath=config.containerPath;
+	selectRows.schemaName='lists';
+	selectRows.queryName='crfEntry';
+	selectRows.filterArray=[LABKEY.Filter.create('entryId',getCRFref(config))];
+	
+	let formConfig=new Object();
+	//selectRows.success=function(data){populateBasicData(config,data)};
+	selectRows.success=function(data){afterCrf(config,formConfig,data)};
+	LABKEY.Query.selectRows(selectRows);
+}
 
+//requires populateBasicData
+function afterCrf(config,formConfig,data){
+	formConfig.crfEntry=data.rows[0];
+	//schedule basic data for later
+	populateBasicData(config,data);
 
-	config.document.getElementById('investigatorName').innerHTML=config.formConfig.user['DisplayName'];
-	config.document.getElementById('eudraCTNumber').innerHTML=config.formConfig.crfEntry['EudraCTNumber'];
-	config.document.getElementById('studyCoordinator').innerHTML=config.formConfig.crfEntry['StudyCoordinator'];
-	config.document.getElementById('studySponsor').innerHTML=config.formConfig.crfEntry['StudySponsor'];
-	config.document.getElementById('siteName').innerHTML=config.formConfig.site['siteName'];
-	config.document.getElementById('sitePhone').innerHTML=config.formConfig.site['sitePhone'];
+	let selectRows=new Object();
+	selectRows.containerPath=config.containerPath;
+	selectRows.schemaName='lists';
+	selectRows.queryName='FormStatus';
+	selectRows.filterArray=[];
+	
+	selectRows.success=function(data){afterFormStatus(config,formConfig,data)};
+	LABKEY.Query.selectRows(selectRows);	
 
 
-	for (let i=0;i<config.formConfig.formSetup.rows.length;i++){
-		let entry=config.formConfig.formSetup.rows[i];
-		let queryName=config.formConfig.queryMap[entry['queryName']];
-		let additionalData=new Object();
+	//use crfEntry['FormStatus'] to determine what configuration to display
+	//reviewMode equivalence table:
+	//
+	//FormStatus	reviewMode
+	//In Progress	undefined/EDIT
+	//Review Pending undefined/EDIT
+	//Submitted	REVIEW
+	//Approved	APPROVED
+	
+	//two level indirect - 
+	//
+	//1. learn of the FormStatus options by reading in the FormStatus list
+	//
+	//2. Load the crfEntry for this crfId 
+}
+	
 
-		setAdditionalData(config,additionalData,entry);
+	
+function afterFormStatus(config, formConfig, data){
+	print(config,"afterFormStatus: ");
+	formConfig.formStatusData=data;
+	
+	let rows=formConfig.formStatusData.rows;
 
-		generateSection(config,queryName,entry['title'],queryName,additionalData);
-		print(config,'Running this');
+	for (let i=0; i<rows.length; i++){
+		let key=rows[i].Key;
+		if (formConfig.crfEntry["FormStatus"]!=key)
+			continue;
+		formConfig.formStatus=rows[i].formStatus;
+		break;
 	}
-	//config.fields=new Object();	
-	//config.queryMap=new Object();
-	config.fields=config.formConfig.fields;
-	config.queryMap=config.formConfig.queryMap;
 
-
-	if (debug)
-		print(config,"Generating buttons");
-
-	//requires onSubmit
-	if ("reviewMode" in config){
-		if (config.reviewMode=="REVIEW"){
+	print(config,"Generating buttons for formStatus \""+formStatus+"\"");
+	
+	let done="FALSE";
+	if (formConfig.formStatus=="Submitted"){
+		generateButton(config,"submitDiv","Complete submission",
+			"Upload to database",onDatabaseUpload,config);
+		generateButton(config,"submitDiv","Review submission",
+			"Ask for further review",onUpdateForReview,config);
+		generateButton(config,"submitDiv","Remove submission",
+			"Remove CRF form",onRemoveCRF,config);
+		done="TRUE";
+	}
+	if (formConfig.formStatus=="Approved"){
+		generateButton(config,"submitDiv","Review submission",
+			"Restore form for further review",onUpdateForReview,config);
+		done="TRUE";
+	}
+	if (done=="FALSE"){
+		generateButton(config,"submitDiv","Complete submission",
+			"Submit",onSubmit,config);
+		generateButton(config,"submitDiv","Remove submission",
+			"Remove CRF form",onRemoveCRF,config);
 	
-			generateButton(config,"submitDiv","Complete submission","Upload to database",onDatabaseUpload,config);
-			generateButton(config,"submitDiv","Review submission","Ask for further review",onUpdateForReview,config);
-			generateButton(config,"submitDiv","Remove submission","Remove CRF form",onRemoveCRF,config);
-		}
-		if (config.reviewMode=="APPROVED"){
-			generateButton(config,"submitDiv","Review submission","Restore form for further review",onUpdateForReview,config);
-
-		}
-	}	
-	else{
-		generateButton(config,"submitDiv","Complete submission","Submit",onSubmit,config);
-		generateButton(config,"submitDiv","Remove submission","Remove CRF form",onRemoveCRF,config);
 	}
-	generateButton(config,"submitDiv","Print Form (Experimental)","Print",printForm,config);
+
 	generateButton(config,"submitDiv","Done","Exit",redirect,config);
+	
+	//schedule actual forms
+	config.fields=new Object();	
+	config.queryMap=new Object();
+
+	//data and layout of actual forms
+	//filled in generateTable
+	formConfig.entries=new Object();
+	formConfig.dataFields=new Object();
+
+	let configSelectRows=new Object();
+	configSelectRows.containerPath=config.containerPath;
+	configSelectRows.schemaName='lists';
+	configSelectRows.queryName=config.setupQueryName;
+	//this is new
+	configSelectRows.queryName="FormSetup";
+	configSelectRows.filterArray=[LABKEY.Filter.create("formName",config.formId)];
+
+	configSelectRows.success=function(data){afterFormSetup(config,formConfig,data);};
+	configSelectRows.failure=onFailure;//function(errorTxt){print(config,"generateForm fail" + errorTxt)};
+	LABKEY.Query.selectRows(configSelectRows);
 
 }
 

+ 3 - 2
web/crf/formPortal.js

@@ -401,10 +401,10 @@ function openForm(config,formConfig,crfRef, crfEntry){
 		// The destination wiki page. The name of this parameter is not arbitrary.
 		"userid": crfEntry.UserId, 
 		"entryId": crfRef,
-		"registrationQueryId":formEntry["masterQuery"],
+		"registrationQueryId":"NOT USED",
 		"reviewMode":reviewMode,
 		"formId":formId,
-		"formName":formEntry["formName"]
+		"formName":"NOT USED" 
 	};
 
 	//"formSetupQuery":formEntry["setupQuery"],
@@ -424,6 +424,7 @@ function createForm(config,formConfig,formId){
 	let crfEntry=new Object();
 	crfEntry.entryId=Date.now();
 	crfEntry["Date"]=new Date();
+	crfEntry["View"]="[VIEW]";
 	crfEntry.formStatus=1;//In progress
 	//set other variables
 	//requires studyData as part of formConfig