From 27e070119687e382be5ed5ec23eeb4762aa5ced2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Todor=20Kondi=C4=87?= <todor.kondic@uni.lu>
Date: Sat, 18 Jun 2022 22:33:11 +0200
Subject: [PATCH] web interface: Adapted to project/data input organisation.

---
 NAMESPACE         |   1 +
 R/api.R           |  23 ++++++-
 R/mix.R           |  12 ++--
 R/shiny-ui-base.R | 166 ++++++++++++++++++++++++++--------------------
 inst/rmd/app.Rmd  |  35 +++++-----
 5 files changed, 142 insertions(+), 95 deletions(-)

diff --git a/NAMESPACE b/NAMESPACE
index 915ee97..7032fc1 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -23,6 +23,7 @@ export(merge2rev)
 export(mk_comp_tab)
 export(mk_tol_funcs)
 export(mz_input)
+export(new_empty_project)
 export(new_project)
 export(new_rv_state)
 export(new_state)
diff --git a/R/api.R b/R/api.R
index a3f7260..a03cfa7 100644
--- a/R/api.R
+++ b/R/api.R
@@ -22,6 +22,21 @@ new_state <- function() {
 ##' @export
 new_rv_state <- function() react_v(m=list2rev(new_state()))
 
+
+
+##' @export
+new_empty_project <- function(project) {
+    m <- new_state()
+    if (!is.character(project)) stop("Argument `project' must be a character string.")
+    if (!dir.exists(project)) stop('Project directory either does not exist, or is unreadable.')
+    project_path <- normalizePath(project)
+    project <- basename(project)
+    m$conf <- list()
+    m$conf$project <- project
+    m$conf$paths$project <- project_path
+    m$conf$paths$data <- m$conf$paths$project
+    m
+}
 ##' @export
 new_project <- function(project) {
     m <- new_state()
@@ -103,6 +118,7 @@ run <- function(project="",m=NULL,phases=NULL,help=F) {
 
 ##' @export
 setup_phase <- function(m) {
+    message("Stage: setup")
     m <- mk_tol_funcs(m)
     m <- load_inputs(m)
     m <- concurrency(m)
@@ -198,6 +214,8 @@ load_inputs <- function(m) {
 
 ##' @export
 mk_comp_tab <- function(m) {
+    message("Stage: comptab")
+
     setid <- m$input$tab$setid
     setkey(setid,set)
     mzml<- m$input$tab$mzml
@@ -205,8 +223,10 @@ mk_comp_tab <- function(m) {
     cmpds<-m$input$tab$cmpds
     setkey(cmpds,ID)
     ## mzml[,`:=`(wd=sapply(file,add_wd_to_mzml,m$conf$project))]
+    print(mzml)
     assert(nrow(cmpds)>0,msg="No compound lists have been provided.")
     assert(all(mzml[,unique(set)] %in% setid[,unique(set)]),msg="Not all set names in the `datatab' data file table match those in the provided set list.")
+    assert(all(mzml[,!is.na(unique(adduct))]),msg="Some data file entries do not have selected adducts.")
     message("Begin generation of the comprehensive table.")
 
     comp <- cmpds[setid,on="ID"][mzml,.(tag,adduct,ID,RT,set,Name,file,SMILES,Formula,mz,known),on="set",allow.cartesian=T]
@@ -346,7 +366,7 @@ concurrency <- function(m) {
     ## message("workers: ",m$conf$concurrency$workers)
 
     ## So we can actually debug.
-    m$future <- if (!m$conf$debug)
+    m$future <- if (is.null(m$conf$debug) || !m$conf$debug)
                     future::future
                 else {
                     message("Debug: futures evaluate as identity")
@@ -388,6 +408,7 @@ mk_tol_funcs <- function(m) {
 
 ##' @export
 extr_data <-function(m) {
+    message("Stage: extract")
     if (!is.null(m$conf$serial) && !m$conf$serial) {
         extr_data_future(m)
     } else {
diff --git a/R/mix.R b/R/mix.R
index 361bee9..fbf0549 100644
--- a/R/mix.R
+++ b/R/mix.R
@@ -568,9 +568,8 @@ base_conf <- function () {
     m <- list()
     m$conf <- list(project=NA_character_,
                    compounds=list(lists=list(),
-                                  sets="",
-                                  data=""),
-                   debug = F)
+                                  sets=""),
+                    debug = F)
     m
 }
 
@@ -599,9 +598,10 @@ fig_conf <- function(m) {
     m
 }
 
-new_conf <- function() fig_conf(presc_conf(
-                           extr_conf(
-                               base_conf())))
+new_conf <- function() fig_conf(
+                           presc_conf(
+                               extr_conf(
+                                   base_conf())))
 
 
 
diff --git a/R/shiny-ui-base.R b/R/shiny-ui-base.R
index ffad906..af4abab 100644
--- a/R/shiny-ui-base.R
+++ b/R/shiny-ui-base.R
@@ -621,7 +621,7 @@ mk_shinyscreen_server <- function(projects,init) {
         rv_dfile(def_datafiles)
         rv_datatab(def_datatab)
     }
-    update_gui <- function(in_conf, session, rv_dfile, rv_datatab, rv_flag_datatab) {
+    update_gui <- function(session, rv_dfile, rv_datatab, rv_flag_datatab) {
         upd_unit <- function(entry,inp_val,inp_unit,choices) {
             if (isTruthy(entry)) {
                 cntnt <- strsplit(entry,split = "[[:space:]]+")[[1]]
@@ -657,47 +657,47 @@ mk_shinyscreen_server <- function(projects,init) {
         }
 
         isolate({
-            rvs$m$conf$project <- in_conf$project
-            rvs$m$conf$paths <- in_conf$paths
-            ## Lists
-            rvs$m$conf$compounds$lists <- in_conf$compounds$lists
-            rvs$m$conf$compounds$sets <- in_conf$compounds$sets
+            ## rvs$m$conf <- in_conf## new_project(in_conf$paths$project)
+            ## rvs$m$conf$paths <- in_conf$paths
+            ## ## Lists
+            ## rvs$m$conf$compounds$lists <- in_conf$compounds$lists
+            ## rvs$m$conf$compounds$sets <- in_conf$compounds$sets
             
             ## Tolerance
             
-            upd_unit(in_conf$tolerance[["ms1 fine"]],
+            upd_unit(rvs$m$conf$tolerance[["ms1 fine"]],
                      "ms1_fine",
                      "ms1_fine_unit",
                      choices=c("ppm","Da"))
-            upd_unit(in_conf$tolerance[["ms1 coarse"]],
+            upd_unit(rvs$m$conf$tolerance[["ms1 coarse"]],
                      "ms1_coarse",
                      "ms1_coarse_unit",
                      choices=c("ppm","Da"))
 
-            upd_unit(in_conf$tolerance[["eic"]],
+            upd_unit(rvs$m$conf$tolerance[["eic"]],
                      "ms1_eic",
                      "ms1_eic_unit",
                      choices=c("ppm","Da"))
-            upd_unit(in_conf$tolerance[["rt"]],
+            upd_unit(rvs$m$conf$tolerance[["rt"]],
                      "ms1_rt_win",
                      "ms1_rt_win_unit",
                      choices=c("min","s"))
 
             ## Prescreen
-            upd_num(in_conf$prescreen[["ms1_int_thresh"]],
+            upd_num(rvs$m$conf$prescreen[["ms1_int_thresh"]],
                     "ms1_int_thresh")
-            upd_num(in_conf$prescreen[["ms2_int_thresh"]],
+            upd_num(rvs$m$conf$prescreen[["ms2_int_thresh"]],
                     "ms2_int_thresh")
-            upd_num(in_conf$prescreen[["s2n"]],
+            upd_num(rvs$m$conf$prescreen[["s2n"]],
                     "s2n")
-            upd_unit(in_conf$prescreen[["ret_time_shift_tol"]],
+            upd_unit(rvs$m$conf$prescreen[["ret_time_shift_tol"]],
                      "ret_time_shift_tol",
                      "ret_time_shift_tol_unit",
                      choices=c("min","s"))
 
             ## Files
-            if (isTruthy(in_conf$paths$data)) {
-                df <- shinyscreen:::file2tab(in_conf$paths$data)
+            if (isTruthy(rvs$m$conf$paths$datatab)) {
+                df <- shinyscreen:::file2tab(rvs$m$conf$paths$datatab)
                 dfile <- data.table::copy(df[,tag:=as.character(tag),with=T])
                 dfile <- dfile[,unique(.SD),.SDcol=c("file","tag")]
                 ## rv_dfile(df[,.(file,tag),by=c("file","tag"),mult="first"][,file:=NULL])
@@ -710,18 +710,18 @@ mk_shinyscreen_server <- function(projects,init) {
             }
 
             ## figures
-            upd_unit(in_conf$figures$rt_min,
+            upd_unit(rvs$m$conf$figures$rt_min,
                      "plot_rt_min",
                      "plot_rt_min_unit",
                      choices=c("min","s"))
             
-            upd_unit(in_conf$figures$rt_max,
+            upd_unit(rvs$m$conf$figures$rt_max,
                      "plot_rt_max",
                      "plot_rt_max_unit",
                      choices=c("min","s"))
 
-            if (isTruthy(in_conf$figures$logaxes)) {
-                logentry <- in_conf$figures$logaxes
+            if (isTruthy(rvs$m$conf$figures$logaxes)) {
+                logentry <- rvs$m$conf$figures$logaxes
                 logchoice <- logical(0)
                 logchoice <- mapply(function(cn,uin) if (cn %in% logentry) uin else NA,
                                     c("ms1_eic_int","ms2_eic_int","ms2_spec_int"),
@@ -736,8 +736,8 @@ mk_shinyscreen_server <- function(projects,init) {
                                          selected = logchoice)
             }
             ## Report
-            if (isTruthy(in_conf$report$author)) updateTextInput(session,"rep_aut",value = in_conf$report$author)
-            if (isTruthy(in_conf$report$title)) updateTextInput(session,"rep_tit",value = in_conf$report$title)
+            if (isTruthy(rvs$m$conf$report$author)) updateTextInput(session,"rep_aut",value = rvs$m$conf$report$author)
+            if (isTruthy(rvs$m$conf$report$title)) updateTextInput(session,"rep_tit",value = rvs$m$conf$report$title)
 
             
         })
@@ -799,8 +799,9 @@ mk_shinyscreen_server <- function(projects,init) {
         ## REACTIVE FUNCTIONS
 
         rf_compound_input_state <- reactive({
-            sets <- rvs$m$conf$compounds$sets
-            lst <- as.list(rvs$m$conf$compounds$lists)
+            sets <- rvs$m$conf$paths$compounds$sets
+            lst <- as.list(rvs$m$conf$paths$compounds$lists)
+            ## TODO XXX
             validate(need(length(lst)>0,
                           message = "Load the compound lists(s) first."))
             validate(need(length(sets)>0 && nchar(sets)>0,
@@ -808,6 +809,7 @@ mk_shinyscreen_server <- function(projects,init) {
             isolate({
                 state <- rev2list(rvs$m)
                 m <- load_compound_input(state)
+
                 ## Side effect! This is because my pipeline logic does not
                 ## work nicely with reactive stuff.
                 rvs$m$input$tab$cmpds <- list2rev(m$input$tab$cmpds)
@@ -819,7 +821,7 @@ mk_shinyscreen_server <- function(projects,init) {
         rf_conf_proj <- reactive({
             
             state <- rev2list(rvs$m)
-            dir.create(state$conf$project,showWarnings = F)
+            if (!is.null(state$conf$paths$project)) dir.create(state$conf$paths$project,showWarnings = F)
             state
             
         })
@@ -827,7 +829,7 @@ mk_shinyscreen_server <- function(projects,init) {
         rf_conf_state <- reactive({
             state <- rf_conf_proj()
             ftab <- get_fn_ftab(state)
-            state$conf$paths$data <- ftab
+            state$conf$paths$datatab <- ftab
             state$conf[["summary table"]]$filter <- rf_get_subset()
             state$conf[["summary table"]]$order <- rf_get_order()
             state
@@ -1092,35 +1094,36 @@ mk_shinyscreen_server <- function(projects,init) {
 
         ## Observers
 
-        observeEvent(input$create_proj_b,{
-            wd <- input$new_proj_name
-            req(!is.null(wd) && !is.na(wd) && nchar(wd)>0)
-            fullwd <- file.path(init$userdir,wd)
-            dir.create(fullwd,recursive = F,showWarnings = F)
-
-            ## Add to the project list if new.
-            if (! (wd %in% rv_projects())) {
-                message("Updating proj list.")
-                reset_gui_and_state(session=session,
-                                    init = init,
-                                    wd = wd,
-                                    rv_dfile = rv_dfile,
-                                    rv_datatab = rv_datatab,
-                                    rv_flag_datatab = rv_flag_datatab,
-                                    rvs = rvs,
-                                    rv_projects = rv_projects)
-                rvs$m$conf$project <- fullwd
-                saveRDS(rev2list(rvs$m),file.path(fullwd,FN_STATE))
+        ## observeEvent(input$create_proj_b,{
+        ##     wd <- input$new_proj_name
+        ##     req(!is.null(wd) && !is.na(wd) && nchar(wd)>0)
+        ##     fullwd <- file.path(init$userdir,wd)
+        ##     dir.create(fullwd,recursive = F,showWarnings = F)
+
+        ##     ## Add to the project list if new.
+        ##     if (! (wd %in% rv_projects())) {
+        ##         message("Updating proj list.")
+        ##         reset_gui_and_state(session=session,
+        ##                             init = init,
+        ##                             wd = wd,
+        ##                             rv_dfile = rv_dfile,
+        ##                             rv_datatab = rv_datatab,
+        ##                             rv_flag_datatab = rv_flag_datatab,
+        ##                             rvs = rvs,
+        ##                             rv_projects = rv_projects)
+        ##         rvs$m$conf$project <- input$new_proj_name
+        ##         rvs$m$paths$project <- fullwd
+        ##         saveRDS(rev2list(rvs$m),file.path(fullwd,FN_STATE))
 
 
                 
-            } else {
-                msg <- "Project already exists. Refusing to overwrite."
-                message(msg)
-                shinymsg(msg)
-            }
+        ##     } else {
+        ##         msg <- "Project already exists. Refusing to overwrite."
+        ##         message(msg)
+        ##         shinymsg(msg)
+        ##     }
 
-        })
+        ## })
 
         observeEvent(input$load_proj_b,{
             
@@ -1139,13 +1142,22 @@ mk_shinyscreen_server <- function(projects,init) {
                                     rvs = rvs,
                                     rv_projects = rv_projects)
                 rvs$m <- list2rev(readRDS(fn_state))
-                rvs$m$conf$project <- fullwd
-                update_gui(rvs$m$conf, session = session,
+                rvs$m$conf$project <- input$proj_list
+                rvs$m$conf$paths$project <- fullwd
+                update_gui(session = session,
                            rv_dfile = rv_dfile,
                            rv_datatab = rv_datatab,
                            rv_flag_datatab = rv_flag_datatab)
             } else {
-                message("No saved state found. This directory is not a project.")
+                message("No saved state found. Creating an empty project.")
+                m <- new_empty_project(fullwd)
+                rvs$m <- NULL
+                rvs$m <- list2rev(m)
+                update_gui(session = session,
+                           rv_dfile = rv_dfile,
+                           rv_datatab = rv_datatab,
+                           rv_flag_datatab = rv_flag_datatab)
+                
             }
         }, label = "project-b")
 
@@ -1157,7 +1169,7 @@ mk_shinyscreen_server <- function(projects,init) {
 
 
         observeEvent(input$save_proj_b,{
-            fn <- file.path(rvs$m$conf$project,FN_STATE)
+            fn <- file.path(rvs$m$conf$paths$project,FN_STATE)
             shinymsg(paste("Saving state to: ",fn,"Please wait.",sep="\n"))
             message("(config) Saving state to: ", paste(fn,collapse = ","))
             fn <- if (length(fn)>0 && nchar(fn[[1]])>0) fn else ""
@@ -1170,7 +1182,7 @@ mk_shinyscreen_server <- function(projects,init) {
                 yaml::write_yaml(m$conf,
                                  file = fconf)
                 shinyscreen:::tab2file(tab=m$input$tab$mzml,file=ftab)
-                m$conf$paths$data <- ftab
+                m$conf$paths$datatab <- ftab
                 saveRDS(object=m,file=fn)
             }
             shinymsg("Saving state completed.")
@@ -1179,14 +1191,14 @@ mk_shinyscreen_server <- function(projects,init) {
         observeEvent(input$sel_indir_b,{
             indir <- input$indir_list
             req(isTruthy(indir))
-            rvs$m$conf$indir <- file.path(init$indir, indir)
-            message("Selected input dir:",rvs$m$conf$indir)
+            rvs$m$conf$paths$data <- file.path(init$indir, indir)
+            message("Selected data dir:",rvs$m$conf$paths$data)
+
         })
 
-        observeEvent(rvs$m$conf$indir,{
-            indir <- rvs$m$conf$indir
+        observeEvent(rvs$m$conf$paths$project,{
+            indir <- rvs$m$conf$paths$project
             req(isTruthy(indir) && dir.exists(indir))
-            
             updateSelectInput(session = session,
                               inputId = "comp_list",
                               choices = list.files(path=indir,
@@ -1210,21 +1222,31 @@ mk_shinyscreen_server <- function(projects,init) {
                                                   recursive = F))
         })
 
+        observeEvent(rvs$m$conf$paths$data,{
+            indir <- rvs$m$conf$paths$data
+            req(isTruthy(indir) && dir.exists(indir))
+
+            updateSelectInput(session = session,
+                              inputId = "dfile_list",
+                              choices = list.files(path=indir,
+                                                   pattern = DFILES_LIST_PATT))
+        })
+
         observeEvent(input$comp_list_b, {
             sels <- input$comp_list
             req(isTruthy(sels))
-            compfiles <- file.path(rvs$m$conf$indir,sels)
+            compfiles <- file.path(rvs$m$conf$paths$project,sels)
             message("(config) Selected compound lists: ", paste(sels,collapse = ","))
-            rvs$m$conf$compounds$lists <- if (length(compfiles)>0 && nchar(compfiles[[1]])>0) compfiles else "Nothing selected."
+            rvs$m$conf$paths$compounds$lists <- if (length(compfiles)>0 && nchar(compfiles[[1]])>0) compfiles else "Nothing selected."
             
         })
 
         observeEvent(input$set_list_b, {
             sels <- input$set_list
             req(isTruthy(sels))
-            setfiles <- file.path(rvs$m$conf$indir,sels)
+            setfiles <- file.path(rvs$m$conf$paths$project,sels)
             message("(config) Selected set lists: ", paste(sels,collapse = ","))
-            rvs$m$conf$compounds$sets <- if (length(setfiles)>0 && nchar(setfiles[[1]])>0) setfiles else "Nothing selected."
+            rvs$m$conf$paths$compounds$sets <- if (length(setfiles)>0 && nchar(setfiles[[1]])>0) setfiles else "Nothing selected."
             
         })
 
@@ -1278,7 +1300,7 @@ mk_shinyscreen_server <- function(projects,init) {
         observeEvent(input$datafiles_b,{
             sels <- input$dfile_list
             req(isTruthy(sels))
-            dfiles <- file.path(rvs$m$conf$indir,sels)
+            dfiles <- file.path(rvs$m$conf$paths$data,sels)
             message("(config) Selected mzMl files: ", paste(sels,collapse = ","))
             if (length(dfiles) > 0) {
                 oldtab <- rv_dfile()
@@ -1347,7 +1369,7 @@ mk_shinyscreen_server <- function(projects,init) {
         observeEvent(input$extract_b,{
             shinymsg("Extraction has started. This may take a while.")
             m <- rf_conf_state()
-            fn_c_state <- file.path(m$conf$project,
+            fn_c_state <- file.path(m$conf$paths$project,
                                     paste0("extract.",shinyscreen:::FN_CONF))
             yaml::write_yaml(x=m$conf,file=fn_c_state)
             message("(extract) Config written to ", fn_c_state)
@@ -1366,7 +1388,7 @@ mk_shinyscreen_server <- function(projects,init) {
                           message = "Perform extraction first."))
             m <- rev2list(rvs$m)
 
-            fn_c_state <- file.path(m$conf$project,
+            fn_c_state <- file.path(m$conf$paths$project,
                                     paste0("presc.",shinyscreen:::FN_CONF))
             yaml::write_yaml(x=m$conf,file=fn_c_state)
             message("(prescreen) Config written to ", fn_c_state)
@@ -1403,7 +1425,7 @@ mk_shinyscreen_server <- function(projects,init) {
                                  tabl = rf_tab4plot_spec(),
                                  figtag = spec,
                                  extension = ext)
-                message("Plots saved to ",file.path(rvs$m$conf$project,
+                message("Plots saved to ",file.path(rvs$m$conf$paths$project,
                                                     FIG_TOPDIR))
 
             } else message("Nothing to save.")
@@ -1506,7 +1528,7 @@ mk_shinyscreen_server <- function(projects,init) {
             tab <- add_msms_peaks(rvs$m$out$tab$flt_summ,
                                   rvs$m$extr$ms2)
             tab2file(tab=tab,
-                     file=file.path(rvs$m$conf$project,
+                     file=file.path(rvs$m$conf$paths$project,
                                     "summary.csv"))
             shinymsg("Summary file export has been completed.")
         },label = "exportsumm_b")
@@ -1685,7 +1707,7 @@ mk_shinyscreen_server <- function(projects,init) {
         
 
         ## Render Outputs
-        output$project <- renderText(rvs$m$conf$project)
+        output$project <- renderText(rvs$m$conf$paths$project)
 
         output$comp_lists <- renderText({
             lsts <- rev2list(rvs$m$conf$compounds$lists)
@@ -1863,7 +1885,7 @@ mk_shinyscreen_server <- function(projects,init) {
                                             format(Sys.time(), "project_%Y%m%d_%H_%M_%S.tar.gz")
                                         },
                                         content=function(file) {
-                                            pdir <- rvs$m$conf$project
+                                            pdir <- rvs$m$conf$paths$project
                                             shiny::req(!is.null(pdir) &&
                                                        !is.na(pdir) &&
                                                        (nchar(pdir) > 0))
diff --git a/inst/rmd/app.Rmd b/inst/rmd/app.Rmd
index 89798f0..1fa9d44 100644
--- a/inst/rmd/app.Rmd
+++ b/inst/rmd/app.Rmd
@@ -104,23 +104,27 @@ before starting `Shinyscreen` in one of the directories under
 
 #### Project management
 
-##### Create new project
+<!-- ##### Create new project -->
 
-```{r, echo=F}
-textInput(inputId = "new_proj_name", label= "New project name",value = "")
-actionButton(inputId = "create_proj_b",
-             label= "Create")
+<!-- ```{r, echo=F} -->
+<!-- textInput(inputId = "new_proj_name", label= "New project name",value = "") -->
+<!-- actionButton(inputId = "create_proj_b", -->
+<!--              label= "Create") -->
 
-```
+<!-- ``` -->
 
 
-##### Load existing project
+##### Load or initialise a project
 
 <details>
-<summary>Load an existing project</summary>
+<summary>Load, or initialise a project</summary>
 
-All the existing projects are shown in the `Avaliable projects`
+All projects are shown in the `Avaliable projects`
 list. Load the project by pressing `Select project` button. 
+
+If the project is new, it has to contain the compound list(s) and the
+set list.
+
 </details>
 
 ```{r, echo=F}
@@ -128,7 +132,7 @@ selectInput('proj_list',
             label = "Select project",
             choices = projects)
 actionButton(inputId = "load_proj_b",
-             label= "Load")
+             label= "Load/Initialise")
 
 ```
 
@@ -161,16 +165,15 @@ downloadButtonRmd("dwn_proj_b",
 ```
 
 
-##### Select input directory
+##### Select data directory
 <details>
-<summary>More on input directories</summary>
+<summary>More on data directories</summary>
 
-Input directory is a subdirectory of the `indir` directory which is
+Data directory is a subdirectory of the `indir` directory which is
 one of the arguments to `app` function used to start Shinyscreen
-GUI. It contains all the input data needed for the prescreening:
-datafiles, compound and set lists in the `CSV` format.
+GUI. It contains the `mzML` data files.
 
-Select on of the input directories from the list by clicking the
+Select one of the data directories from the list by clicking the
 `Select` button.
 
 </details>
-- 
GitLab