formPortal.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. var formPortal={};
  2. //global config variable
  3. formPortal.config=new Object();
  4. formPortal.setDebug=
  5. function(debug=null){
  6. if (debug){
  7. this.print=function(msg){debug.print(msg);};
  8. this.clear=function(){debug.clear();}
  9. return;
  10. }
  11. //provide default functions if not debug object is available
  12. this.print=function(msg){console.log(msg);}
  13. this.clear=function(){;}
  14. }
  15. formPortal.setDebug();
  16. formPortal.getMode=
  17. function(){
  18. if ("role" in this.config){
  19. return this.config.role;
  20. }
  21. return "crfEditor";
  22. }
  23. formPortal.doNothing=
  24. function(){
  25. this.print('doNothing called');
  26. }
  27. //load runQuery.js
  28. formPortal.printMessage=
  29. function(msg){
  30. let txt=this.config.document.createElement("p");
  31. this.config.document.getElementById(this.config.div).appendChild(txt);
  32. txt.innerText=msg;
  33. }
  34. formPortal.userName=
  35. function(id){
  36. let formConfig=this.config.formConfig;
  37. for (let i=0;i<formConfig.users.rows.length;i++){
  38. if (formConfig.users.rows[i].UserId!=id)
  39. continue;
  40. return formConfig.users.rows[i].DisplayName;
  41. }
  42. return "NONE";
  43. }
  44. formPortal.setContainer=
  45. function(label,container){
  46. let config=this.config;
  47. if (!(config.formConfig.hasOwnProperty('container'))){
  48. config.formConfig.container=new Array();
  49. }
  50. config.formConfig.container[label]=container;
  51. }
  52. formPortal.getContainer=
  53. function(label){
  54. return this.config.formConfig.container[label];
  55. }
  56. formPortal.init=
  57. function(cb=null){
  58. let that=this;
  59. let action=function(){that.scriptsLoaded(cb);};
  60. LABKEY.Utils.requiresScript(["crfTecant/runQuery.js","crfTecant/formGenerator.js","crfTecant/variableList.js"],action);
  61. }
  62. formPortal.scriptsLoaded=
  63. function(cb=null){
  64. formGenerator.set(this);
  65. if (cb) cb();
  66. }
  67. formPortal.generateFormArray=
  68. function(){
  69. let that=this;
  70. let action=function(){that.fcontinue0();};
  71. this.init(action);
  72. }
  73. formPortal.fcontinue0=
  74. function(){
  75. this.print("generateFormArray "+this.getMode());
  76. let config=this.config;
  77. config.formConfig=new Object();
  78. config.formConfig.softwareVersion='T.2.01'; //report software version
  79. //report software version
  80. config.document.getElementById('version').innerText=config.formConfig.softwareVersion;
  81. this.setContainer('data',LABKEY.ActionURL.getContainer());
  82. this.setContainer('config',LABKEY.ActionURL.getContainer());
  83. this.setContainer('CRF',LABKEY.ActionURL.getContainer());
  84. let selectRows=new Object();
  85. //this is local data
  86. selectRows.containerPath=this.getContainer('CRF');
  87. selectRows.schemaName='lists';
  88. selectRows.queryName='crfSettings';
  89. //store form related data to this object
  90. let that=this;
  91. selectRows.success=function(data){that.afterSettings(data);};
  92. LABKEY.Query.selectRows(selectRows);
  93. }
  94. formPortal.afterSettings=
  95. function(data){
  96. let fName="[afterSettings]";
  97. let config=this.config;
  98. config.formConfig.settings=new Array();
  99. for (let i=0;i<data.rows.length;i++){
  100. let n=data.rows[i]['name'];
  101. let v=data.rows[i]['value'];
  102. config.formConfig.settings[n]=v;
  103. }
  104. let st=config.formConfig.settings;
  105. this.print(fName);
  106. for (let k in st){
  107. this.print(fName+'\t'+k+'='+st[k]);
  108. }
  109. //if ('dataContainer' in st){
  110. // setContainer('data',st['dataContainer']);
  111. //}
  112. let vname='configContainer';
  113. if (vname in st){
  114. this.setContainer('config',st[vname]);
  115. }
  116. this.print(fName+' config: '+this.getContainer('config'));
  117. this.print(fName+' data: '+this.getContainer('data'));
  118. //setup queryArray
  119. let queryArray=new Array();
  120. //targetObject
  121. let targetObject=config.formConfig;
  122. //static variables
  123. queryArray.push(runQuery.makeQuery(targetObject,'data','crfStaticVariables','crfStaticVariables',[]));
  124. //Forms
  125. queryArray.push(runQuery.makeQuery(targetObject,'config','Forms','dataForms',[]));
  126. //users
  127. queryArray.push(runQuery.makeQuery(targetObject,'data','users','users',[]));
  128. queryArray[queryArray.length-1].schemaName='core';
  129. //inputLists
  130. queryArray.push(runQuery.makeQuery(targetObject,'config','inputLists','inputLists',[]));
  131. //crfEditors
  132. queryArray.push(runQuery.makeQuery(targetObject,'config','crfEditors','crfEditors',[]));
  133. //crfMonitors
  134. queryArray.push(runQuery.makeQuery(targetObject,'config','crfMonitors','crfMonitors',[]));
  135. //crfSponsors
  136. queryArray.push(runQuery.makeQuery(targetObject,'config','crfSponsors','crfSponsors',[]));
  137. //crfManagers
  138. queryArray.push(runQuery.makeQuery(targetObject,'config','crfManagers','crfManagers',[]));
  139. //FormStatus
  140. queryArray.push(runQuery.makeQuery(targetObject,'config','FormStatus','formStatusg',[]));
  141. //site
  142. queryArray.push(runQuery.makeQuery(targetObject,'config','site','siteData',[]));
  143. //crfEntry
  144. queryArray.push(runQuery.makeQuery(targetObject,'data','crfEntry','crfEntries',[]));
  145. queryArray.push(
  146. runQuery.makeQuery(targetObject,'config','generateConfig','generateConfigData',[]));
  147. let that=this;
  148. let action=function(){that.addStudyData();};
  149. runQuery.getDataFromQueries(this,queryArray,action);
  150. //getDataFromQueries(queryArray,fcontinue);
  151. }
  152. formPortal.addStudyData=
  153. function(){
  154. let config=this.config;
  155. //setup queryArray
  156. let queryArray=new Array();
  157. let targetObject=config.formConfig;
  158. queryArray.push(runQuery.makeQuery(targetObject,'data','StudyProperties','studyData',[]));
  159. let e=queryArray[queryArray.length-1];
  160. e.schemaName='study';
  161. let columnModel="";
  162. let varRows=config.formConfig['crfStaticVariables'].rows;
  163. for (let i=0;i<varRows.length;i++){
  164. if (i>0) columnModel+=',';
  165. columnModel+=varRows[i]['staticVariable'];
  166. }
  167. e.columns=columnModel;
  168. let that=this;
  169. let action=function(){that.fcontinue();};
  170. runQuery.getDataFromQueries(this,queryArray,action);
  171. }
  172. formPortal.filterEntry=
  173. function(entry,filter,settings){
  174. let fName="[filterEntry]";
  175. if (entry.Form!=filter.form)
  176. return false;
  177. //only select forms where status matches the target status
  178. if (entry.FormStatus!=filter.formStatus){
  179. //check for additionalStates
  180. let addStates=filter.additionalVisibilityStates[filter.role];
  181. this.print(fName+' addState['+filter.role+'/'+entry.FormStatus+'] '+addStates);
  182. if (!addStates) return false;
  183. let ar=addStates.split(',');
  184. this.print(fName+" ar "+ar.length);
  185. let v=String(entry.FormStatus);
  186. if (!(ar.includes(v))) return false;
  187. this.print(fName+" allowed for state "+entry.FormStatus);
  188. }
  189. this.print(fName+' candidate '+entry.entryId);
  190. //TODO: smart filter on user (now we get to see all)
  191. //
  192. //for editors
  193. if ("filterUser" in settings && filter.role=='crfEditor' && entry.UserId!=filter.userId){
  194. this.print(fName+' skipping identity mismatch: '+entry.UserId+'/'+filter.userId);
  195. return false;
  196. }
  197. //for others
  198. let matchingSite=-1;
  199. let potentialSiteNumbers="[";
  200. for (let k=0;k<filter.sites.length;k++){
  201. if (k>0) potentialSiteNumbers+=',';
  202. potentialSiteNumbers+=filter.sites[k].siteNumber;
  203. //skip mismatching sites
  204. if (entry.Site!=filter.sites[k].siteNumber) continue;
  205. matchingSite=filter.sites[k].siteNumber;
  206. break;
  207. }
  208. potentialSiteNumbers+=']';
  209. if (matchingSite==-1){
  210. this.print(fName+' skipping wrong site: '+entry.Site+'/'+potentialSiteNumbers);
  211. return false;
  212. }
  213. return true;
  214. }
  215. formPortal.fcontinue=
  216. function(){
  217. let fName='[fcontinue]';
  218. let config=this.config;
  219. let formConfig=config.formConfig;
  220. this.print(fName+" number of study data entries: "+formConfig.studyData.rows.length);
  221. this.print(fName+" participantId: "+formConfig.studyData.rows[0].SubjectColumnName);
  222. let dataForms=formConfig.dataForms.rows;
  223. formConfig.table=config.document.createElement("table");
  224. config.document.getElementById(config.div).appendChild(formConfig.table);
  225. let accessModeColumn=this.getMode()+'Status';
  226. this.print(fName+' accessModeColumn '+accessModeColumn);
  227. //cutting down on number of fields
  228. //let creatorModeColumn=getMode()+'Creator';
  229. //switch from status based to form based access
  230. this.print(fName+" forms: "+dataForms.length);
  231. this.print(fName+" entries: "+formConfig.crfEntries.rows.length);
  232. let fEntries=formConfig.crfEntries.rows;
  233. let users=formConfig.users.rows;
  234. let currentUserId=LABKEY.Security.currentUser.id;
  235. let currentUser=undefined;
  236. for (let i=0;i<users.length;i++){
  237. if (users[i].UserId!=currentUserId) continue;
  238. currentUser=users[i];
  239. }
  240. //determine the role filter
  241. let fList=config.role+'s';
  242. //check for users that fit the role,
  243. //fRows lists all users for role
  244. let fRows=config.formConfig[fList].rows;
  245. this.print(fName+' candidates: '+fRows.length)
  246. //current user must be in the list
  247. let currentUserRoles=new Array();
  248. //the same user can act for multiple sites
  249. for (let i=0;i<fRows.length;i++){
  250. if (fRows[i].User!=currentUser.UserId) continue;
  251. currentUserRoles.push(fRows[i]);
  252. }
  253. //cludge for public sites where all users can act as anything
  254. let sts=config.formConfig.settings;
  255. let vName='allowAllForSite';
  256. if (vName in sts){
  257. let tempUserRole=new Object();
  258. tempUserRole.User=currentUser.UserId;
  259. tempUserRole.Site=parseInt(sts[vName]);
  260. currentUserRoles.push(tempUserRole);
  261. }
  262. //currentUser was not matched in fRows
  263. if (currentUserRoles.length==0){
  264. this.printMessage('User '+currentUser.DisplayName+" can't act as "+config.role);
  265. return;
  266. }
  267. //currentUser should be also attached to the site of the document
  268. let currentSites=new Array();
  269. let siteRows=config.formConfig.siteData.rows;
  270. for (let i=0;i<siteRows.length;i++){
  271. for (let j=0;j<currentUserRoles.length;j++){
  272. if (siteRows[i].siteNumber!=currentUserRoles[j].Site) continue;
  273. currentSites.push(siteRows[i]);
  274. }
  275. }
  276. config.formConfig.currentSites=currentSites;
  277. let msg='User '+currentUser.DisplayName+' acting as '+config.role+' for (';
  278. for (let i=0;i<currentSites.length;i++){
  279. if (i>0) msg+=', ';
  280. msg+=currentSites[i].siteName;
  281. }
  282. msg+=')';
  283. this.printMessage(msg);
  284. let filter=new Object();
  285. filter.role=config.role;
  286. filter.userId=currentUser.UserId;
  287. filter.sites=currentSites;
  288. //make a formStatus map
  289. let formStatusMap=new Object();
  290. this.print(fName+' formStatusMap: '+config.formConfig.formStatusg.rows.length);
  291. for (let i=0;i<config.formConfig.formStatusg.rows.length;i++){
  292. let fs=config.formConfig.formStatusg.rows[i];
  293. let s=fs['Key'];
  294. formStatusMap[s]=fs;
  295. this.print(fName+' formStatusMap adding '+s);
  296. }
  297. this.print(fName+' formStatusMap '+Object.keys(formStatusMap).length+'/'+config.formConfig.formStatusg.rows.length);
  298. //browse through forms
  299. for (let i=0;i<dataForms.length;i++){
  300. //dataForms is Forms
  301. let qForm=dataForms[i];
  302. let formKey=qForm.Key;
  303. filter.form=qForm.Key;
  304. //add row for each form
  305. let row=formConfig.table.insertRow(i);
  306. let formName=qForm.formName;
  307. this.print(fName+" ["+i+"/"+formKey+']: '+formName);
  308. //column counter
  309. let k=0;
  310. //get the target status
  311. let formStatus=qForm[accessModeColumn];
  312. filter.formStatus=qForm[accessModeColumn];
  313. this.print(fName+' target formStatus '+formStatus);
  314. filter.additionalVisibilityStates=new Object();
  315. let as=qForm["additionalVisibilityStates"];
  316. if (as){
  317. filter.additionalVisibilityStates=variableList.parseVariables(as);
  318. }
  319. for (let j=0;j<fEntries.length;j++){
  320. let entry=fEntries[j];
  321. if (!this.filterEntry(entry,filter,config.formConfig.settings))
  322. continue;
  323. //insert form
  324. //
  325. let fbox=config.document.createElement("div");
  326. let color='gold';
  327. this.print(fName+' status '+entry.FormStatus+' obj '+formStatusMap[entry.FormStatus]);
  328. if (formStatusMap[entry.FormStatus]){
  329. let c=formStatusMap[entry.FormStatus]['color'];
  330. if (c) color=c;
  331. this.print(fName+' status '+entry.FormStatus+' color '+c);
  332. }
  333. fbox.classList.add("box",color);
  334. let fp=config.document.createElement("p");
  335. let id=entry.entryId;
  336. fp.innerHTML=id;
  337. //it would be great if this were patientId if available
  338. //fp.classList.add("large","center");
  339. fp.classList.add("center");
  340. fbox.appendChild(fp);
  341. let fp1=config.document.createElement("p");
  342. let user="NONE";
  343. for (let ii=0;ii<users.length;ii++){
  344. if (users[ii].UserId!=entry.UserId)
  345. continue;
  346. user=users[ii].DisplayName;
  347. break;
  348. }
  349. fp1.innerHTML=user;
  350. fp1.classList.add("center");
  351. fbox.appendChild(fp1);
  352. let fp2=config.document.createElement("p");
  353. fp2.innerHTML=formName;
  354. fp2.classList.add("center");
  355. fbox.appendChild(fp2);
  356. let fp3=config.document.createElement("p");
  357. fp3.id="pid"+id;
  358. let pid=entry['participantStudyId'];
  359. let loc=entry['participantLocalId'];
  360. let label='';
  361. if (pid) label+=pid+' ';
  362. if (loc) label+='(Local: '+loc+')';
  363. if (label.length==0) label="NONE";
  364. fp3.innerHTML=label;
  365. fp3.classList.add("center");
  366. fbox.appendChild(fp3);
  367. let cell=row.insertCell(k);
  368. cell.classList.add("stretch");
  369. cell.id="box"+entry.crfRef;
  370. let button=config.document.createElement("button");
  371. button.appendChild(fbox);
  372. let that=this;
  373. button.onclick=function(){that.openForm(entry)};
  374. cell.appendChild(button);
  375. k++;
  376. }
  377. this.print(fName+' finished checking existing forms');
  378. //only those that are allowed to create forms
  379. //print('Status: '+qForm[creatorModeColumn]);
  380. let creator=qForm['creator'];
  381. if (!creator) continue;
  382. if (creator!=this.getMode()) continue;
  383. //if (qForm[creatorModeColumn]!='TRUE') continue;
  384. let fbox=config.document.createElement("div");
  385. fbox.classList.add("box","red");
  386. let fp=config.document.createElement("p");
  387. fp.innerHTML="Create new";
  388. fbox.appendChild(fp);
  389. let fp2=config.document.createElement("p");
  390. fp2.innerHTML=formName;
  391. fp2.classList.add("center");
  392. fbox.appendChild(fp2);
  393. let cell=row.insertCell(k);
  394. cell.classList.add("stretch");
  395. let button=config.document.createElement("button");
  396. button.appendChild(fbox);
  397. let that=this;
  398. button.onclick=function(){that.createForm(formKey)};
  399. cell.appendChild(button);
  400. }
  401. if (config.role=='crfManager')
  402. this.print('Skipping form generator');
  403. //need formGenerator.js
  404. //formGenerator.addFormGenerator(this);
  405. }
  406. formPortal.openForm=
  407. function(crfEntry){
  408. let fName="[openForm]";
  409. let config=this.config;
  410. let formConfig=config.formConfig;
  411. let crfRef=crfEntry.entryId;
  412. this.print(fName+" clicked for "+crfRef);
  413. let formId=crfEntry.Form;
  414. for (let i=0;i<formConfig.dataForms.rows.length;i++){
  415. if (formConfig.dataForms.rows[i].Key!=formId) continue;
  416. this.print(fName+" setting form "+formConfig.dataForms.rows[i].formName);
  417. formEntry=formConfig.dataForms.rows[i];
  418. break;
  419. }
  420. if (formEntry==undefined) return;
  421. //select between review and view
  422. //let formUrl=formEntry["formUrl"];
  423. //if ("reviewMode" in config) formUrl=formEntry["reviewFormUrl"];
  424. //print("Setting url "+formUrl);
  425. //direct all to the same html
  426. let formUrl="visit";
  427. reviewMode="EDIT";
  428. if ("reviewMode" in config) reviewMode=config.reviewMode;
  429. let params = {
  430. "name": formUrl,
  431. // The destination wiki page. The name of this parameter is not arbitrary.
  432. "entryId": crfRef,
  433. "formId":formId,
  434. "role" : config.role
  435. };
  436. //"formSetupQuery":formEntry["setupQuery"],
  437. let containerPath= LABKEY.ActionURL.getContainer();
  438. // This changes the page after building the URL.
  439. //Note that the wiki page destination name is set in params.
  440. var wikiURL = LABKEY.ActionURL.buildURL("crf_tecant", formUrl , containerPath, params);
  441. this.print(fName+" redirecting to "+wikiURL);
  442. window.location = wikiURL;
  443. }
  444. formPortal.createForm=
  445. function(formId){
  446. let fName="[createForm]";
  447. let config=this.config;
  448. let formConfig=config.formConfig;
  449. let dataForms=formConfig.dataForms.rows;
  450. let qForm=null;
  451. for (let i=0;i<dataForms.length;i++){
  452. if (dataForms[i].Key==formId){
  453. qForm=dataForms[i];
  454. break;
  455. }
  456. }
  457. this.print(fName+" create form w/id "+formId);
  458. let crfEntry=new Object();
  459. crfEntry.entryId=Date.now();
  460. crfEntry["Date"]=new Date();
  461. crfEntry["View"]="[VIEW]";
  462. crfEntry.FormStatus=qForm["initialStatus"];//In progress
  463. this.print(fName+" setting status to "+crfEntry.FormStatus);
  464. //set other variables
  465. //requires studyData as part of formConfig
  466. let studyData=formConfig.studyData.rows[0];
  467. let varRows=formConfig['crfStaticVariables'].rows;
  468. for (let i=0;i<varRows.length;i++){
  469. let varName=varRows[i].staticVariable;
  470. crfEntry[varName]=studyData[varName];
  471. }
  472. crfEntry.UserId=LABKEY.Security.currentUser.id;
  473. crfEntry.Site=config.formConfig.currentSites[0].siteNumber;
  474. this.print(fName+" setting site to id="+crfEntry.Site);
  475. //from argument list
  476. crfEntry.Form=formId;
  477. let crfStatus=new Object();
  478. crfStatus.entryId=crfEntry.entryId;
  479. crfStatus.submissionDate=new Date();
  480. crfStatus.FormStatus=crfEntry.FormStatus;
  481. crfStatus.User=crfEntry.UserId;
  482. crfStatus.Form=crfEntry.Form;
  483. crfStatus.operator=config.role;
  484. crfStatus.action='createForm';
  485. let that=this;
  486. let cb=function(data){that.openForm(crfEntry);};
  487. //this is for debug
  488. //let cb=function(data){;};
  489. let containerPath=this.getContainer('data');
  490. let pass=function(data){formGenerator.insertRow('lists','crfStatus',crfStatus,cb,containerPath);};
  491. formGenerator.insertRow('lists','crfEntry',crfEntry,pass,this.getContainer('data'));
  492. }