formPortal.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. //global config variable
  2. const config=new Object();
  3. function print(msg){
  4. config.document.getElementById(config.debugArea).value+="\n"+msg;
  5. }
  6. function clear(){
  7. config.document.getElementById(config.debugArea).value="";
  8. }
  9. function getMode(){
  10. if ("role" in config){
  11. return config.role;
  12. }
  13. return "crfEditor";
  14. }
  15. function doNothing(){
  16. print('doNothing called');
  17. }
  18. function makeQuery(containerName,queryName,fieldName,filterArray){
  19. //queryArray should contain elements with
  20. //- fieldName to set the data variable
  21. //- containerName to select container (data,config,CRF)
  22. //- queryName to select query
  23. //- filterArray to perform filtering, empty array works
  24. //- callback cb to be called with no arguments
  25. let e=new Object();
  26. e.containerName=containerName;
  27. e.queryName=queryName;
  28. e.fieldName=fieldName;
  29. e.filterArray=filterArray;
  30. return e;
  31. }
  32. function getDataFromQueries(queryArray,cb){
  33. afterQuery(new Object(),-1,queryArray,cb);
  34. }
  35. function afterQuery(data,id,queryArray,cb){
  36. print('afterQuery['+id+']: ');
  37. if (id>-1){
  38. let fieldName=queryArray[id].fieldName;
  39. print('afterQuery['+fieldName+']: '+data.rows.length);
  40. //uses config.formConfig
  41. config.formConfig[fieldName]=data;
  42. }
  43. id+=1;
  44. if (id==queryArray.length) {
  45. cb();
  46. return;
  47. }
  48. let e=queryArray[id];
  49. let qconfig=new Object();
  50. qconfig.containerPath=getContainer(e.containerName);
  51. qconfig.schemaName="lists";
  52. if ("schemaName" in e){
  53. print('afterQuery: schemaName='+e.schemaName);
  54. qconfig.schemaName=e.schemaName;
  55. }
  56. if ("columns" in e){
  57. print('afterQuery: columns='+e.columns);
  58. qconfig.columns=e.columns;
  59. }
  60. qconfig.queryName=e.queryName;
  61. //this should point to configuration container
  62. //don't filter -> so we can pick up other forms (say registration) later on
  63. //qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
  64. if ("filterArray" in e)
  65. qconfig.filterArray=e.filterArray;
  66. //qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
  67. qconfig.success=function(data){afterQuery(data,id,queryArray,cb);};
  68. qconfig.failure=doNothing;
  69. LABKEY.Query.selectRows(qconfig);
  70. }
  71. function printMessage(msg){
  72. let txt=config.document.createElement("p");
  73. config.document.getElementById(config.div).appendChild(txt);
  74. txt.innerText=msg;
  75. }
  76. function userName(id){
  77. let formConfig=config.formConfig;
  78. for (let i=0;i<formConfig.users.rows.length;i++){
  79. if (formConfig.users.rows[i].UserId!=id)
  80. continue;
  81. return formConfig.users.rows[i].DisplayName;
  82. }
  83. return "NONE";
  84. }
  85. function setContainer(label,container){
  86. if (!(config.formConfig.hasOwnProperty('container'))){
  87. config.formConfig.container=new Array();
  88. }
  89. config.formConfig.container[label]=container;
  90. }
  91. function getContainer(label){
  92. return config.formConfig.container[label];
  93. }
  94. function generateFormArray(){
  95. print("generateFormArray "+getMode());
  96. config.formConfig=new Object();
  97. config.formConfig.softwareVersion='0.1.7';
  98. //report software version
  99. config.document.getElementById('version').innerText=config.formConfig.softwareVersion;
  100. setContainer('data',LABKEY.ActionURL.getContainer());
  101. setContainer('config',LABKEY.ActionURL.getContainer());
  102. setContainer('CRF',LABKEY.ActionURL.getContainer());
  103. let selectRows=new Object();
  104. //this is local data
  105. selectRows.containerPath=getContainer('CRF');
  106. selectRows.schemaName='lists';
  107. selectRows.queryName='crfSettings';
  108. //store form related data to this object
  109. selectRows.success=afterSettings;
  110. LABKEY.Query.selectRows(selectRows);
  111. }
  112. function afterSettings(data){
  113. config.formConfig.settings=new Array();
  114. for (let i=0;i<data.rows.length;i++){
  115. let n=data.rows[i]['name'];
  116. let v=data.rows[i]['value'];
  117. config.formConfig.settings[n]=v;
  118. }
  119. let st=config.formConfig.settings;
  120. print('afterSettings');
  121. for (let k in st){
  122. print('\t'+k+'='+st[k]);
  123. }
  124. //if ('dataContainer' in st){
  125. // setContainer('data',st['dataContainer']);
  126. //}
  127. let vname='configContainer';
  128. if (vname in st){
  129. setContainer('config',st[vname]);
  130. }
  131. print('Config: '+getContainer('config'));
  132. print('Data: '+getContainer('data'));
  133. //setup queryArray
  134. let queryArray=new Array();
  135. //Forms
  136. queryArray.push(makeQuery('config','Forms','dataForms',[]));
  137. //users
  138. queryArray.push(makeQuery('data','users','users',[]));
  139. queryArray[queryArray.length-1].schemaName='core';
  140. //inputLists
  141. queryArray.push(makeQuery('config','inputLists','inputLists',[]));
  142. //studyData
  143. queryArray.push(makeQuery('data','StudyProperties','studyData',[]));
  144. let e=queryArray[queryArray.length-1];
  145. e.schemaName='study';
  146. e.columns="StudySponsor,StudyCoordinator,EudraCTNumber";
  147. e.columns+=',RegulatoryNumber,SubjectColumnName';
  148. //crfEditors
  149. queryArray.push(makeQuery('config','crfEditors','crfEditors',[]));
  150. //crfMonitors
  151. queryArray.push(makeQuery('config','crfMonitors','crfMonitors',[]));
  152. //crfSponsors
  153. queryArray.push(makeQuery('config','crfSponsors','crfSponsors',[]));
  154. //FormStatus
  155. queryArray.push(makeQuery('config','FormStatus','formStatusg',[]));
  156. //site
  157. queryArray.push(makeQuery('config','site','siteData',[]));
  158. //crfEntry
  159. queryArray.push(makeQuery('data','crfEntry','crfEntries',[]));
  160. getDataFromQueries(queryArray,fcontinue);
  161. }
  162. function fcontinue(){
  163. let formConfig=config.formConfig;
  164. print("Number of study data entries: "+formConfig.studyData.rows.length);
  165. print("ParticipantId: "+formConfig.studyData.rows[0].SubjectColumnName);
  166. let qconfig=new Object();
  167. qconfig.containerPath=getContainer('data');
  168. qconfig.schemaName="study";
  169. let demographicDataId=formConfig.dataForms.rows[0].masterQuery;
  170. let demographicDataQuery="NONE";
  171. for (let i=0;i<formConfig.inputLists.rows.length;i++){
  172. let entry=formConfig.inputLists.rows[i];
  173. print("inputList ["+i+"] ["+entry.Key+"] "+entry.queryName);
  174. if (entry.Key==demographicDataId){
  175. demographicDataQuery=entry.queryName;
  176. break;
  177. }
  178. }
  179. print('Setting demographic query to '+demographicDataQuery);
  180. qconfig.queryName=demographicDataQuery;
  181. //qconfig.queryName="demographicData";
  182. qconfig.success=afterPopulatingDemographicData;
  183. LABKEY.Query.selectRows(qconfig);
  184. }
  185. function afterPopulatingDemographicData(data){
  186. let formConfig=config.formConfig;
  187. formConfig.demographicData=data;
  188. print("afterPopulatingDemographic");
  189. print("Number of patients: "+formConfig.demographicData.rows.length);
  190. fcontinue2();
  191. }
  192. function fcontinue2(){
  193. let formConfig=config.formConfig;
  194. let dataForms=formConfig.dataForms.rows;
  195. formConfig.table=config.document.createElement("table");
  196. config.document.getElementById(config.div).appendChild(formConfig.table);
  197. let accessModeColumn=getMode()+'Status';
  198. print('accessModeColumn '+accessModeColumn);
  199. let creatorModeColumn=getMode()+'Creator';
  200. //switch from status based to form based access
  201. print("Forms: "+dataForms.length);
  202. print("Entries: "+formConfig.crfEntries.rows.length);
  203. let fEntries=formConfig.crfEntries.rows;
  204. let users=formConfig.users.rows;
  205. let currentUserId=LABKEY.Security.currentUser.id;
  206. let currentUser=undefined;
  207. for (let i=0;i<users.length;i++){
  208. if (users[i].UserId!=currentUserId) continue;
  209. currentUser=users[i];
  210. }
  211. let fList=config.role+'s';
  212. let fRows=config.formConfig[fList].rows;
  213. //current user must be in the list
  214. //
  215. let currentUserRoles=new Array();
  216. //the same user can act for multiple sites
  217. for (let i=0;i<fRows.length;i++){
  218. if (fRows[i].User!=currentUser.UserId) continue;
  219. currentUserRoles.push(fRows[i]);
  220. }
  221. if (currentUserRoles.length==0){
  222. printMessage('User '+currentUser.DisplayName+" can't act as "+config.role);
  223. return;
  224. }
  225. let currentSites=new Array();
  226. let siteRows=config.formConfig.siteData.rows;
  227. for (let i=0;i<siteRows.length;i++){
  228. for (let j=0;j<currentUserRoles.length;j++){
  229. if (siteRows[i].siteNumber!=currentUserRoles[j].Site) continue;
  230. currentSites.push(siteRows[i]);
  231. }
  232. }
  233. let msg='User '+currentUser.DisplayName+' acting as '+config.role+' for (';
  234. for (let i=0;i<currentSites.length;i++){
  235. if (i>0) msg+=', ';
  236. msg+=currentSites[i].siteName;
  237. }
  238. msg+=')';
  239. printMessage(msg);
  240. for (let i=0;i<dataForms.length;i++){
  241. let qForm=dataForms[i];
  242. let formKey=qForm.Key;
  243. //figure out master query name
  244. let masterQuery="NONE";
  245. let mID=qForm.masterQuery;
  246. for (let i2=0;i2<formConfig.inputLists.rows.length;i2++){
  247. //queryName
  248. if (formConfig.inputLists.rows[i2].Key!=mID)
  249. continue;
  250. masterQuery=formConfig.inputLists.rows[i2].queryName;
  251. print("Setting master query "+masterQuery);
  252. break;
  253. }
  254. //add row for each form
  255. let row=formConfig.table.insertRow(i);
  256. let formName=qForm.formName;
  257. print("["+i+"/"+formKey+']: '+formName);
  258. let k=0;
  259. let formStatus=qForm[accessModeColumn];
  260. print('target formStatus '+formStatus);
  261. for (let j=0;j<fEntries.length;j++){
  262. let entry=fEntries[j];
  263. let formId=entry.Form;
  264. //print("Row["+j+"] formId: "+formId);
  265. if (formId!=formKey)
  266. continue;
  267. //should we consider this form
  268. if (entry.FormStatus!=formStatus){
  269. //print('Form status mismatch :'+entry.FormStatus);
  270. continue;
  271. }
  272. print('Candidate '+entry.entryId);
  273. //TODO: smart filter on user (now we get to see all)
  274. //
  275. //for editors
  276. if (config.role=='crfEditor' && entry.UserId!=currentUser.UserId){
  277. print('Skipping identity mismatch: '+entry.UserId+'/'+currentUser.UserId);
  278. continue;
  279. }
  280. let matchingSite=-1;
  281. let potentialSiteNumbers="[";
  282. for (let k=0;k<currentSites.length;k++){
  283. if (k>0) potentialSiteNumbers+=',';
  284. potentialSiteNumbers+=currentSites[k].siteNumber;
  285. if (entry.Site!=currentSites[k].siteNumber) continue;
  286. matchingSite=currentSites[k].siteNumber;
  287. break;
  288. }
  289. potentialSiteNumbers+=']';
  290. if (matchingSite==-1){
  291. print('Skipping wrong site: '+entry.Site+'/'+potentialSiteNumbers);
  292. continue;
  293. }
  294. //insert form
  295. //
  296. let fbox=config.document.createElement("div");
  297. fbox.classList.add("box","gold");
  298. let fp=config.document.createElement("p");
  299. let id=entry.entryId;
  300. fp.innerHTML=id;
  301. //it would be great if this were patientId if available
  302. //fp.classList.add("large","center");
  303. fp.classList.add("center");
  304. fbox.appendChild(fp);
  305. let fp1=config.document.createElement("p");
  306. let user="NONE";
  307. for (let ii=0;ii<users.length;ii++){
  308. if (users[ii].UserId!=entry.UserId)
  309. continue;
  310. user=users[ii].DisplayName;
  311. break;
  312. }
  313. fp1.innerHTML=user;
  314. fp1.classList.add("center");
  315. fbox.appendChild(fp1);
  316. let fp2=config.document.createElement("p");
  317. fp2.innerHTML=formName;
  318. fp2.classList.add("center");
  319. fbox.appendChild(fp2);
  320. let fp3=config.document.createElement("p");
  321. fp3.id="pid"+id;
  322. fp3.innerHTML="NONE";
  323. print('Setting participant id from query: '+masterQuery);
  324. if (masterQuery!="NONE"){
  325. let qconfig=new Object();
  326. qconfig.schemaName='lists';
  327. qconfig.queryName=masterQuery;
  328. qconfig.filterArray=[LABKEY.Filter.create('crfRef',id)];
  329. qconfig.success=function(data){setPatientId(data,fp3.id);}
  330. LABKEY.Query.selectRows(qconfig);
  331. }
  332. fp3.classList.add("center");
  333. fbox.appendChild(fp3);
  334. let cell=row.insertCell(k);
  335. cell.classList.add("stretch");
  336. cell.id="box"+entry.crfRef;
  337. let button=config.document.createElement("button");
  338. button.appendChild(fbox);
  339. button.onclick=function(){openForm(entry)};
  340. cell.appendChild(button);
  341. k++;
  342. }
  343. print('finished checking existing forms');
  344. //only those that are allowed to create formsa
  345. if (qForm[creatorModeColumn]!='TRUE') continue;
  346. let fbox=config.document.createElement("div");
  347. fbox.classList.add("box","red");
  348. let fp=config.document.createElement("p");
  349. fp.innerHTML="Create new";
  350. fbox.appendChild(fp);
  351. let fp2=config.document.createElement("p");
  352. fp2.innerHTML=formName;
  353. fp2.classList.add("center");
  354. fbox.appendChild(fp2);
  355. let cell=row.insertCell(k);
  356. cell.classList.add("stretch");
  357. let button=config.document.createElement("button");
  358. button.appendChild(fbox);
  359. button.onclick=function(){createForm(formKey)};
  360. cell.appendChild(button);
  361. }
  362. }
  363. function setPatientId(data,id){
  364. let formConfig=config.formConfig;
  365. if (data.rows.length==0) return;
  366. //every masterQuery must have participantCode
  367. let participantCode=data.rows[0].participantCode;
  368. let participantField=formConfig.studyData.rows[0].SubjectColumnName;
  369. print('setPatientId: '+data.queryName);
  370. print('participantCode: '+participantCode);
  371. print('participantField: '+participantField);
  372. //equates to registration
  373. for (let i=0;i<formConfig.demographicData.rows.length;i++){
  374. let entry=formConfig.demographicData.rows[i];
  375. let key=entry.lsid;
  376. print('Comparing to: '+key);
  377. if (key!=participantCode) continue;
  378. print('Setting: ');
  379. let participantId=entry[participantField];
  380. config.document.getElementById(id).innerHTML=participantId;
  381. break;
  382. }
  383. }
  384. function openForm(crfEntry){
  385. let formConfig=config.formConfig;
  386. let crfRef=crfEntry.entryId;
  387. print("Clicked for "+crfRef);
  388. let formId=crfEntry.Form;
  389. for (let i=0;i<formConfig.dataForms.rows.length;i++){
  390. if (formConfig.dataForms.rows[i].Key!=formId) continue;
  391. print("Setting form "+formConfig.dataForms.rows[i].formName);
  392. formEntry=formConfig.dataForms.rows[i];
  393. break;
  394. }
  395. if (formEntry==undefined) return;
  396. //select between review and view
  397. //let formUrl=formEntry["formUrl"];
  398. //if ("reviewMode" in config) formUrl=formEntry["reviewFormUrl"];
  399. //print("Setting url "+formUrl);
  400. //direct all to the same html
  401. let formUrl="visit";
  402. reviewMode="EDIT";
  403. if ("reviewMode" in config) reviewMode=config.reviewMode;
  404. let params = {
  405. "name": formUrl,
  406. // The destination wiki page. The name of this parameter is not arbitrary.
  407. "entryId": crfRef,
  408. "formId":formId,
  409. "role" : config.role
  410. };
  411. //"formSetupQuery":formEntry["setupQuery"],
  412. let containerPath= LABKEY.ActionURL.getContainer();
  413. // This changes the page after building the URL.
  414. //Note that the wiki page destination name is set in params.
  415. var wikiURL = LABKEY.ActionURL.buildURL("crf", formUrl , containerPath, params);
  416. print("Redirecting to "+wikiURL);
  417. window.location = wikiURL;
  418. }
  419. function createForm(formId){
  420. let formConfig=config.formConfig;
  421. print("Create form w/id "+formId);
  422. let crfEntry=new Object();
  423. crfEntry.entryId=Date.now();
  424. crfEntry["Date"]=new Date();
  425. crfEntry["View"]="[VIEW]";
  426. crfEntry.formStatus=1;//In progress
  427. //set other variables
  428. //requires studyData as part of formConfig
  429. let studyData=formConfig.studyData.rows[0];
  430. crfEntry.EudraCTNumber=studyData.EudraCTNumber;
  431. crfEntry.StudyCoordinator=studyData.StudyCoordinator;
  432. crfEntry.StudySponsor=studyData.StudySponsor;
  433. crfEntry.RegulatoryNumber=studyData.RegulatoryNumber;
  434. crfEntry.UserId=LABKEY.Security.currentUser.id;
  435. //requires crfEditors as part of formConfig
  436. for (let i=0;i<formConfig.crfEditors.rows.length;i++){
  437. print("Checking user "+formConfig.crfEditors.rows[i].User);
  438. if (formConfig.crfEditors.rows[i].User!=crfEntry.UserId) continue;
  439. print("Found user");
  440. crfEntry.Site=formConfig.crfEditors.rows[i].Site;
  441. print("Setting site to id="+crfEntry.Site);
  442. break;
  443. }
  444. //from argument list
  445. crfEntry.Form=formId;
  446. let qconfig=new Object();
  447. qconfig.containerPath=getContainer('data');
  448. qconfig.schemaName='lists';
  449. qconfig.queryName='crfEntry';
  450. qconfig.success=function(data){openForm(crfEntry)};
  451. qconfig.rows=[crfEntry];
  452. LABKEY.Query.insertRows(qconfig);
  453. }