From 7f221f83cdf56d8b7ab09e060f383b6f72309476 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Sun, 28 Mar 2021 22:11:17 -0400 Subject: [PATCH 001/260] fix highlight on preview table in val --- app.R | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app.R b/app.R index 03dab7a1..4557e9ae 100644 --- a/app.R +++ b/app.R @@ -19,7 +19,7 @@ reticulate::import("sys") source_python("synLoginFun.py") source_python("metadataModelFuns.py") - +options(stringsAsFactors = FALSE) # stringsAsFactors = TRUE by default for R < 4.0 ######### ui <- dashboardPage( @@ -416,7 +416,8 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) ### reads csv file and previews rawData <- eventReactive(input$file1, { - infile <- readr::read_csv(input$file1$datapath, na = c("", "NA")) + infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% + replace(., is.na(.), " ") # change NA to blank(one space) to match validateModelManifest output ### remove empty rows/columns where readr called it "X"[digit] for unnamed col infile <- infile[, !grepl('^X', colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] @@ -456,7 +457,9 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F ] template_type <- as.character(template_type_df$schema_name) - annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) + annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) %>% + rapply(., function(x) gsub("\'\'", "\' \'", x), how = "replace") %>% # change '' to ' ' + rapply(., function(x) gsub("^$", " ", x), how = "replace") # change empty value to (one space) blank show('text_div2') From ee07b3cef432de37ea57a08c88a273c7e235d6b4 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Sun, 28 Mar 2021 22:40:25 -0400 Subject: [PATCH 002/260] fix help message & remove rownames on preview table --- app.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app.R b/app.R index 4557e9ae..6089bbaf 100644 --- a/app.R +++ b/app.R @@ -128,7 +128,7 @@ ui <- dashboardPage( status = "primary", width = 12, DT::DTOutput("tbl"), - helpText("Google spreadsheet row numbers are incremented from this table by 1") + helpText("Upload manifest to preview the metadata") ), box( title = "Validate Filled Metadata", @@ -431,7 +431,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) observeEvent( rawData(), { output$tbl <- DT::renderDT({ - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE) + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE ) }) @@ -523,7 +523,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) ### currently only one column, requires backend support of multiple output$tbl <- DT::renderDT({ datatable(rawData(), - options = list(lengthChange = FALSE, scrollX = TRUE) + options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE ) %>% formatStyle(errorDT$Column, backgroundColor = styleEqual(errorDT$Value, rep("yellow", length(errorDT$Value) ) )) ## how to have multiple errors }) From 49f3b219921d52c40d06a5d3a293a626e37da48f Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Thu, 1 Apr 2021 15:32:06 -0400 Subject: [PATCH 003/260] change NA to can simply fix the issue --- app.R | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app.R b/app.R index 6089bbaf..cf17a127 100644 --- a/app.R +++ b/app.R @@ -417,8 +417,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) ### reads csv file and previews rawData <- eventReactive(input$file1, { infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% - replace(., is.na(.), " ") # change NA to blank(one space) to match validateModelManifest output - ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + replace(., is.na(.), "") # change NA to blank to match schema output infile <- infile[, !grepl('^X', colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] }) @@ -457,9 +456,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F ] template_type <- as.character(template_type_df$schema_name) - annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) %>% - rapply(., function(x) gsub("\'\'", "\' \'", x), how = "replace") %>% # change '' to ' ' - rapply(., function(x) gsub("^$", " ", x), how = "replace") # change empty value to (one space) blank + annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) show('text_div2') From 2f55790e9b2e11a0d665da1efad77d67f9cd5250 Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:56:01 -0400 Subject: [PATCH 004/260] save the original comments --- app.R | 1 + 1 file changed, 1 insertion(+) diff --git a/app.R b/app.R index cf17a127..2b7209ca 100644 --- a/app.R +++ b/app.R @@ -418,6 +418,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) rawData <- eventReactive(input$file1, { infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% replace(., is.na(.), "") # change NA to blank to match schema output + ### remove empty rows/columns where readr called it "X"[digit] for unnamed col infile <- infile[, !grepl('^X', colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] }) From a388c73a1f255a3fee286043e1d915e41aa278ff Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Sat, 10 Apr 2021 23:01:37 -0400 Subject: [PATCH 005/260] collect styles to a scss file --- app.R | 33 ++++++++------------- www/styles.scss | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 www/styles.scss diff --git a/app.R b/app.R index d66e3f11..db7b46a0 100644 --- a/app.R +++ b/app.R @@ -49,7 +49,7 @@ ui <- dashboardPage( ), dashboardBody( tags$head( - tags$link(rel = "stylesheet", type = "text/css", href = "styles.css"), + tags$style(sass(sass_file("www/styles.scss"))), singleton( includeScript("www/readCookie.js") )), @@ -101,8 +101,7 @@ ui <- dashboardPage( div( id = 'text_div', height = "100%", - htmlOutput("text"), - style = "font-size:18px; background-color: white; border: 1px solid #ccc; border-radius: 3px; margin: 10px 0; padding: 10px" + htmlOutput("text") ) ), helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") @@ -139,15 +138,13 @@ ui <- dashboardPage( hidden( div(id = 'text_div2', height = "100%", - htmlOutput("text2"), - style = "font-size:18px; background-color: white; margin: 10px 0; padding: 10px" + htmlOutput("text2") ), DT::DTOutput("tbl2"), actionButton("gsheet_btn", " Click to Generate Google Sheet Link", icon = icon("table")), div(id = 'gsheet_div', height = "100%", - htmlOutput("gsheet_link"), - style = "font-size:18px; background-color: white; border: 1px solid #ccc; border-radius: 3px; margin: 10px 0; padding: 10px" + htmlOutput("gsheet_link") ) ), helpText( @@ -352,8 +349,8 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) if (is.null(input$template_type)) { output$text <- renderUI({ - tags$a( HTML(paste0('', - "Please select a template from the 'Select your Dataset' tab !", ''))) + tags$span(class="error_msg", + HTML("Please select a template from the 'Select your Dataset' tab !")) }) } else { selected_folder <- input$dataset @@ -538,20 +535,14 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) ### format output text output$text2 <- renderUI({ - # for now, manually change text color to red via html, it could be cleaner when we collect them to a css/scss file - val_text_col <- ifelse(!is.null(validation_res) && validation_res == "valid", "green", "#E53935") + text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg") tagList( - if (is.null(input$template_type)) HTML(paste0('', - "Please select a template from the 'Select your Dataset' tab !", '', '
')), - if (is.null(rawData())) HTML(paste0('', - "Please upload a filled template !", '')), - if (!is.null(validation_res)) HTML(paste0('', - "Your metadata is ", validation_res, " !!!", '')), - if (!is.null(type_error)) HTML(paste0('', - '

', type_error, '
')), - if (!is.null(help_msg)) HTML(paste0('', - '

', help_msg, '
')) + if (is.null(input$template_type)) span(class=text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")), + if (is.null(rawData())) span(class=text_class, HTML("Please upload a filled template !")), + if (!is.null(validation_res)) span(class=text_class, HTML(paste0("Your metadata is ", validation_res, " !!!"))), + if (!is.null(type_error)) span(class=text_class, HTML(paste0("

", type_error))), + if (!is.null(help_msg)) span(class=text_class, HTML(paste0("

", help_msg))) ) }) diff --git a/www/styles.scss b/www/styles.scss new file mode 100644 index 00000000..2b945d95 --- /dev/null +++ b/www/styles.scss @@ -0,0 +1,78 @@ +$error_col: #E53935; +$success_col: #28a745; + +/*** Top navigation bar ***/ +.main-header { + max-height: 50px +} + +.main-header .logo { + height: 70px; + font-size: 21px; + padding-top: 10px +} + +.sidebar-toggle { + height: 15px; + padding-top: 25px !important +} + +.navbar { + min-height: 50px !important +} + +.message-menu { + padding-top: 5px +} + +/*** Sidebar ***/ +.left-side, .main-sidebar { + padding-top: 80px; + font-weight: bold; + font-size: 1.1em +} + +#text_div, #text_div2, #gsheet_div { + font-size: 18px; + background-color: white; + margin: 10px 0; + padding: 10px 0; +} + +.error_msg { + color: $error_col; +} + +.success_msg { + color: $success_col; +} + +/*** Notification bar ***/ +.shiny-notification { + position:fixed; + bottom: 0; + right: 0; + width: 100%; +} +#shiny-notification-error { + height: 500px; + padding :20px; + display: table-cell +} +#shiny-notification-processing {background-color: #F7DC6F} +#shiny-notification-success {background-color: #82E0AA} + +/*** Footer ***/ +footer { + position: absolute; + padding: 18px; + left: 0; + bottom: 0; + width: 100%; + background-color: #D0D6DC; + color: #465362; + font-size: 10px; + text-align: center; + z-index: 1000 +} + From b6e1fbb40e1fe6670009a8d1630d739c24708029 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Tue, 13 Apr 2021 12:44:21 -0400 Subject: [PATCH 006/260] remove css --- www/styles.css | 60 -------------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 www/styles.css diff --git a/www/styles.css b/www/styles.css deleted file mode 100644 index b3c59c52..00000000 --- a/www/styles.css +++ /dev/null @@ -1,60 +0,0 @@ -/*** Top navigation bar ***/ -.main-header { - max-height: 50px -} - -.main-header .logo { - height: 70px; - font-size: 21px; - padding-top: 10px -} - -.sidebar-toggle { - height: 15px; - padding-top: 25px !important -} - -.navbar { - min-height: 50px !important -} - -.message-menu { - padding-top: 5px -} - -/*** Sidebar ***/ -.left-side, .main-sidebar { - padding-top: 80px; - font-weight: bold; - font-size: 1.1em -} - -/*** Notification bar ***/ -.shiny-notification { - position:fixed; - bottom: 0; - right: 0; - width: 100%; -} -#shiny-notification-error { - height: 500px; - padding :20px; - display: table-cell -} -#shiny-notification-processing {background-color: #F7DC6F} -#shiny-notification-success {background-color: #82E0AA} - -/*** Footer ***/ -footer { - position: absolute; - padding: 18px; - left: 0; - bottom: 0; - width: 100%; - background-color: #D0D6DC; - color: #465362; - font-size: 10px; - text-align: center; - z-index: 1000 -} - From 9cd42112cfc8a002c163afdcef4ec0e0cf6adc07 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Tue, 13 Apr 2021 21:29:08 -0400 Subject: [PATCH 007/260] improve error msg for wrong schema --- app.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app.R b/app.R index 2139fa1e..982dd1b3 100644 --- a/app.R +++ b/app.R @@ -470,10 +470,10 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template + waiter_msg <- "Mismatched Template Found !" # get all mismatched components error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% unique() - column_names <- "Component" - + # error messages for mismatch mismatch_c <- error_values %>% sQuote %>% paste(collapse = ", ") type_error <- paste0("The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", input$template_type, " >>.") @@ -486,12 +486,14 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) } else if (length(inx_ws) > 0) { # wrong schema error(s): validating metadata miss any required columns + waiter_msg <- "Wrong Schema Used !" type_error <- paste0("The submitted metadata does not contain all required column(s).") help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and ensure your metadata contains all required columns." } else { + waiter_msg <- sprintf("%d errors found", length(annotation_status)) type_error <- paste0("The submitted metadata have ", length(annotation_status), " errors.") help_msg <- NULL @@ -512,7 +514,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) } validate_w$update( - html = h3(sprintf("%d errors found", length(annotation_status))) + html = h3(waiter_msg) ) ### format output text @@ -531,9 +533,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) if (length(inx_ws) > 0) { # if it is wrong schema error, highlight all cells - # for now, should we manually add 'T/F to highlight colnames' parameter into DT::datatbale/DT::formatStyle? - datatable(rawData() %>% rename_with(~ paste0('', .x, '')), - escape = F, options = list(lengthChange = FALSE, scrollX = TRUE) ) %>% + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE) ) %>% formatStyle(1, target = "row", backgroundColor = "yellow") } else { @@ -559,7 +559,7 @@ schema_to_display_lookup <- data.frame(schema_name, display_name) }) } - Sys.sleep(2) + Sys.sleep(3) validate_w$hide() } ) From d5d425b25b93d2906a8ef6f3d643125effe4a108 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Tue, 13 Apr 2021 22:13:24 -0400 Subject: [PATCH 008/260] load scss library --- app.R | 1 + 1 file changed, 1 insertion(+) diff --git a/app.R b/app.R index db7b46a0..ab87f75a 100644 --- a/app.R +++ b/app.R @@ -12,6 +12,7 @@ library(purrr) library(plotly) library(shinypop) library(waiter) +library(scss) # read scss file #########global use_condaenv('data_curator_env', required = TRUE) From d4eb1f1b085a199502b5973aca1a9904bee66210 Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Tue, 13 Apr 2021 22:21:38 -0400 Subject: [PATCH 009/260] fix typo scss to sass --- app.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.R b/app.R index 3aec1de3..99e95501 100644 --- a/app.R +++ b/app.R @@ -12,7 +12,7 @@ library(purrr) library(plotly) library(shinypop) library(waiter) -library(scss) # read scss file +library(sass) # read scss file #########global use_condaenv('data_curator_env', required = TRUE) From 803b85cdded930df8258f064744e5c7b47eab687 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Tue, 13 Apr 2021 22:53:28 -0400 Subject: [PATCH 010/260] update wording --- app.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.R b/app.R index cf17a127..bae064ef 100644 --- a/app.R +++ b/app.R @@ -128,7 +128,7 @@ ui <- dashboardPage( status = "primary", width = 12, DT::DTOutput("tbl"), - helpText("Upload manifest to preview the metadata") + helpText("Upload filled template to preview the metadata") ), box( title = "Validate Filled Metadata", From 3f9ecd2d22545d902e46c4e890963d47b276622c Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Wed, 14 Apr 2021 09:41:11 -0400 Subject: [PATCH 011/260] scss structure --- app.R | 2 +- www/scss/basic/_button.scss | 1 + www/scss/basic/_message.scss | 32 ++++++++++++ www/scss/basic/_variables.scss | 9 ++++ www/scss/main.scss | 16 ++++++ www/scss/section/_content.scss | 8 +++ www/scss/section/_footer.scss | 12 +++++ www/scss/section/_header.scss | 9 ++++ www/scss/section/_navigation.scss | 3 ++ www/scss/section/_sidebar.scss | 11 +++++ www/styles.scss | 78 ------------------------------ www/synapse_logo_blk.png | Bin 0 -> 20190 bytes 12 files changed, 102 insertions(+), 79 deletions(-) create mode 100644 www/scss/basic/_button.scss create mode 100644 www/scss/basic/_message.scss create mode 100644 www/scss/basic/_variables.scss create mode 100644 www/scss/main.scss create mode 100644 www/scss/section/_content.scss create mode 100644 www/scss/section/_footer.scss create mode 100644 www/scss/section/_header.scss create mode 100644 www/scss/section/_navigation.scss create mode 100644 www/scss/section/_sidebar.scss delete mode 100644 www/styles.scss create mode 100644 www/synapse_logo_blk.png diff --git a/app.R b/app.R index 99e95501..0a2ee476 100644 --- a/app.R +++ b/app.R @@ -50,7 +50,7 @@ ui <- dashboardPage( ), dashboardBody( tags$head( - tags$style(sass(sass_file("www/styles.scss"))), + tags$style(sass(sass_file("www/scss/main.scss"))), singleton( includeScript("www/readCookie.js") )), diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss new file mode 100644 index 00000000..b1edd959 --- /dev/null +++ b/www/scss/basic/_button.scss @@ -0,0 +1 @@ +// styles of button are collected in here \ No newline at end of file diff --git a/www/scss/basic/_message.scss b/www/scss/basic/_message.scss new file mode 100644 index 00000000..3e209e8b --- /dev/null +++ b/www/scss/basic/_message.scss @@ -0,0 +1,32 @@ +// styles of messages are collected in here +// (e.g pop-up messages/notification messages et.al) + +// message +.message-menu { + padding-top: 5px +} + +// validation message +.error_msg { + color: $error_col; +} + +.success_msg { + color: $success_col; +} + +// notification +.shiny-notification { + position:fixed; + bottom: 0; + right: 0; + width: 100%; +} +#shiny-notification-error { + height: 500px; + padding :20px; + display: table-cell +} + +#shiny-notification-processing {background-color: $notif_process_col} +#shiny-notification-success {background-color: $notif_success_col} \ No newline at end of file diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss new file mode 100644 index 00000000..f4b38557 --- /dev/null +++ b/www/scss/basic/_variables.scss @@ -0,0 +1,9 @@ +// global variables are collected here + +// colors +$error_col: #E53935; +$success_col: #28a745; +$notif_process_col: #F7DC6F; +$notif_success_col: #82E0AA; +$footer_col: #465362; +$footer_bg_col: #D0D6DC; \ No newline at end of file diff --git a/www/scss/main.scss b/www/scss/main.scss new file mode 100644 index 00000000..f8b2829e --- /dev/null +++ b/www/scss/main.scss @@ -0,0 +1,16 @@ +// global variables +@import 'basic/variables'; + +// dashboard sections +@import 'section/header'; +@import 'section/navigation'; +@import 'section/sidebar'; +@import 'section/content'; +@import 'section/footer'; + +// feature styles +@import 'basic/button'; +@import 'basic/message'; + + + diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss new file mode 100644 index 00000000..7b330116 --- /dev/null +++ b/www/scss/section/_content.scss @@ -0,0 +1,8 @@ +// specify div +#text_div, #text_div2, #gsheet_div { + font-size: 18px; + background-color: white; + margin: 10px 0; + padding: 10px 0; +} + diff --git a/www/scss/section/_footer.scss b/www/scss/section/_footer.scss new file mode 100644 index 00000000..c72f65eb --- /dev/null +++ b/www/scss/section/_footer.scss @@ -0,0 +1,12 @@ +footer { + position: absolute; + padding: 18px; + left: 0; + bottom: 0; + width: 100%; + background-color: $footer_bg_col; + color: $footer_col; + font-size: 10px; + text-align: center; + z-index: 1000 +} diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss new file mode 100644 index 00000000..f824c55c --- /dev/null +++ b/www/scss/section/_header.scss @@ -0,0 +1,9 @@ +.main-header { + max-height: 50px; + + .logo { + height: 70px; + font-size: 21px; + padding-top: 10px; + } +} diff --git a/www/scss/section/_navigation.scss b/www/scss/section/_navigation.scss new file mode 100644 index 00000000..c06cdc59 --- /dev/null +++ b/www/scss/section/_navigation.scss @@ -0,0 +1,3 @@ +.navbar { + min-height: 50px !important +} \ No newline at end of file diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss new file mode 100644 index 00000000..cd482add --- /dev/null +++ b/www/scss/section/_sidebar.scss @@ -0,0 +1,11 @@ +.sidebar-toggle { + height: 15px; + padding-top: 25px !important +} + +/*** Sidebar ***/ +.left-side, .main-sidebar { + padding-top: 80px; + font-weight: bold; + font-size: 1.1em +} \ No newline at end of file diff --git a/www/styles.scss b/www/styles.scss deleted file mode 100644 index 2b945d95..00000000 --- a/www/styles.scss +++ /dev/null @@ -1,78 +0,0 @@ -$error_col: #E53935; -$success_col: #28a745; - -/*** Top navigation bar ***/ -.main-header { - max-height: 50px -} - -.main-header .logo { - height: 70px; - font-size: 21px; - padding-top: 10px -} - -.sidebar-toggle { - height: 15px; - padding-top: 25px !important -} - -.navbar { - min-height: 50px !important -} - -.message-menu { - padding-top: 5px -} - -/*** Sidebar ***/ -.left-side, .main-sidebar { - padding-top: 80px; - font-weight: bold; - font-size: 1.1em -} - -#text_div, #text_div2, #gsheet_div { - font-size: 18px; - background-color: white; - margin: 10px 0; - padding: 10px 0; -} - -.error_msg { - color: $error_col; -} - -.success_msg { - color: $success_col; -} - -/*** Notification bar ***/ -.shiny-notification { - position:fixed; - bottom: 0; - right: 0; - width: 100%; -} -#shiny-notification-error { - height: 500px; - padding :20px; - display: table-cell -} -#shiny-notification-processing {background-color: #F7DC6F} -#shiny-notification-success {background-color: #82E0AA} - -/*** Footer ***/ -footer { - position: absolute; - padding: 18px; - left: 0; - bottom: 0; - width: 100%; - background-color: #D0D6DC; - color: #465362; - font-size: 10px; - text-align: center; - z-index: 1000 -} - diff --git a/www/synapse_logo_blk.png b/www/synapse_logo_blk.png new file mode 100644 index 0000000000000000000000000000000000000000..84e1347f9b14ea1d2c01f43a5f3171186f62ac56 GIT binary patch literal 20190 zcmcFK1ydYN(*y|?+}+)RJBMp_Q zcg;+DcZ8CH6cPeH0t5sEl8m&t%IEy}`JTaj{T#JZZNfe$XiE`!5eSHeIK)?Dn9pxg zQ)v}>2ncU#2#8-H5D?FwpkE*e2)FML5GO_u5Pazn5IBz6oyr2AKfapCNr^*z{P*Pd zlqG#aU|nV8C14Mr5z(md^DA~DKS5s{oE6l*Oc#1&LO{s>lMxqD^ISd8@$kg__dEiy zw9xfdgzKTe7MAE~wYfAAv8Cn8ggNd(lulxf{6!i>iclE7+>`24qbU);2`?jkxgzA^ zAHcYI-Sw3#-pqZ_H&^O5At&P@JLfX@9y=j7mzkB7wIYpHlEBEsM8zi^lAE<+M` z=yy6Vbr|?hH?W?xAW3FnXrx1;B%&!I?O%tPH}8>3j5N-m!cnRyheyRy1A3wIh$2i@ z3qvKdbR2Ns`iS(h5=AP-2G8$}T6C`Hk^LEE584_rQ|k<^nb4`h%#sh*Rw@+d>p-R1XZJ;4r;y!U1mbgN=411%goikk_{hGW4STWSrOTVC zEwK1khm}V$_Oi?MKb15SU-62UUmv@f$Rf3R@g6GfHzm4w-nHOF+l!7GBfKhV30Y$2`~~#ur^hf;ik@hZn?|%3;xP0&u~{DW zeLTNH2};g=Tr@?j-+i6R{#LAnh7cYOeNVMHN-_9{V52zRVzyo=djwmp4udE#XlS;c zi3BruusuWd{j{lVlQ;a!L!R8=*<>=&N~jW+tG-DC&!~J?Hq{ma7tq1p_dSpf{9!cO zgaKNkOB-Mc5W}Ib91b$X(3U~zUiF{s7^kasJf;v*o$x~E;8 zurx60ajk)lKSY<-FX=yx9vok zycCxXmy141YwrTFdKS-4BEtU&go*<^a>VH$ld|5BB&T5(EfbX|uws_WFXMUfib>wr zExs9KztG1xZ3YuGDHhfEN8asu45a%82T?nhIrKQ{Vl zvJUY!s9OFOqwVpGd>~Fz{Jqk|3^JtPW6sS3jYvsXc z3`ai>OfHu&Er`Ww-PN*E*f>+)WIV1Gz#@_!@-gh*w}iD$uhQbj{?(m0z-c*KSIP{! zH0Sa7G@HAXIFEo-|F%+-CqF2x1FUi`{sA5Pbqi)Ji;*a68^lVee@ZO+vx;s_C#oo%Sk|H1Suq+XvGqEw zsMvgveX$`r5s94Su6p-#OjHcP;5>!>U37z9xu2A>I~OgzXp3^e5IF0c-^VYE08|=@SDkY{V{QtIybrN z(mN9|%SvEbrp$4z?eUdw77fj8oF_K&&uzwC*evyX)IXMJs^jG?nW)=sW@brJ8LQb? z65k_m{{u|556~aJXA{1Atw*fAup?<))df}C2mHuUXi`X9&#~WC_%%9!_qMkWmV|g% zLZ(A+r5&2el7zS|s~n{DcX##rDM8wQBJyw#<&ePc@WXN1PmCAP5l^7|Qh#VWsD4a6 zfF|PQ$_F57y77}?*z|h2RUrQv3`c{KNPwViK4#KbjLT~B!K=bIfH9U^ za|xxc-J1%mNfT4#bl_23fz>`Pr~E7Z@O;^^oXiwwaf9zg?byi>U~k3JPWuc&g$Ii& zY7`|y8Kvg$(qg_&xL4Z#k@uAJXMPiyB5sJh`Ijv|5!7zhd((Q*lmniE9gpFFNuq zOB7J@0>YEb(zNpium)}7c%i<$hbcagDP1w3c@nto-`R~-`);%!3{T+IfpL~B7Orj8 zCZlF3HPlt+p1Eqzargkj|IFv3Osx|>c(JHTKyYeNInFldFNqGj6~=?nT$jo4Hh~Xk z{23!_L?UMIzh)r2W+4OHWGu1Y2uD_1Zlbxanzb5@&~Q2c{V5HwYA_PA)yfU~ttWqL zdQR@s%eHi&td>Ld~G zW7$kwPIZI9x!#T1i{@%r4JqlnY=4s>ZWjndyv?JXm=e`eQ>)5BM;q6;GYL~f*-F@- zesn!nBZLJETrf%8JS!C|*jB~*syQQzz}o8y z0FHC;go^y{IQwpja`zywD6TdI!2JDnXj#camnUA;PyN#`B+TrqL;3Iwfm<%q5PYRC zp7ljZi8+AXyA$z0;>zWvPJKDzTPp=ky1Mh9)e-x3NR6~BJy=NfQj*Gt(w1dqtXU6|;GM3U=!;aHgW;Vw>-{a6 zQ!DPN-B;o7a;G<1K>naScC5{pZMPzM0Xkzc@Y)68Xvt)^-db}|c_C49TC#Cd`SRQv zSYCk;fW^HVld=Pl_!iax6*hCA7aCqoLN`4o*-$ye`Ln<7iS=w|mCbJRcsLI*?|^T~ zi|pj4iqjiy$CIN#sKJ0%!v|gwVgPD#7_H!8dibfPebL)!PoA~ldf@XLok-qTUgT>B-VQ&@`$w5SzJZ7>{6 z5p-GE);ShmVh9Nr8U)?p}uCC&JA>5dfNHJ&!SMEzB9rTg`gCIRadK; zPdV%M&MldB4+tslTk3g*oJ6VVKe{8OqJ^`yo?OOvp-{Xfv1;}r8bO_Bol8WHOzpCh|7@D zI#?(5b#koKV=|gn-RVeB4DWWIY3R%_Dz$^CrWzMW9nq*;uYV2E#C>qHdLm37nlU|H zBFB%D0;m~ORfdm*krRi0FSZzM^>gwdl-tuZc(?*GFf1JJdJ7l zfxNLNiY8<-ud6fz`bmE7Uf9%I@(5O-gsh+!=R6gcP>~W6Bplp_S0va7soyV=+3Vmr zM9mcg8nw|TcVJZl4RK%`-CxU$c=cwu_(D)LBeU6I*m+dizfl zOofxhIlXKIA3J@>>n)%2MFI^10hRzN-j!t+gONIV%%A9FYPK@+;XP*t&dG~J}6cE9A>}V+zEX< zIT^-xxQEM;dR;YltTj*1CqST`WY%wd3=H;JX{g>!|6k2vM>DJ|QJObc%}REu6{&$L>N(3bdnORtyW`cB1XzZ8&`goWGu8b&YL zi=ZOTOIq^9J9c2uZuk)1zi1XF?yHq|>G#akxHihPN9uE}yEx}gl$<_wLCbBBi=AIO|E*B1CNLlLaM`e2%~O)Yf|xaT(*o4= z+OYFLve>$~L~7tQlLUX5?L+Cee=kYAPmoAfS1Z&aq%?Gb%{y0lyb2$PG{57I({M`{ zvi+_}V{SaQ7Pz)YGhi{Cv=B)miw}Mhf+exfhV8p_xhQen(okV(k4*W!%4U876eCSj zAe4~n_-(eOOfNT{&>8n=VK*koFL>2uOisbH***~TKd!%jU_x8 zERE<|H~qRa-K`Jvs#?$2%cOZ~O`k&O!)Rd8!$ozRt=e4MQviR~`nVl^YPT!V;#-E% z59Ssn<7d!V^WB?xSG%mNGn?|Pw5=1f;X&EW!{Fk_SjYRznSC^Mc8WA1{?8wstIE3Q@UG{qqS3Nn?S!V0j*UdVj>O4M@|rl%jU7+EQR zT@n=Ni=V2p(U>Nb8ZTt&Qx6j_M5yQD&6?~u$K!UHgRk3oxp&!rv%?y*blXkQm(OT> z91{Av(S>5Z97Er0mvv>shXARsoN!FEtap!7s&H)i=@H@AO=pT`?Zzdfl)zOOE34BN zW?rx6{;Br%xss_1a9-B3J$G?@-hiWvul!ThvxqyF%9m5P#r=d-9T`L}EDMiKfIT_h zkmrAp^bq6{qsQqZFv$++EA;sS?+Tvf$Y#YdZfu0`${oVEZ6IQlI)~oz-*$`9{!*ii1@Sb_ z+3%((MlS2c@R<}ST+)Qiw7F0@Z*5(@P-&?N%uV%&FnE!NzuI~Td`}0uM(sHs8@SRb zp^>^3t7*+yrjXfH&g#yT7kGy{fV>a*pHf6L4d>TbQyzAO|2!8eN}NXHYIrMhWS8T{M!_S=Ym*-^-` zU^v+VyGOZvs|}}{_JZTCPd@tYcu?%9*jQuoqIMs5j!1$!FPiFrqzu;<_*{0P$&*sW zu6xWZG^J*+9(tKSWTO}yiwy?edjNPF`ei?s*7A&0wzAs!{TU8k0z{OntRvGSf;-gZK%>^`Vlb%%Hf}`9*F>Nr0_S=b8>MMe%h+{EJ&M2U z{;08(*xp7b`eu}iBTvChlw7J=&EKunVpk?o(fyb!{twalQ0uMA33Ff7Q$$?EphklD zrb5htOWFL})9(m{S?#%zbUN>x&dQ%EQp${Q65!RjD+qyQ8+7?;`(PI8jEOTsTO@*n z14aLP?oVW&`dw;iJgAsX|i~T>jnRLLjzo%6R+n6 z5xotz9OM(B$VRqs`X_#rHrf4M<%b(nYgG#%;WM6L={LNoVdWR;d!mwkBNz>dZL7K5 zX#{*$*ZZ;4QluPS7)4j)RA`(hDsvw4nr21bG^V@*WzY5?MJ^Z>tG5P2GfX!IM_?E^ zwCK~rhtJKwUo$=^xe_lft4%Cr(QH5kac{oGuhzGD?ddQWFS+1e7mYfjsh{brCOrCU zB-8;*8X=e8iEO<%>^zg#N@EVLl>5(D35Fl9Tsm}~!osiX`i_TBAJCKHMI~=)*B5VY z6b3!5vG$upW4OPM>a6bmtaFhx$1fz~!( z#^_uf{2=6}aF)m4+Si#)OepAVmty2{d7iZIM#or`a$TVVZjG~vagtxG7ptkLbjfk= zK_A2$mC~3M1d9d-w+_lkt^gHv)Btp|Cf6yY+*2WRe}8nUktPQoVn>Ve&Um-PcHXk|vu$49EI!1v`E!k*SEB|Nc5 zx(*|dv~sUzVzj+batJ9O#0MEsN;{(ZBTwkYF!xXBTWV8}7l53A111lpsx0I-$RT6- zf(RwiFk&#NR zeSNvcJ#%%+VjO|QWhDAz{?t`Ca{g695b1;~^9L-ABE|$wX?%uJ};y zL%l4?`(K19kKUbZ}^ziV91r2qHhD{=zI=a&Q~{jM>?n+hJP5`p67q*s`cT; zMtY)Igd$`MRE}M*ZqR7X9eM)CYmX<2`%&`1#CtSfVuZ3=E+xU&zm7*4O8xjWbI){EV} zN%geVbIzZT9_|DKF*O^mvV4&>yKtef9xf?&sDKI2U(<0z*Kri?LYuE9N?bX}V$a_W zf0Xl)|l(|0M^cJX28uLrgV|bo}*E0pt=qa3^sP_1)D`iDp5iW`n_CGExom%{V9b~Xeq=^_#!i7nZURF;eR}I{A#RrKEufrNSouT2VQuV@{mmIPpPKaLKUMY?@ICQ+Z#$R=S!{&# z7~#wviNO)IsM8qGcjnkbm1Qff7v*J5KXOtmpS&W(oeZ2m#G|LldTU#TZSke1L{(cAm}BLfA^*>`&fRO&okG_)3qkJ>@!wZRzoZ~u=i(hV)whlx%Iu@XPs!m z5t@E_(`;mV((t_(S7ZDPfvOyi*k){o%0R(ttkvo|oQ`vkQ_sy`5tpp>O15avgkseU z8)_Y&{8d-Pby1_ig6aAC@}aieY|O>|O?#B@jx4)@X@(Iw9-V3rRK%pf2cDkTP7b-!%_8lIYh*15-ARC3OP+Nn!~T|p1JO{F{HL#gM2dm`N}7z$%T0Rk znP2b6t`t}9(0R+Hi%Wak3$48ZzjW28XrVr@XY56Z%>-+0`h1q#$87^>5{sr=DsAoA zc^qa|53P%2X|c{x7AA`#5z+=9_%v<4PimS(4M(R`{4IJHH|yMGDm!7~OX)Y_zh19D zI*WoD8`1Gos?C?OyB@c-*n3wD#!BPf1#VlmC=_qNB^uQ)n#!&}Mh+dfTZdfwoUtA3 znr_A>-qnR(YG1z2Z`%?uu|%3V+_S({U=SpUn=_BDi(4pU=@r?fTzeX&h%B7r>;0Q8 z5w6&A$%Ju%vP|#`o1kbB!S8LybVfuNlbYEn1T`k5{g49 z2&M=dpBs0?vcT}#X84-BmOL&cGy%BTO$WXPoVv)92*pp$Y8QLADtXt3jKVRkv%h+m>;NvM5e`f3pTc^e<$Ch~mwE~sngoaw=<)q!rm3)nGxW!2h2IR6FwYw~F zIWM=~-puk?^->b$eMaoF*Vtznu}#o-AG?}h07S9I!@4xc2fnV4Mmp}1MM@Tpry%1( z)53^rs`$ICJazV;Bc}@LuBd;gSZZ(32+eAkzNJnO!}YOK;LO#^yCCl;H*r(sg@@xN z@@0>MG8oeNUK=pB_FDR`CdD3Z_iMQ-vP&*XKw8vxj2+F=iupI;#J=gXzqq%21CNuA z<~q;hbfn(Gx=7<>Cl!MiYnEM`;kVw!_Htqh)TDF>0dXm)`>f{rtmk+Cen5o@ECfqU zO-db_Z#!P>lrHOd(3VLxHy9vt2di0pDGJ96i5gqr6^{n z2km5TrnV2kcPxWMyMi^A$~5eIZGVnczo7ixnV`pB%2A&bdQ@lA&C}YO6t6$~fTVtl zZj6EUk4=+OSPmH?H>$qMsEeu3r(ICBrTypU_73dxY~9-zMk>6=@klFkx*~^pvD-{< zKvvUg zGDk~Da-(l`<_Lo&g71X8&r*TjY|9tC+8j_MN{#4*|Tp;H*1sD>cJK(O}(SbwI+CfW+AFf`v9R5-ev@ zxQo`M``!KTOp<}2i*$%{scqv}AD|GK+iO#gH-lSK!Q!^roQJ}M&fUh-Pe^FRIplE3 zU@%0E|7tz{x1x96r+du`o4$Bsz}$REGhkdadSIS*2N^b{_0?B9O<&uOG2j*`4EmF{ z03X&H1%Nj4e;8lZBpw-%C;0-*1!qd-5sMx1qpx`1+T7{|ZdkzPiADm6l89>!CU5aY z!jr@e7nt4nC8YA9L>Jzurx%n3J3b0nhgxhURe~|E|Mu+f<0zwH3>TYctpLqo8E}vR z$9|Gbi0wSc0p6(WIFm4~3tqYkFlb<7MCeRh*B|bc-?VNvWB~Jbv;EnA)&iTwzW)5a z5dTcb7SWi<|?XBFOtaHv5hOcPu`@=DC)BCk|O zyeH(5)s}!^ViCx*EUgw!#lE>l3|8>2%V7C!P<;bGOBMMzh$7fr2Ku*?3oA9ZEs*ng zm`J|#MK6@t#Iz`a)}gPLM9#~yq5*~xYNzmzAkhBda`;N$l_Fs77k4T&At~|M9U;+& zv(Rr@4rB|$!Jl!I6;9u#e;9}i?+kYL+7=eLFVc#>+C1pt9~0^a|L}Jr<~8B|86;`% z1v5}MQ`@iodTacJAT>lX2!%|9)$xzo2wfHe>*gOknEprZ+gAxXcr%<- zm3`QdoDhX0ww+LJPy6MurK6o+%v70bP_t%a&dC0i-*AP9#LlXS0SNIF$%ScTxX z3MeJ-vp@3(AEC*=0?k8C7jcLHDzj*^RxzY|VFDAI(;t6IYE)-K#SvuuD}F=yho)`4 z@uNIsx;~@8e^KLbl^{=<;e)M1Zqk?>nWGDK4j>kqj4NcIoQmy z-X`o(fMG6U9!xXx%DUHMlqhA>m-VoA9|0S%kpyz5U@2nH(YQlR%|m$HYhp5XgUcCLWk6EE}-^-Fe8p!2Rqx z;}%FxiMFcjgrcMQxhT;{zo zc`jT!hpP=2mQ4GOkMsdo^R0}e1Ryrw+y|;*cpR{Ve=!{0t8I|o8YBZ4M9&Q4pZhx zf(+ENFz)@d+OJKOv0nX&93EeL-*NJ4bi-!)FY58_WM`zwW{_^zt91iE&_*#OM>sMI zVI>`dq0AK0b`ePEx99tD{s{4_ATa*48e)T%lgIKAz&df)YJ?`nu{|zSB8?{%5eWx- zSG)tBsDv=p`wvpu1&#S6XtqVs6soB75yVb|m(KAC182;6CT9|)LkfSt@p`&fpcKFf z*aNb-ej81-=g(gK1!n|7p9JTT<=RFM^yYV#)V#ntW*^c$)H2D+OHzw zzb?VntvSgcd8!yA<)P^nl83-mnMSW_3B6*&QY zea6Uo<=)}QN}OAM-gYC9FC}InA|$8F3KFH4rc)XKS=9*@L6q+_jbelgOK1j{n+8^a z$g5xVP(gu38Q(Lp7i~U~)I(H&!o2Ml?N-gyN$(tWL;|UyLHS`$#7)m3A$tef10n1c zLOhW$fnjhoij?{&A#Is*;CNx_0fxru?N7Ayj#ZV=_ym%MN-BELkTZh<{~Y~900wmX z&-OjhTvW8twI~K<4mJ3AfrbcTP}@~<(drTqU%d%3Utuei;t|5IZ>v&!BJHgr8$0D6 z^UDK0H^H;qT57^5ON8)u$aGZF^XagaDjGC6CTlYh52{=-m#%T)0 zt#NrnJ~Igpou;IAS;ae21p_QAniZ^$@7~lu;Lm3yA|NV$L2^l10o5!aJ0VpP%E_`l zuTt*Dm8Jwmd;L+t1eq6AQ_$~YFE_X@ALdrtcv>~?uJVbx$EHC1@z;MOb0w!ngM2&U z;d{LMA;|7syg>vpg;1SC7DzqK@+=buQ~OAJPaPl^J#Q-iZh^v?Yg^_r^Skp#C{D)2-iZf7fx1rS6T%%WLd~lptec z!&Yp~Nfbji(BYV}!iYh8BJnE1nQAJlkFDb1S&}FrOJ%7^+;@d-j}88ybgoG< zwy*jvzsTcj+1T1_YpyK)x^1Z#gK3V0LIM9mnTBI1B*2e|iblMvK_!UM1R1X*Rb0#D z(Y(|I?B-ueoM2JMc=uDWOj_tUe$GVKWHESt{KNTnnpXK;Z#$sg`rK6uk%ES$=sW$F zvJv?N#CUh=o_jJpz}ugyD9NP`ebKK7T(rVw;>Bcs?6&tmodqF*#9H)PA)&aIWGsNC zHjTWOzxfgZ0?i~5M?T>89IZWQ@*M~a1HafUA!gIP=T4H@H-CUAY*vlE;YQab(I2Wd zZpx^wE3frOeN-Z>U>5$=F~yMF`VUf9clua%KRv}%S08~EbdbkA2^Iyes`-K;ib86BGoe__Le$@Nrc<>4D>hga+PJiNP4d z*6i?jy#5cs9!Xb<0hFPzoLxvgU2+=#Q|J0v`;t(Ruz>6f~N%rNz&H;AkmX}Q+0n8YDve$<%1ouu`;B*9L{fb>};`#~J(Wqw17{8=X^W^tjl`;kL2tTn_j{ zfcX-vU8Llr17=evH|9=k7&XR+hZ7F&zqcX}nh{)3VX?@340y zZ0_0wR!0RMhU!U+i5?z}4iu`4d7+~He!Z{bb+NtltXg?6OSb#-tH7;U%vJ#C_DBgo zRaJ(JIW4Um1eg8$jFI3)#m>XJ29*o)Blz@!_|N%97kF^fcIH)FlCS{?1)Pc> zyy5nB`2+fa!}erjbH9#A5H^sSjo|nLKl)Wov5oE4L%Ivu)aaBkQ<7;z|GvR$zwVCW z`zU-IGtezCEvtpDP019koi8nn`oYHP2#ZHyn_;Gqzd`B?>xomwFbe&708W>G(w3Xm z1u=VqE9D%QFN;bmzPe{ss^8Z~^HU-G&G1;NBy;-TjA)?9 z`~lqw`zI>)t&G2_!9Okj)>6zCQ}SKk`k|LH`X;!0JgsDWFd(ogNwj{??05jGunZxQ zbw?3@t79QT=^OI0S=QXA;3CV-eic>w9c*0%++LdQHQtCkQaHs!!YHC+b|qKhN!Rt( zdBA6Pp(3wAGdv&vLyc)tNVx4fyHLx1k#dP5C~- zv&fk4;L5#7Ys>@&r1RACb8m3{lFXSZ6ba_I9`}3oCQbT^^AVarw6))ts$Z?^^^-t7 zk}CdQLl)_j&H~NLq|X*Vdp?XJ)ZSOBF(Njabhvh#iQZ(Z4%p;s`sQ7Mt$=h!B*5uT zD8pnDKZ|8{KsanMw$n&_E@RD}{r4L~m7!1X>cb)js)mvRS;Rn*VhrUuBSS*XtL^kN zypK4vyI^W{4e@49*8s@A3hN}a?~Bli014M15z4o+gU}pD37P~=wO>lr9NmwQ&n=!Q zMf?x-PWpFT@*$XkYO1n#N&U$9O~3w@izkC{kq?uL5M`3SjxCQPJiT4&uH3qNI&5c0 zOQ=%2tO<%)d1^4)vHTz_IwR$ev!$tYy79SQK>A|H_tf(qG3+;%zG+ zWA`@Ha;>VAA!6K`Hnc1rYxhr!-LGMGL#=9o;FBL-Y%B+KK${*2b}T(1J$PRGY00J$ zu~ct~hN(JW%NX6wUfMPjb3Z=T)nMEKOJL`hl};qQ5@LZ)lDe&FuNs0Rz4$Rz{W{*F zp|?EW>x-!9bIy?JX^i&#ong}ca~I|O1CaiWc|>|3Es5;eLRMYbTo%B2@} zKxh0!c^=*EVd0a279;(x5yRmfANvr}oz`~1_u{1-%#T<08iGFs()E?#(*np{miBn< zsHMDH?*gJal-j)ZuIJl;K&NpbGr0m3ASN8NG8dwqNp-Xzi0@Fo&Ie~+$!s|BO2FmC zNJm3Yq+1YPUHwZ8(Gy_)UWlYAwcB~%wB*~uOCk+!|JJ)L)NGph%{0YUA!5X#X85A2 z_Uj|PK`z@Yh`C(#WCQbUdb!=5k6=l3D}kl3v{<=7F7j`-?TrpD@D-}je{HZ4CP2s= zB>II+X<={p=!2w9@Ovg=9Y{QaGgVN#L#u`h-Lw##hKZ)EH;{}op*9}y2PE=^rFj;y zY$sA6Y)M7ZNru=wRg}7hU~u-5O77^j4%ik?s#M{a^0D**Jec~T=Wd5+GJSo0wR2al zVxoQyrwKjckIks7+{N5nAiK=hnN9z2kBfNa)ZA6h{=)7&!vSEzFWVDHji3RCoTX7wel@C9vOJMf^=n(HO9t{}KezW7$44V0>_?h>3;$5zGpF<}E zg;J@R5t^?g3abQbk8?F}wn36nYPSB^`_0ljoR}F+#hT&_j2+qQ{~48UE(^`u_0VWm z%4?EG?;*IE$6#+I6Zl3tavh7dQ;%UDQN}1o9$VV9U(#@!vq};WtjGNGT2rTj=xGPE zH0p_y@$~!Z*Z`l)N_r86kD-+LdnYehKOO@Z;CZ%!W3^lX1?z%<);VO~f_na|m6hxH zp*ssFwR`+hg4tCcymTM4;>VE|B+KGY^qMJYqDRO?gg^Ka1}u^-pK+Pd;@ij`b-)8q z+zJbM4_ngwTgBWsp_*?=lWds0vQnU5KWKk5u;of|)n)JXW64uo`gd7WcjEX5@fD?% z(JM}0LcujJwh%5vsr|W|dPs6*<@Qa8!?hSQaQBe!(QOPVC-Z7}Ez8TM<;pnwF5!tG z)p4jZ<~q_OgnYIn2sQAe5FJ%i1TF^7hl5bg{5||6ry>tN9r6Pumxu?$@+XCFWl-s{ z6`z)RV5wXP^DJhdJREwVt++ZSo7;~KGj-miV{S+4V;q}(9~6~im#>6z@zPk;%Sr;X z`~C!zo&V;exi~3VVcu!JdHM5}%tc;=mwr~I1_{fGs1=7UHgHMa^^RL%Ow)F*vxgWA z*6t4y5rALbXhl)0N{v`#EKlOmB(rel%0FA*Fk-mK7ardo2xMaIBz066=S)PFU_{Zx zwV1Z=W}B_0T0fpkW-W5jZgIb-yVONm%3XL!PsWjBGA3v=3nFE(Gjli}{boCa^GBy< z@k$eXQs98^tTk>~4sWd}C&sCz_^sV*);&wTDChl<_v3m+NKd(gXXD_JgGm3mp@Iv) zm}7sbg_#Se4iM$DN%FoNbMF+_!VEz#MG|r z>xz?YLs6%-9jhqb3i1fAV65wYna*NAlc_8gypdP&wnZ zkAD2O`aq!mZzY{(7zV;ICTOEEhQP@je~Lqu-Im17Mzp6CVt>AP#Tz*m%ZUz~mAe~c zu5M-i42e@j6ak@ViyZO@s|$0Rdw@vb&@!dC)3+2Ua$MfGE&IXFcv5H;H0j}WE`-nK zJDUDW*PYLZo3h67a~)8ZhhjVR*(mR*fr=(+v7Hw$-4ErHtO|gcChZF3r$L=o?wKhJ(`Pf= zg37htIWoU(Pf`VsrD{Q_0wo{w8hcV)yHHx{%VD8ry!jh%=E zK$H}4o|}Fk1Vgf(Pg9iTG=#LuuYG?cao-Dhqxi zMWvNBVzNgkEbR*xk)2@z4d~X4Tf}_UGF=jgc>lg{$3o=OxF=$w;ws@yO6whGF?^r! zv8l|{=Fm&$v0+|pl6$-d(Uij#QkZ}>X*t^5O_m20)nEJ%E}Vt);Y@!9|EBm{S-A2S zdEAH8-Q)H-9++!=%L89l?;E^)rmCLKltS75dR8r2j|4_!W9-$U^`Qd_RW7bTCRdu2 zbFnRA?++5?d+9=PLd@Z$tDLB`&D!4fFOdvUBB8W}G4>|QMhF6MnELs05lVNey(79& zP}*W$0$hRA=Q>3a)Q#MGxC!ud%~sh8TeoSnf|h&?xVO{y9mjEgIK!U|$LfJ+$&En5zzSncPH$a!)- z7vid|%rF&o>ORa^v+1n(8bt>to#DhPfaGky*L{)A7v3%Ra&Vq79n`+)uQ^E`gDb6m zjbE?f_j0;dD$4R#IqbPY@X7ut7Jddlam3?Wa-T{cqJSrgEo~mH5h@X;5ZY!Zk^iGN zc;*Y1nd8`f)nIcV3gq|Q6c64+!$5NAHMU4c4y&p0)85@+Ztkm{uocONz7Oz3Jsn4f znyKYg8_230j{G0ooSAOeCg1BV377_sETO!e-dBB7GO%Tl3q%lo>$ntbHwidDAWO z&_ZDkp$`e^ORT!xZxXvLLK<6Uf+2gJ3+!#+*+%o2PMVjo`4^4Qm2=i@5=n>_t<#;b zJ1E85c|)4TJymfd)c%k_#$it)F?dsR_V*FKM|6gi3Q4mTD+6mf3d3fLND~cG;@6t? z4SU6NfqG9{y^o&PCVce$Hbgo;S^E&&< z#(?bLS-}7ABYz~hl3U7cIW?uZ!H>GE+}*dkrf;WE6<-h@CrrWltYsh(Qp^a$d8gB| zi!lw=iL7f5h`~~zWSA5U7i-{~wlED}9q-7;u)@~bcoq=Ynw_3HyF^Jn8YBpq}lYI%#7f`+^S?h_A09CAQH$i7-O z?Q8oTgwv!B+w*}3Z>I}N6?Uw^vETDI0!0;Fqztu*_gB+$dJcIz`9%#H^Ob~Z9YXxw zuSzAcwTQ(Q2m)IFvGc-bQiocx{OWn)SKD&_k>>Uf+0ydj5QH>Y-zxXpyaohiwTV}} zw~wPvMvUd&j$}7EvAXqIaS^z{(yT1oeiH-%+}O{| z1e)coj>$#(2t@kZq2;SviX>C?K> z)D3e&046m%eB}R{dD3_&ysop)*ke>f#@K2I4Ov2#FqUjH!&tJ7kr0I%OoWE9GxjA* z#@I5l^e2i$%80BX5*o=af7zlMJ=61kdOy71-!J#mIp^NrJ^Q)$oDqpEqvJJY(!hjG z@ok2{n`No0yV>e5qJ-o(4IGW5?rKI^_r}LLOe0b|0@dCv$A`-m#TZh4S;z5Mu5><; zCK_Fo-yY~2nE&k{@ZF!frlf8JjU&ISy+F0K=7}2@6iJeSH_;q8>{v=iGU2%fxcN^B z!1^Ri2e7NyL*YxxVAm*~yKgv%9kAYI0IM4&;T4cAA{}a$zxHJ(qVIg48KAO%k2b<4 zhZaiLWFz3iuuWqi!pL7{mBl;iZ`x`O`TW`Bx1TV@n69ItanO5Lxq60V#tl_{%B_L_ zwWQ;hjS=yE06`=YnM{LW(nAXc+YAL{pB#joFT4b~a6<(2*I$?;LCDuIw}yA?#>XkN zXccS?&&!`d;;+OwX~G4SeKEZt0vwQ(Bchl3p|)+9?+RA&$j2Of@xT~Z%2ijtPQ1}D zzoT)A%+k^f04XC8-rrm2C*r1v$v@1LVRYT$t)ZkDBg}xcm06>I4=>G$=FNexDR+99 zVeqtR(|q*(@lg{(Dnl#uF82ruG&qB3;P%|@7f)ZOkuhE?fge(t?IYy%_-pu0yZBWolMr^sdJi z@d~j*oy*uKoTh0(I?=gCGI8#E&dNOc)aqxmptXFTo6tj z5&I;WZl7<K?gYwTz+{lQ0;=2WGoYpnhD5s~ z3>lK2h9)Z03ruzA~f2>wg3R#bF~o4+@}K5`}r?Z34xjrB3z43C~P>-ydCi znDaHqX+#4rbuge1{$C+<2+sqY?^FG3WtajJMVd8)!gaEU~!WGBg zR?m5fpnjqDMk9;$+{d?8$!Q@YN5vmZT|`g!PEK7Fdw9c$1L1gC(P^XXkGK?u|OAFUb3> zmQ0pNbxIw?prqY3T~8%GEYDVbx>*rbY510wt+-~S?JjSEZB3}};vttBx%R5HNPdjL zJ*7N*y(}jSg0ooS5q%(*H*SBmInX$?tVl9p$1m#R;;!F|oG%+*k0Ug8`1)BWLIee8nat&|?v#aWxv znJBq%iJh4eR)(n@psMxJhNxjlS9|`W#5GHt^%=)_$D+SOr~Uv`Rrm9a@6It{G*6i$ z7$O@&BumvOItjSP8fXXcmOGFclxCQn=ZcIQCk4Q4nY;!*?vH*`?-D(Cs(X+XFLu_y}BATK)Z%)7RPh8wd z2!1CSn-q{if1V$T^|%E-6jMQ;Ul}MD@F-K;IkoP1$Hr$1dq z?+Ccp-g|b$Mc0ec^_xRy;Wk$Er3xF7w^FJ;Z?vvXM_#Mbb8+O5F2^ic@2|7@oKko) z`5rL0cQii`8GVLJp>sZWaV6^fcU9ojkCqEPZe|6t1WCA;mF+R^;kzkDtwPpM(2Nfj z?b{8PCTLtKH$2rHQ5k5qN?JG1ePjkeiCh>haHdnesCz1MV_>+O<}`{o&l)T^>iQ}k zoo6xemztW-7E>tqE zjp*+(4ae-gO6MW*m6i9~)m`bEp&}|5OPA|ChDko{CEFc~K-LAg361OJV|*gD!NzB- zdp|P(5KC}WDGvr^jvSkMIn+zn8bIlS;FApLZpN?r*p7DXYG)k?s|(0JG(UVrdtLb_ ze}OYof>$1C*`5r17WLcK&79_f-L2AnxOj*e3)YxJ$a^3BhJXU(bcS(DqB~Ou^c2&u z>b_trVuEnPdGPBuW)0QEEn!i=9xBbg?cPD*)5V&;2F$vME zT|CwW-5#Z>%Z7`AzVFi!Q;FqlDG?3WwI+>rl<)1IEGKn&DSZ|A0E|Rig3%)Z{@T~~`1TsXn?Au568?(g+ren^3u1t{CjM&_K z0pFL+utq#?01}l_Olj+5rVEv?9y(mZ0VDWYses&z5tn*Coqk-PKfH2FO&eI%Wn8Rv zf_#iJJi=8RGUvSU4%Q_LZLvNFk?7=)wowUG0y7OJfxs1B%rojvUse7}h<_MpHrYL{ z_0zNbD%1_#)UnMTw@n!pRq~^M=vGnq;?Y^0h};rL&&o-y*1!(ZkvU{7g2eFU-qLb! z=cx4N;~u)V5Uqcnlq~#(6!Jojw~c-6&o42;t?6_8uHX5&_VoxAqOFtG?^q*1zPDg+ z2incdlN7e#UQ=GJ8BWC(>p6r9&_Sg5b4XuPivE`;K2^;1J0jl*rYAf4BNWgSK%bQ5 zmTsGX_s>sbeKt%ouZKe6F0ScgVt?RZfy={%>@auLw!9O#RQW(t~eY?{X zjZW-)owi?D@4dW*BMM4`#)?@>tIAV*KhReMyLu(8f+u-c0hQkT>_j&B_Mec9r|JIZ z^-rdIP*>SY-S@<2{+%3QO+dOP*VnvMt&#gUa$Zb-4%_zN!^wf;FCIR@?+f2DP$xx5 zt#`kY(W;Zs!eYcq^%^YBD*pCMHPr0Z2QLlPn(6{Oyl8fKszT8J zt99TH+u^XXG;vYMi#6>{9*=OsU-QI!>v-K}W!K)v)Zl8W%5ZgMRaJXcEu9NmI%@E9 oaJUW}&K~ks;eR3A47}!d{qFyba0eEY%R)G2fv_>DH^RpJ2Z|Ik82|tP literal 0 HcmV?d00001 From 78603bd004f784cfc21bed5bdea6ff8f97c3bbae Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 14 Apr 2021 16:25:17 -0700 Subject: [PATCH 012/260] updated config.json to be compatible with latest HTAN.jsonld --- www/config.json | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/www/config.json b/www/config.json index 3f264dab..d3144027 100644 --- a/www/config.json +++ b/www/config.json @@ -1,20 +1,35 @@ { "manifest_schemas": [ {"display_name": "scRNA-seq Level 1", "schema_name": "ScRNA-seqLevel1", "type": "assay"}, + {"display_name": "scRNA-seq Level 2", "schema_name": "ScRNA-seqLevel2", "type": "assay"}, + {"display_name": "scRNA-seq Level 3", "schema_name": "ScRNA-seqLevel3", "type": "assay"}, + {"display_name": "scRNA-seq Level 4", "schema_name": "ScRNA-seqLevel4", "type": "assay"}, {"display_name": "scATAC-seq Level 1", "schema_name": "ScATAC-seqLevel1", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 1", "schema_name": "BulkRNA-seqLevel1", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 2", "schema_name": "BulkRNA-seqLevel2", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 3", "schema_name": "BulkRNA-seqLevel3", "type": "assay"}, - {"display_name": "Bulk DNAseq Level 1", "schema_name": "BulkWESLevel1", "type": "assay"}, - {"display_name": "Bulk DNAseq Level 2", "schema_name": "BulkWESLevel2", "type": "assay"}, - {"display_name": "Bulk DNAseq Level 3", "schema_name": "BulkWESLevel3", "type": "assay"}, + {"display_name": "Bulk WES Level 1", "schema_name": "BulkWESLevel1", "type": "assay"}, + {"display_name": "Bulk WES Level 2", "schema_name": "BulkWESLevel2", "type": "assay"}, + {"display_name": "Bulk WES Level 3", "schema_name": "BulkWESLevel3", "type": "assay"}, {"display_name": "Imaging Level 2", "schema_name": "ImagingLevel2", "type": "assay"}, {"display_name": "Clinical Tier 1: Demographics", "schema_name": "Demographics", "type": "clinical"}, {"display_name": "Clinical Tier 1: Diagnosis", "schema_name": "Diagnosis", "type": "clinical"}, {"display_name": "Clinical Tier 1: FamilyHistory", "schema_name": "FamilyHistory", "type": "clinical"}, {"display_name": "Clinical Tier 1: Exposure", "schema_name": "Exposure", "type": "clinical"}, {"display_name": "Clinical Tier 1: FollowUp", "schema_name": "FollowUp", "type": "clinical"}, + {"display_name": "Clinical Tier 1: Molecular Test", "schema_name": "MolecularTest", "type": "clinical"}, {"display_name": "Clinical Tier 1: Therapy", "schema_name": "Therapy", "type": "clinical"}, + {"display_name": "Clinical Tier 2", "schema_name": "ClinicalDataTier2", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Acute Lymphoblastic Leukemia", "schema_name": "AcuteLymphoblasticLeukemiaTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Breast Precancer and Cancer ", "schema_name": "BreastCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Colorectal Precancer and Cancer", "schema_name": "ColorectalCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Lung Precancer and Cancer", "schema_name": "LungCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Neuroblastoma and Glioma", "schema_name": "BrainCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Melanoma", "schema_name": "MelanomaTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Ovarian Precancer and Cancer ", "schema_name": "OvarianCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Pancreatic Precancer and Cancer", "schema_name": "PancreaticCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Prostate Precancer and Cancer", "schema_name": "ProstateCancerTier3", "type": "clinical"}, + {"display_name": "Clinical Tier 3: Sarcoma", "schema_name": "SarcomaTier3", "type": "clinical"}, {"display_name": "Biospecimen Tier 1 & 2", "schema_name": "Biospecimen", "type": "biospecimen"}, {"display_name": "Other Assay (Minimal Metadata)", "schema_name": "OtherAssay", "type": "assay"} ], From 94371faa5bb2d5f09f83af35c21a5cbb6e0ded25 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Wed, 14 Apr 2021 21:41:02 -0400 Subject: [PATCH 013/260] add missed codes --- app.R | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app.R b/app.R index 2624bc3a..ed86ebd1 100644 --- a/app.R +++ b/app.R @@ -265,7 +265,7 @@ server <- function(input, output, session) { tryCatch( { ### logs in - syn_login(sessionToken = input$cookie, rememberMe = FALSE) + syn_login(sessionToken = token, rememberMe = FALSE) ### welcome message output$title <- renderUI({ @@ -276,7 +276,7 @@ server <- function(input, output, session) { ### updating global vars with values for projects # synStore_obj <<- syn_store(config$main_fileview, token = input$cookie) - synStore_obj <<- syn_store(token = input$cookie) + synStore_obj <<- syn_store(token = token) # get_projects_list(synStore_obj) projects_list <<- syn_store$getStorageProjects(synStore_obj) @@ -589,7 +589,9 @@ server <- function(input, output, session) { validation_res <- "invalid" # mismatched template index inx_mt <- which(sapply(annotation_status, function(x) grepl("Component value provided is: .*, whereas the Template Type is: .*", x[[3]]))) - + # missing column index + inx_ws <- which(sapply(annotation_status, function(x) grepl("Wrong schema", x[[2]]))) + if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template waiter_msg <- "Mismatched Template Found !" From 47fb2a62b996d2c7e06a7c5fced102c914c5c19f Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Wed, 14 Apr 2021 21:46:20 -0400 Subject: [PATCH 014/260] remove local test code --- app.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.R b/app.R index ed86ebd1..e03a4d5e 100644 --- a/app.R +++ b/app.R @@ -265,7 +265,7 @@ server <- function(input, output, session) { tryCatch( { ### logs in - syn_login(sessionToken = token, rememberMe = FALSE) + syn_login(sessionToken = input$cookie, rememberMe = FALSE) ### welcome message output$title <- renderUI({ @@ -276,7 +276,7 @@ server <- function(input, output, session) { ### updating global vars with values for projects # synStore_obj <<- syn_store(config$main_fileview, token = input$cookie) - synStore_obj <<- syn_store(token = token) + synStore_obj <<- syn_store(token = input$cookie) # get_projects_list(synStore_obj) projects_list <<- syn_store$getStorageProjects(synStore_obj) From 5fa0726b1478e1e5ef05312b1847db4613a53e2e Mon Sep 17 00:00:00 2001 From: Rongrong Chai Date: Tue, 20 Apr 2021 14:06:45 -0400 Subject: [PATCH 015/260] rm helper msg --- app.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app.R b/app.R index 0a2ee476..953a2463 100644 --- a/app.R +++ b/app.R @@ -127,8 +127,7 @@ ui <- dashboardPage( solidHeader = TRUE, status = "primary", width = 12, - DT::DTOutput("tbl"), - helpText("Google spreadsheet row numbers are incremented from this table by 1") + DT::DTOutput("tbl") ), box( title = "Validate Filled Metadata", From e9e05654562eb4a39fc085d2e621296cb6905a1e Mon Sep 17 00:00:00 2001 From: Rongrong Chai Date: Tue, 20 Apr 2021 14:19:17 -0400 Subject: [PATCH 016/260] rm msg --- app.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app.R b/app.R index f2783624..d77701a1 100644 --- a/app.R +++ b/app.R @@ -172,9 +172,8 @@ ui <- dashboardPage( solidHeader = TRUE, status = "primary", width = 12, - DT::DTOutput("tbl"), - helpText("Google spreadsheet row numbers are incremented from this table by 1") - ), + DT::DTOutput("tbl") + ), box( title = "Validate Filled Metadata", status = "primary", From 6fab30c9d2b2ebee5f99de75aba6a346e6fe9aa4 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 20 Apr 2021 21:04:05 -0700 Subject: [PATCH 017/260] moved necessary python files to python directory --- metadataModelFuns.py | 37 ------------------- python/metadata_model.py | 14 +++++++ .../synapse_func_alias.py | 0 synStoreFuns.py | 30 --------------- synStore_Session.py | 31 ---------------- 5 files changed, 14 insertions(+), 98 deletions(-) delete mode 100644 metadataModelFuns.py create mode 100644 python/metadata_model.py rename synLoginFun.py => python/synapse_func_alias.py (100%) delete mode 100644 synStoreFuns.py delete mode 100644 synStore_Session.py diff --git a/metadataModelFuns.py b/metadataModelFuns.py deleted file mode 100644 index 830886ea..00000000 --- a/metadataModelFuns.py +++ /dev/null @@ -1,37 +0,0 @@ -# import json -from schematic.models.metadata import MetadataModel - -from schematic import CONFIG - -config = CONFIG.load_config("./schematic/config.yml") - -#inputMModelLocation = "./schemas/exampleSchemaReq.jsonld" -#inputMModelLocation = "./HTAN-data-pipeline/schemas/scRNASeq.jsonld" -# inputMModelLocation = "./HTAN-data-pipeline/schemas/HTAPP.jsonld" -inputMModelLocation = CONFIG["model"]["input"]["location"] -inputMModelLocationType = CONFIG["model"]["input"]["file_type"] - -manifest_title = CONFIG["manifest"]["title"] -manifest_data_type = CONFIG["manifest"]["data_type"] -# datasetType = "scRNASeq" -# modelType = "TableA" - -metadata_model = MetadataModel(inputMModelLocation, inputMModelLocationType) -metadata_model.getModelManifest(title=manifest_title, - rootNode=manifest_data_type) - -### function for getting model Manifest -# mm.getModelManifest(modelType, additionalMetadata = {"Filename":["MantonCB1_HiSeq_1_S1_L001_R1_001.fastq.gz"]} ) -# getModelManifest = mm.getModelManifest - -# ### function for validating manifest -# # mm.validateModelManifest(manifest_path, datasetType) -# validateModelManifest = mm.validateModelManifest - -# ### populates manifest with path to csv -# populateModelManifest = mm.populateModelManifest - -# ### gets dependencies -# # "Generating dependency graph and ordering dependencies") -# # dependencies = mm.getOrderedModelNodes(component, "requiresDependency") -# getDependencies = mm.getOrderedModelNodes diff --git a/python/metadata_model.py b/python/metadata_model.py new file mode 100644 index 00000000..92883cb1 --- /dev/null +++ b/python/metadata_model.py @@ -0,0 +1,14 @@ +from schematic.models.metadata import MetadataModel +from schematic import CONFIG + +config = CONFIG.load_config("./schematic/config.yml") + +inputMModelLocation = CONFIG["model"]["input"]["location"] +inputMModelLocationType = CONFIG["model"]["input"]["file_type"] + +manifest_title = CONFIG["manifest"]["title"] +manifest_data_type = CONFIG["manifest"]["data_type"] + +metadata_model = MetadataModel(inputMModelLocation, inputMModelLocationType) +metadata_model.getModelManifest(title=manifest_title, + rootNode=manifest_data_type) diff --git a/synLoginFun.py b/python/synapse_func_alias.py similarity index 100% rename from synLoginFun.py rename to python/synapse_func_alias.py diff --git a/synStoreFuns.py b/synStoreFuns.py deleted file mode 100644 index 47b979f1..00000000 --- a/synStoreFuns.py +++ /dev/null @@ -1,30 +0,0 @@ -###!!!! use synStore_Session for server instead -import synapseclient -from SynapseStorage import SynapseStorage - -syn_get = syn.get - -storage_fileview = "syn20446927" - -syn = synapseclient.Synapse() -syn.login() - -syn_store = SynapseStorage(storage_fileview, syn) - -### "Testing retrieval of project list from Synapse -get_projects_list = syn_store.getStorageProjects() - -###print("Testing retrieval of folder list within a given storage project from Synapse") -#"syn19557917" -get_folder_list = syn_store.getStorageDatasetsInProject - -### print("Testing retrieval of file list within a given storage dataset from Synapse") -# "syn19557948" -get_file_list = syn_store.getFilesInStorageDataset - -### print("Testing association of antities with annotation from manifest") -# "./synapse_storage_manifest.csv", "syn20685746" -get_manifest_syn_id = syn_store.associateMetadataWithFiles - - - diff --git a/synStore_Session.py b/synStore_Session.py deleted file mode 100644 index f563b587..00000000 --- a/synStore_Session.py +++ /dev/null @@ -1,31 +0,0 @@ -from schematic.store.synapse import SynapseStorage - -syn_store = SynapseStorage - -### "Testing retrieval of project list from Synapse -# get_projects_list = syn_store.getStorageProjects - -###print("Testing retrieval of folder list within a given storage project from Synapse") -# get_folder_list = syn_store.getStorageDatasetsInProject - -### print("Testing retrieval of file list within a given storage dataseyt from Synapse") -# get_file_list = syn_store.getFilesInStorageDataset - -### print("Testing association of antities with annotation from manifest") -# get_associated_manifestId = syn_store.associateMetadataWithFiles - -### getting all manifests associated with a project accessible by user -### returns a list, empty if manifest isn't there -# [('syn20687304', 'HCA immune cells census'), -# ('syn20703799', 'Ischaemic Sensitivity of Human Tissue'), -# []), -# ( ('syn20687304', 'HCA immune cells census'), -# ('syn21682582', 'Test'), -# ('syn21682585', 'synapse_storage_manifest.csv'))] -# get_all_manifests = syn_store.getAllManifests - -### updating fileset in a manifest associated with a dataset -#manifestId = syn_store.update_dataset_manifest_files(dataset_id) -# returns '' if no manifest exists -# depends on fileview so it may take a few min for new files to show -# get_update_manifestId = syn_store.updateDatasetManifestFiles \ No newline at end of file From 403b12797edaf8fc76e874ca872d4383770ea30c Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 20 Apr 2021 21:06:52 -0700 Subject: [PATCH 018/260] package management with renv for Data Curator App --- renv.lock | 566 ++++++++++++++++++++++++++++++++++++++++++++++ renv/.gitignore | 3 + renv/activate.R | 157 +++++++++++++ renv/settings.dcf | 5 + 4 files changed, 731 insertions(+) create mode 100644 renv.lock create mode 100644 renv/.gitignore create mode 100644 renv/activate.R create mode 100644 renv/settings.dcf diff --git a/renv.lock b/renv.lock new file mode 100644 index 00000000..776c6bfd --- /dev/null +++ b/renv.lock @@ -0,0 +1,566 @@ +{ + "R": { + "Version": "3.6.3", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cran.rstudio.com" + }, + { + "Name": "Sage", + "URL": "http://ran.synapse.org" + } + ] + }, + "Packages": { + "BH": { + "Package": "BH", + "Version": "1.72.0-3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "8f9ce74c6417d61f0782cbae5fd2b7b0" + }, + "DT": { + "Package": "DT", + "Version": "0.17", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "56b33b77f4cffd78ff96b8e5a69eabb0" + }, + "MASS": { + "Package": "MASS", + "Version": "7.3-51.6", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1dad32ac9dbd8057167b2979fb932ff7" + }, + "Matrix": { + "Package": "Matrix", + "Version": "1.2-18", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "08588806cba69f04797dab50627428ed" + }, + "R6": { + "Package": "R6", + "Version": "2.4.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "292b54f8f4b94669b08f94e5acce6be2" + }, + "RColorBrewer": { + "Package": "RColorBrewer", + "Version": "1.1-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "e031418365a7f7a766181ab5a41a5716" + }, + "Rcpp": { + "Package": "Rcpp", + "Version": "1.0.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "125dc7a0ed375eb68c0ce533b48d291f" + }, + "askpass": { + "Package": "askpass", + "Version": "1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "e8a22846fff485f0be3770c2da758713" + }, + "base64enc": { + "Package": "base64enc", + "Version": "0.1-3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "543776ae6848fde2f48ff3816d0628bc" + }, + "cli": { + "Package": "cli", + "Version": "2.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "be982c9bcbfbe9e59c0225b0ed37d47e" + }, + "colorspace": { + "Package": "colorspace", + "Version": "2.0-0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "abea3384649ef37f60ef51ce002f3547" + }, + "commonmark": { + "Package": "commonmark", + "Version": "1.7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "0f22be39ec1d141fd03683c06f3a6e67" + }, + "cpp11": { + "Package": "cpp11", + "Version": "0.2.7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "730eebcc741a5c36761f7d4d0f5e37b8" + }, + "crayon": { + "Package": "crayon", + "Version": "1.3.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "0d57bc8e27b7ba9e45dba825ebc0de6b" + }, + "crosstalk": { + "Package": "crosstalk", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2b06f9e415a62b6762e4b8098d2aecbc" + }, + "curl": { + "Package": "curl", + "Version": "4.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2b7d10581cc730804e9ed178c8374bd6" + }, + "data.table": { + "Package": "data.table", + "Version": "1.14.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d1b8b1a821ee564a3515fa6c6d5c52dc" + }, + "digest": { + "Package": "digest", + "Version": "0.6.25", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f697db7d92b7028c4b3436e9603fb636" + }, + "dplyr": { + "Package": "dplyr", + "Version": "1.0.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d0d76c11ec807eb3f000eba4e3eb0f68" + }, + "ellipsis": { + "Package": "ellipsis", + "Version": "0.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" + }, + "fansi": { + "Package": "fansi", + "Version": "0.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "fea074fb67fe4c25d47ad09087da847d" + }, + "farver": { + "Package": "farver", + "Version": "2.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c98eb5133d9cb9e1622b8691487f11bb" + }, + "fastmap": { + "Package": "fastmap", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "83ab58a0518afe3d17e41da01af13b60" + }, + "fs": { + "Package": "fs", + "Version": "1.5.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "44594a07a42e5f91fac9f93fda6d0109" + }, + "generics": { + "Package": "generics", + "Version": "0.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4d243a9c10b00589889fe32314ffd902" + }, + "ggplot2": { + "Package": "ggplot2", + "Version": "3.3.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3eb6477d01eb5bbdc03f7d5f70f2733e" + }, + "glue": { + "Package": "glue", + "Version": "1.4.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f43e0d5e85ccb0a4045670c0607ee504" + }, + "gtable": { + "Package": "gtable", + "Version": "0.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ac5c6baf7822ce8732b343f14c072c4d" + }, + "htmltools": { + "Package": "htmltools", + "Version": "0.5.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "af2c2531e55df5cf230c4b5444fc973c" + }, + "htmlwidgets": { + "Package": "htmlwidgets", + "Version": "1.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6fdaa86d0700f8b3e92ee3c445a5a10d" + }, + "httpuv": { + "Package": "httpuv", + "Version": "1.5.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4e6dabb220b006ccdc3b3b5ff993b205" + }, + "httr": { + "Package": "httr", + "Version": "1.4.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7146fea4685b4252ebf478978c75f597" + }, + "isoband": { + "Package": "isoband", + "Version": "0.2.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b2008df40fb297e3fef135c7e8eeec1a" + }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.7.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "98138e0994d41508c7a6b84a0600cfcb" + }, + "labeling": { + "Package": "labeling", + "Version": "0.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3d5108641f47470611a32d0bdf357a72" + }, + "later": { + "Package": "later", + "Version": "1.1.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d0a62b247165aabf397fded504660d8a" + }, + "lattice": { + "Package": "lattice", + "Version": "0.20-41", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "fbd9285028b0263d76d18c95ae51a53d" + }, + "lazyeval": { + "Package": "lazyeval", + "Version": "0.2.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "d908914ae53b04d4c0c0fd72ecc35370" + }, + "lifecycle": { + "Package": "lifecycle", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3471fb65971f1a7b2d4ae7848cf2db8d" + }, + "magrittr": { + "Package": "magrittr", + "Version": "1.5", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1bb58822a20301cee84a41678e25d9b7" + }, + "mgcv": { + "Package": "mgcv", + "Version": "1.8-31", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4bb7e0c4f3557583e1e8d3c9ffb8ba5c" + }, + "mime": { + "Package": "mime", + "Version": "0.9", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "e87a35ec73b157552814869f45a63aa3" + }, + "munsell": { + "Package": "munsell", + "Version": "0.5.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6dfe8bf774944bd5595785e3229d8771" + }, + "nlme": { + "Package": "nlme", + "Version": "3.1-148", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "662f52871983ff3e3ef042c62de126df" + }, + "openssl": { + "Package": "openssl", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b3209c62052922b6c629544d94c8fa8a" + }, + "pillar": { + "Package": "pillar", + "Version": "1.5.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "24622aa4a0d3de3463c34513edca99b2" + }, + "pkgconfig": { + "Package": "pkgconfig", + "Version": "2.0.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "01f28d4278f15c76cddbea05899c5d6f" + }, + "plotly": { + "Package": "plotly", + "Version": "4.9.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f6b85d9e4ed88074ea0ede1aa74bb00e" + }, + "promises": { + "Package": "promises", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a8730dcbdd19f9047774909f0ec214a4" + }, + "purrr": { + "Package": "purrr", + "Version": "0.3.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "97def703420c8ab10d8f0e6c72101e02" + }, + "rappdirs": { + "Package": "rappdirs", + "Version": "0.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "8c8298583adbbe76f3c2220eef71bebc" + }, + "renv": { + "Package": "renv", + "Version": "0.11.0-3", + "Source": "GitHub", + "RemoteType": "github", + "RemoteHost": "api.github.com", + "RemoteRepo": "renv", + "RemoteUsername": "rstudio", + "RemoteRef": "master", + "RemoteSha": "caf0b39c883168cdd5ebd55a547f6d8689ab8712", + "Hash": "094b6d0b0fe28b14a6780dad836f6356" + }, + "reticulate": { + "Package": "reticulate", + "Version": "1.16", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5db95d35ae4605b46cea66b6e3bcab3e" + }, + "rjson": { + "Package": "rjson", + "Version": "0.2.20", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7d597f982ee6263716b6a2f28efd29fa" + }, + "rlang": { + "Package": "rlang", + "Version": "0.4.10", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "599df23c40a4fce9c7b4764f28c37857" + }, + "rstudioapi": { + "Package": "rstudioapi", + "Version": "0.11", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "33a5b27a03da82ac4b1d43268f80088a" + }, + "sass": { + "Package": "sass", + "Version": "0.3.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3ef1adfe46b7b144b970d74ce33ab0d6" + }, + "scales": { + "Package": "scales", + "Version": "1.1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6f76f71042411426ec8df6c54f34e6dd" + }, + "shiny": { + "Package": "shiny", + "Version": "1.5.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ee4ed72d7a5047d9e73cf922ad66e9c9" + }, + "shinydashboard": { + "Package": "shinydashboard", + "Version": "0.7.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "133639dc106955eee4ffb8ec73edac37" + }, + "shinyjs": { + "Package": "shinyjs", + "Version": "2.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "9ddfc91d4280eaa34c2103951538976f" + }, + "shinypop": { + "Package": "shinypop", + "Version": "0.0.1.930", + "Source": "GitHub", + "RemoteType": "github", + "RemoteHost": "api.github.com", + "RemoteRepo": "shinypop", + "RemoteUsername": "dreamRs", + "RemoteRef": "HEAD", + "RemoteSha": "3ab7e384c835f78c42997618d106e2121f4cc50b", + "Hash": "1d9118cbf95a83cee2f98dd5c0dff105" + }, + "shinythemes": { + "Package": "shinythemes", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "30f0ebc41feba25691073626ff5e2cf4" + }, + "sourcetools": { + "Package": "sourcetools", + "Version": "0.1.7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "947e4e02a79effa5d512473e10f41797" + }, + "stringi": { + "Package": "stringi", + "Version": "1.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a063ebea753c92910a4cca7b18bc1f05" + }, + "stringr": { + "Package": "stringr", + "Version": "1.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "0759e6b6c0957edb1311028a49a35e76" + }, + "sys": { + "Package": "sys", + "Version": "3.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "507f3116a38d37ad330a038b3be07b66" + }, + "tibble": { + "Package": "tibble", + "Version": "3.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4d894a114dbd4ecafeda5074e7c538e6" + }, + "tidyr": { + "Package": "tidyr", + "Version": "1.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "450d7dfaedde58e28586b854eeece4fa" + }, + "tidyselect": { + "Package": "tidyselect", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6ea435c354e8448819627cf686f66e0a" + }, + "utf8": { + "Package": "utf8", + "Version": "1.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c3ad47dc6da0751f18ed53c4613e3ac7" + }, + "vctrs": { + "Package": "vctrs", + "Version": "0.3.7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5540dc30a203a43a1ce5dc6a89532b3b" + }, + "viridisLite": { + "Package": "viridisLite", + "Version": "0.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ce4f6271baa94776db692f1cb2055bee" + }, + "waiter": { + "Package": "waiter", + "Version": "0.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "7bfebcea9f02aa9b2821fb4f529031e6" + }, + "withr": { + "Package": "withr", + "Version": "2.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ecd17882a0b4419545691e095b74ee89" + }, + "xtable": { + "Package": "xtable", + "Version": "1.8-4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" + }, + "yaml": { + "Package": "yaml", + "Version": "2.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2826c5d9efb0a88f657c7a679c7106db" + } + } +} diff --git a/renv/.gitignore b/renv/.gitignore new file mode 100644 index 00000000..82740ba9 --- /dev/null +++ b/renv/.gitignore @@ -0,0 +1,3 @@ +library/ +python/ +staging/ diff --git a/renv/activate.R b/renv/activate.R new file mode 100644 index 00000000..924c2d38 --- /dev/null +++ b/renv/activate.R @@ -0,0 +1,157 @@ + +local({ + + # the requested version of renv + version <- "0.8.2" + + # avoid recursion + if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) + return(invisible(TRUE)) + + # signal that we're loading renv during R startup + Sys.setenv("RENV_R_INITIALIZING" = "true") + on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) + + # signal that we've consented to use renv + options(renv.consent = TRUE) + + # load the 'utils' package eagerly -- this ensures that renv shims, which + # mask 'utils' packages, will come first on the search path + library(utils, lib.loc = .Library) + + # check to see if renv has already been loaded + if ("renv" %in% loadedNamespaces()) { + + # if renv has already been loaded, and it's the requested version of renv, + # nothing to do + spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") + if (identical(spec[["version"]], version)) + return(invisible(TRUE)) + + # otherwise, unload and attempt to load the correct version of renv + unloadNamespace("renv") + + } + + # construct path to renv in library + libpath <- local({ + + root <- Sys.getenv("RENV_PATHS_LIBRARY", unset = "renv/library") + prefix <- paste("R", getRversion()[1, 1:2], sep = "-") + + # include SVN revision for development versions of R + # (to avoid sharing platform-specific artefacts with released versions of R) + devel <- + identical(R.version[["status"]], "Under development (unstable)") || + identical(R.version[["nickname"]], "Unsuffered Consequences") + + if (devel) + prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") + + file.path(root, prefix, R.version$platform) + + }) + + # try to load renv from the project library + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) + return(renv::load()) + + # failed to find renv locally; we'll try to install from GitHub. + # first, set up download options as appropriate (try to use GITHUB_PAT) + install_renv <- function() { + + message("Failed to find installation of renv -- attempting to bootstrap...") + + # ensure .Rprofile doesn't get executed + rpu <- Sys.getenv("R_PROFILE_USER", unset = NA) + Sys.setenv(R_PROFILE_USER = "") + on.exit({ + if (is.na(rpu)) + Sys.unsetenv("R_PROFILE_USER") + else + Sys.setenv(R_PROFILE_USER = rpu) + }, add = TRUE) + + # prepare download options + pat <- Sys.getenv("GITHUB_PAT") + if (nzchar(Sys.which("curl")) && nzchar(pat)) { + fmt <- "--location --fail --header \"Authorization: token %s\"" + extra <- sprintf(fmt, pat) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "curl", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { + fmt <- "--header=\"Authorization: token %s\"" + extra <- sprintf(fmt, pat) + saved <- options("download.file.method", "download.file.extra") + options(download.file.method = "wget", download.file.extra = extra) + on.exit(do.call(base::options, saved), add = TRUE) + } + + # fix up repos + repos <- getOption("repos") + on.exit(options(repos = repos), add = TRUE) + repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" + options(repos = repos) + + # check for renv on CRAN matching this version + db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) + if ("renv" %in% rownames(db)) { + entry <- db["renv", ] + if (identical(entry$Version, version)) { + message("* Installing renv ", version, " ... ", appendLF = FALSE) + dir.create(libpath, showWarnings = FALSE, recursive = TRUE) + utils::install.packages("renv", lib = libpath, quiet = TRUE) + message("Done!") + return(TRUE) + } + } + + # try to download renv + message("* Downloading renv ", version, " ... ", appendLF = FALSE) + prefix <- "https://api.github.com" + url <- file.path(prefix, "repos/rstudio/renv/tarball", version) + destfile <- tempfile("renv-", fileext = ".tar.gz") + on.exit(unlink(destfile), add = TRUE) + utils::download.file(url, destfile = destfile, mode = "wb", quiet = TRUE) + message("Done!") + + # attempt to install it into project library + message("* Installing renv ", version, " ... ", appendLF = FALSE) + dir.create(libpath, showWarnings = FALSE, recursive = TRUE) + + # invoke using system2 so we can capture and report output + bin <- R.home("bin") + exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" + r <- file.path(bin, exe) + args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(libpath), shQuote(destfile)) + output <- system2(r, args, stdout = TRUE, stderr = TRUE) + message("Done!") + + # check for successful install + status <- attr(output, "status") + if (is.numeric(status) && !identical(status, 0L)) { + text <- c("Error installing renv", "=====================", output) + writeLines(text, con = stderr()) + } + + + } + + try(install_renv()) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + message("Successfully installed and loaded renv ", version, ".") + return(renv::load()) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + +}) diff --git a/renv/settings.dcf b/renv/settings.dcf new file mode 100644 index 00000000..d04fb5e1 --- /dev/null +++ b/renv/settings.dcf @@ -0,0 +1,5 @@ +external.libraries: +ignored.packages: +snapshot.type: packrat +use.cache: TRUE +vcs.ignore.library: TRUE From a3f055419826aedcd1b0ff7e388034d2b5af96cc Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 20 Apr 2021 21:10:37 -0700 Subject: [PATCH 019/260] add .Rprofile --- .Rprofile | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .Rprofile diff --git a/.Rprofile b/.Rprofile new file mode 100644 index 00000000..2d988993 --- /dev/null +++ b/.Rprofile @@ -0,0 +1,11 @@ +.First <- function() { + options( + repos = c( + CRAN = "https://cran.rstudio.com/", + Sage = "http://ran.synapse.org" + ) + ) +} + +source("renv/activate.R") + From f805f4eb6e6bdd708ebd03946e1ad6322cfdf519 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 20 Apr 2021 21:12:07 -0700 Subject: [PATCH 020/260] update README --- README.md | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9d1b6f5c..7b6e8b85 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,14 @@ # Data Curator App +## Introduction + +The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the schematic Python package. It allows data contributors to easily annotate, validate and submit their metadata. + + ## Setup -### Data Curator App Setup (frontend) -Follow the steps below to make sure the _Data Curator App_ (frontend) is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main) (backend): +### Data Curator App Setup +Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main): Navigate to the location where you want to setup the application (i.e., the _Shiny Server_). Clone the code on this github branch (_shiny-server-main_): @@ -13,34 +18,39 @@ Create a conda environment in the cloned directory from the `environment.yml` fi conda env create -f environment.yml -Here, our conda environment name `data_curator_env` is set from the `environment.yml` file . +Here, our conda environment name `data_curator_env_oauth` is set from the `environment.yml` file . -Activate the `data_curator_env` environment: +Activate the `data_curator_env_oauth` environment: - conda activate data_curator_env - -_Note_: -- You can change the name of your conda environment inside `environment.yml` or even use another environment, but please note that you will need to make changes accordingly in the [`app.R`](https://github.com/Sage-Bionetworks/data_curator/blob/shiny-server-develop/app.R#L17) file. + conda activate data_curator_env_oauth -------- -### Schematic Setup (backend) +### Schematic Setup The next step is to install the latest release of the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main) (backend) as a folder `schematic` inside the `data_curator` folder and tie it together with this frontend. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites). -------- -### App Configuration file +### App Configuration File Use the app configuration file `www/config.json` to adapt this app to your DCC. * `manifest schemas`: defines the list of schemas displayed under the "Choose a Metadata Template Type:" dropdown in the application. - * `display_name` : The display name for the dropdown. (e.g. "Genomics Assay") - * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. "GenomicsAssay") - * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type "assay". + * `display_name` : The display name for the dropdown. (e.g. _scRNA-seq Level 1_) + * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. _ScRNA-seqLevel1_) + * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type _assay_. + +* `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) +* `community` : the abbreviated name of the community or project. (e.g. _HTAN_) + + +### Authentication (OAuth) + +This utilizes a Synapse OAuth client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration file. -* `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. "syn20446927") -* `community` : the abbreviated name of the community or project. (e.g. "HTAN") -} +``` +cp example_config.yaml config.yaml +# Edit config.yaml +chmod 400 config.yaml +``` \ No newline at end of file From 2b5253ec4051a5f064e98384453a1d695070b651 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 20 Apr 2021 21:13:14 -0700 Subject: [PATCH 021/260] add general .Rproj file --- HTAN_test_shiny.Rproj => Shiny_App.Rproj | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename HTAN_test_shiny.Rproj => Shiny_App.Rproj (100%) diff --git a/HTAN_test_shiny.Rproj b/Shiny_App.Rproj similarity index 100% rename from HTAN_test_shiny.Rproj rename to Shiny_App.Rproj From b96fb853c9d8b97c43ee647d3ef13a7547be9c3c Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 10:47:48 -0700 Subject: [PATCH 022/260] example config file for OAuth credentials --- example_config.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 example_config.yaml diff --git a/example_config.yaml b/example_config.yaml new file mode 100644 index 00000000..73014ea2 --- /dev/null +++ b/example_config.yaml @@ -0,0 +1,5 @@ +# This file contains the oauth client id and secret required for +# the application. This file needs to have chmod 400 permissions +# client_id has to be a string +client_id: +client_secret: From 98891a48f1d0a5b9116024dac09706688b2e5bcc Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:10:59 -0700 Subject: [PATCH 023/260] don't track config.yaml file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 38f3f3d0..11623cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ schematic/token.pickle credentials.json token.pickle **/__pycache__ +config.yaml \ No newline at end of file From f8ba43f65578f9e755f7c19e256cd5eeed6de4ad Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:12:20 -0700 Subject: [PATCH 024/260] file to store global variables --- global.R | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 global.R diff --git a/global.R b/global.R new file mode 100644 index 00000000..03afeffb --- /dev/null +++ b/global.R @@ -0,0 +1,56 @@ +library(shiny) +library(httr) +library(rjson) +library(yaml) + + +APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" + +has_auth_code <- function(params) { + # params is a list object containing the parsed URL parameters. Return TRUE if + # based on these parameters, it looks like auth code is present that we can + # use to get an access token. If not, it means we need to go through the OAuth + # flow. + return(!is.null(params$code)) +} + +oauth_client = yaml.load_file("config.yaml") + +client_id <- toString(oauth_client$client_id) +client_secret <- oauth_client$client_secret +if (is.null(client_id)) stop("config.yaml is missing client_id") +if (is.null(client_secret)) stop("config.yaml is missing client_secret") + +app <- oauth_app("shinysynapse", + key = client_id, + secret = client_secret, + redirect_uri = APP_URL) + +# These are the user info details ('claims') requested from Synapse: +claims=list( + family_name=NULL, + given_name=NULL, + email=NULL, + email_verified=NULL, + userid=NULL, + orcid=NULL, + is_certified=NULL, + is_validated=NULL, + validated_given_name=NULL, + validated_family_name=NULL, + validated_location=NULL, + validated_email=NULL, + validated_company=NULL, + validated_at=NULL, + validated_orcid=NULL, + company=NULL +) + +claimsParam<-toJSON(list(id_token = claims, userinfo = claims)) +api <- oauth_endpoint( + authorize=paste0("https://signin.synapse.org?claims=", claimsParam), + access="https://repo-prod.prod.sagebase.org/auth/v1/oauth2/token" +) + +# The 'openid' scope is required by the protocol for retrieving user information. +scope <- "openid view download modify" From 133338f6dcfcec81bb37b3661c1effa9c500b0d5 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:13:22 -0700 Subject: [PATCH 025/260] getting setup with reticulate --- init_python_venv.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 init_python_venv.sh diff --git a/init_python_venv.sh b/init_python_venv.sh new file mode 100644 index 00000000..d9ce6532 --- /dev/null +++ b/init_python_venv.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# a sample initialization of a virtualenv for use with +# this project. a local virtualenv is created, the python +# dependencies are installed into it, and an environment +# variable is set to hint reticulate to use this virtualenv. + +# this assumes that a python3 command is available on the path +# with a python version >= 3.6 + +# Sample usage: +# $source init_python_venv.sh + +python3 -m venv venv +. venv/bin/activate + +pip install -r requirements.txt + +export RETICULATE_PYTHON=venv/bin/python + From c4d77f081bf20aa0610d89986082698ebe52cf71 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:15:05 -0700 Subject: [PATCH 026/260] add requirements.txt file --- requirements.txt | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..58e855e1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,61 @@ +attrs==19.3.0 +cachetools==4.1.1 +certifi==2020.6.20 +cffi==1.14.0 +chardet==3.0.4 +click==7.1.2 +click-log==0.3.2 +cryptography==2.9.2 +decorator==4.4.2 +Deprecated==1.2.4 +entrypoints==0.3 +fastjsonschema==2.14.4 +google-api-core==1.26.3 +google-api-python-client==1.12.8 +google-auth==1.19.1 +google-auth-httplib2==0.0.4 +google-auth-oauthlib==0.4.4 +googleapis-common-protos==1.53.0 +graphviz==0.16 +httplib2==0.18.1 +idna==2.10 +importlib-metadata==1.7.0 +inflection==0.5.1 +isodate==0.6.0 +jsonschema==3.2.0 +keyring==12.0.2 +keyrings.alt==3.1 +networkx==2.5.1 +numpy==1.19.0 +oauth2client==3.0.0 +oauthlib==3.1.0 +orderedset==2.0.1 +packaging==20.9 +pandas==1.2.3 +pip==20.1.1 +protobuf==3.15.7 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycparser==2.20 +pygsheets==2.0.5 +pyparsing==2.4.7 +pyrsistent==0.16.0 +python-dateutil==2.8.1 +pytz==2020.1 +PyYAML==5.4.1 +rdflib==5.0.0 +requests==2.24.0 +requests-oauthlib==1.3.0 +rsa==4.6 +schematicpy==0.1.11 +SecretStorage==2.3.1 +setuptools==52.0.0 +six==1.15.0 +synapseclient==2.3.0 +tabletext==0.1 +toml==0.10.2 +uritemplate==3.0.1 +urllib3==1.25.9 +wheel==0.34.2 +wrapt==1.12.1 +zipp==3.1.0 From 0be1bd9ddcff9688b888789eaffd1e79f2dcc6cc Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:17:16 -0700 Subject: [PATCH 027/260] move code from app.R to ui.R and server.R --- server.R | 778 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui.R | 238 +++++++++++++++++ 2 files changed, 1016 insertions(+) create mode 100644 server.R create mode 100644 ui.R diff --git a/server.R b/server.R new file mode 100644 index 00000000..456d54eb --- /dev/null +++ b/server.R @@ -0,0 +1,778 @@ +# This is the server logic for a Shiny web application. +# You can find out more about building applications with Shiny here: +# +# http://shiny.rstudio.com +# +# This server has been modified to be used specifically on Sage Bionetworks Synapse pages +# to log into Synapse as the currently logged in user from the web portal using the session token. +# +# https://www.synapse.org + +library(shiny) +library(shinyjs) +library(dplyr) +library(shinythemes) +library(shinydashboard) +library(stringr) +library(DT) +library(jsonlite) +library(reticulate) +library(ggplot2) +library(purrr) +library(plotly) +library(shinypop) +library(waiter) + +# Don't necessarily have to set `RETICULATE_PYTHON` env variable +reticulate::use_condaenv("data_curator_env") + +shinyServer(function(input, output, session) { + ########### session global variables + source_python("python/synapse_func_alias.py") + source_python("python/metadata_model.py") + + params <- parseQueryString(isolate(session$clientData$url_search)) + if (!has_auth_code(params)) { + return() + } + redirect_url <- paste0( + api$access, "?", "redirect_uri=", + APP_URL, "&grant_type=", + "authorization_code", "&code=", params$code + ) + # get the access_token and userinfo token + req <- POST(redirect_url, + encode = "form", + body = "", + authenticate(app$key, app$secret, type = "basic"), + config = list() + ) + # Stop the code if anything other than 2XX status code is returned + stop_for_status(req, task = "get an access token") + token_response <- content(req, type = NULL) + access_token <- token_response$access_token + + # import module that contains SynapseStorage class + synapse_driver <- import("schematic.store.synapse") + + ### read config in + config <- jsonlite::fromJSON("www/config.json") + + ### logs in and gets list of projects they have access to + synStore_obj <- NULL + # get_projects_list(synStore_obj) + projects_list <- c() + + projects_namedList <- c() + + proj_folder_manifest_cells <- c() + + folder_synID <- NULL + + filename_list <- c() + ############ + + ### synapse cookies + session$sendCustomMessage(type = "readCookie", message = list()) + + ### initial login front page items + observeEvent(input$cookie, { + ## login and update session; otherwise, notify to login to Synapse first + tryCatch( + { + ### logs in + syn_login(sessionToken = input$cookie, rememberMe = FALSE) + + ### welcome message + output$title <- renderUI({ + titlePanel(h4(sprintf( + "Welcome, %s", syn_getUserProfile()$userName + ))) + }) + + ### updating global vars with values for projects + # synStore_obj <<- synapse_driver$SynapseStorage(config$main_fileview, token = input$cookie) + synStore_obj <<- synapse_driver$SynapseStorage(token = input$cookie) + + # get_projects_list(synStore_obj) + projects_list <<- synapse_driver$SynapseStorage$getStorageProjects(synStore_obj) + + for (i in seq_along(projects_list)) { + projects_namedList[projects_list[[i]][[2]]] <<- + projects_list[[i]][[1]] + } + + ### updates project dropdown + updateSelectizeInput(session, "var", choices = sort(names(projects_namedList))) + + ### update waiter loading screen once login successful + waiter_update(html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3(sprintf( + "Welcome, %s!", syn_getUserProfile()$userName + )) + )) + Sys.sleep(2) + waiter_hide() + }, + error = function(err) { + Sys.sleep(2) + waiter_update(html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3("Looks like you're not logged in!"), + span( + "Please ", + a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), + " to Synapse, then refresh this page." + ) + )) + } + ) + }) + + + ###### BUTTONS STUFF !!! remove last arrow + Previous_Button <- tags$div(actionButton( + "Prev_Tab", + HTML('
') + )) + Next_Button <- div(actionButton( + "Next_Tab", + HTML('
') + )) + + list_tabs <- c("instructions", "data", "template", "upload") + + output$Next_Previous <- renderUI({ + tab_list <- list_tabs + if (input[["tabs"]] == "upload") { + # column(1,offset=1,Previous_Button) + } else if (input[["tabs"]] == "instructions") { + column(1, offset = 10, Next_Button) + } else { + div( + column(1, offset = 1, Previous_Button), + column(1, offset = 8, Next_Button) + ) + } + }) + + observeEvent(input$Prev_Tab, { + tab_list <- list_tabs + current_tab <- which(tab_list == input[["tabs"]]) + updateTabItems(session, "tabs", selected = tab_list[current_tab - 1]) + }) + + observeEvent(input$Next_Tab, { + tab_list <- list_tabs + current_tab <- which(tab_list == input[["tabs"]]) + updateTabItems(session, "tabs", selected = tab_list[current_tab + 1]) + }) + + ####### BUTTONS END + + ### lists folder datasets if exists in project + observeEvent( + ignoreNULL = TRUE, + ignoreInit = TRUE, + input$var, + { + output$folders <- renderUI({ + selected_project <- input$var + + # if selected_project not empty + if (!is.null(selected_project)) { + project_synID <- + projects_namedList[[selected_project]] ### get synID of selected project + + ### gets folders per project + folder_list <- + synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folderNames <- names(folders_namedList) + + ### updates foldernames + selectInput( + inputId = "dataset", + label = "Folder:", + choices = folderNames + ) + } + }) + } + ) + + ### mapping from display name to schema name + schema_name <- config$manifest_schemas$schema_name + display_name <- config$manifest_schemas$display_name + + output$manifest_display_name <- renderUI({ + selectInput( + inputId = "template_type", + label = "Template:", + choices = display_name + ) + }) + + observeEvent( + { + input$dataset + input$template_type + }, + { + sapply( + c( + "text_div", + "text_div2", + "tbl2", + "gsheet_btn", + "gsheet_div", + "submitButton" + ), + FUN = hide + ) + } + ) + + schema_to_display_lookup <- data.frame(schema_name, display_name) + + # loading screen for template link generation + manifest_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Generating link...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + ### shows new metadata link when get gsheets template button pressed OR updates old metadata if is exists + observeEvent(input$download, { + manifest_w$show() + + if (is.null(input$template_type)) { + output$text <- renderUI({ + tags$span( + class = "error_msg", + HTML("Please select a template from the 'Select your Dataset' tab !") + ) + }) + } else { + selected_folder <- input$dataset + selected_project <- input$var + + ### lookup schema template name + template_type_df <- + schema_to_display_lookup[match( + input$template_type, + schema_to_display_lookup$display_name + ), 1, drop = F] + template_type <- as.character(template_type_df$schema_name) + + project_synID <- + projects_namedList[[selected_project]] ### get synID of selected project + + folder_list <- + synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### checks if a manifest already exists + existing_manifestID <- + synapse_driver$SynapseStorage$getDatasetManifest(synStore_obj, folder_synID) + + ### if there isn't an existing manifest make a new one + if (existing_manifestID == "") { + file_list <- + synapse_driver$SynapseStorage$getFilesInStorageDataset(synStore_obj, folder_synID) + file_namedList <- c() + for (i in seq_along(file_list)) { + file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] + } + filename_list <- names(file_namedList) + + manifest_url <- + metadata_model$getModelManifest( + paste0(config$community, " ", input$template_type), + template_type, + filenames = as.list(filename_list) + ) + ### make sure not scalar if length of list is 1 in R + ## add in the step to convert names later ### + } else { + ### if the manifest already exists + manifest_entity <- syn_get(existing_manifestID) + # prepopulatedManifestURL = mm.populateModelManifest("test_update", entity.path, component) + manifest_url <- + metadata_model$populateModelManifest( + paste0(config$community, " ", input$template_type), + manifest_entity$path, + template_type + ) + } + + output$text <- renderUI({ + tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### + }) + } + + ## links shows in text box + show("text_div") + ### if want a progress bar need more feedback from API to know how to increment progress bar ### + + manifest_w$hide() + }) + + ### renders fileInput ui + output$fileInput_ui <- renderUI({ + fileInput( + "file1", + "Upload CSV File", + accept = c( + "text/csv", + "text/comma-separated-values", + ".csv" + ) + ) + }) + + ### reads csv file and previews + rawData <- eventReactive(ignoreNULL = FALSE, input$file1, { + if (is.null(input$file1)) { + return(NULL) + } # if no file uploaded, return null + infile <- readr::read_csv(input$file1$datapath, + na = c("", "NA"), + col_types = readr::cols(.default = "c") + ) %>% + replace(., is.na(.), "") # change NA to blank to match schema output) + ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + infile <- infile[, !grepl("^X", colnames(infile))] + infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + }) + + observeEvent(input$file1, { + sapply(c( + "text_div2", + "tbl2", + "gsheet_btn", + "gsheet_div", + "submitButton" + ), + FUN = hide + ) + }) + + ### renders in DT for preview + observeEvent(rawData(), { + output$tbl <- DT::renderDT({ + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE) + }) + }) + + ## loading screen for validating metadata + validate_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Validating...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + ### toggles validation status when validate button pressed + observeEvent(input$validate, { + validation_res <- NULL + type_error <- NULL + help_msg <- NULL + + validate_w$show() + + if (!is.null(rawData()) & !is.null(input$template_type)) { + ### lookup schema template name + template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F] + template_type <- as.character(template_type_df$schema_name) + + annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) + + if (length(annotation_status) != 0) { + validation_res <- "invalid" + # mismatched template index + inx_mt <- which(sapply(annotation_status, function(x) grepl("Component value provided is: .*, whereas the Template Type is: .*", x[[3]]))) + # missing column index + inx_ws <- which(sapply(annotation_status, function(x) grepl("Wrong schema", x[[2]]))) + + if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template + + waiter_msg <- "Mismatched Template Found !" + # get all mismatched components + error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% unique() + column_names <- "Component" + + # error messages for mismatch + mismatch_c <- error_values %>% + sQuote() %>% + paste(collapse = ", ") + type_error <- paste0("The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", input$template_type, " >>.") + help_msg <- paste0("Please check that you have selected the correct template in the Select your Dataset tab and + ensure your metadata contains only one template, e.g. ", input$template_type, ".") + + # get wrong columns and values for updating preview table + errorDT <- data.frame( + Column = sapply(annotation_status[inx_mt], function(i) i[[2]]), + Value = sapply(annotation_status[inx_mt], function(i) i[[4]][[1]]) + ) + } else if (length(inx_ws) > 0) { # wrong schema error(s): validating metadata miss any required columns + + waiter_msg <- "Wrong Schema Used !" + type_error <- "The submitted metadata does not contain all required column(s)." + help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and + ensure your metadata contains all required columns." + } else { + waiter_msg <- sprintf("%d errors found", length(annotation_status)) + type_error <- paste0("The submitted metadata have ", length(annotation_status), " errors.") + help_msg <- NULL + + errorDT <- data.frame( + Column = sapply(annotation_status, function(i) i[[2]]), + Value = sapply(annotation_status, function(i) i[[4]][[1]]), + Error = sapply(annotation_status, function(i) i[[3]]) + ) + # sort rows based on input column names + errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))), ] + + # output error messages as data table + show("tbl2") + output$tbl2 <- DT::renderDT({ + datatable(errorDT, + caption = "The errors are also highlighted in the preview table above.", + rownames = FALSE, options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), + lengthChange = FALSE, info = FALSE, searching = FALSE + ) + ) + }) + } + + validate_w$update( + html = h3(waiter_msg) + ) + + ### update DT view with incorrect values + ### currently only one column, requires backend support of multiple + output$tbl <- DT::renderDT({ + if (length(inx_ws) > 0) { + # if it is wrong schema error, highlight all cells + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% + formatStyle(1, target = "row", backgroundColor = "yellow") + } else { + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% + formatStyle(errorDT$Column, + backgroundColor = styleEqual(errorDT$Value, rep("yellow", length(errorDT$Value))) + ) + } + }) + + show("gsheet_btn") + } else { + validation_res <- "valid" + ### show submit button + output$submit <- renderUI({ + actionButton("submitButton", "Submit to Synapse") + }) + } + } + + ### format output text + output$text2 <- renderUI({ + text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg") + + tagList( + if (is.null(input$template_type)) span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")), + if (is.null(rawData())) span(class = text_class, HTML("Please upload a filled template !")), + if (!is.null(validation_res)) span(class = text_class, HTML(paste0("Your metadata is ", validation_res, " !!!"))), + if (!is.null(type_error)) span(class = text_class, HTML(paste0("

", type_error))), + if (!is.null(help_msg)) span(class = text_class, HTML(paste0("

", help_msg))) + ) + }) + + show("text_div2") + + Sys.sleep(2.5) + + validate_w$hide() + }) + + # if user click gsheet_btn, generating gsheet + observeEvent(input$gsheet_btn, { + # loading screen for Google link generation + gsheet_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Generating link...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + gsheet_w$show() + + ### lookup schema template name + template_type_df <- + schema_to_display_lookup[match( + input$template_type, + schema_to_display_lookup$display_name + ), 1, drop = F] + template_type <- as.character(template_type_df$schema_name) + + ## if error not empty aka there is an error + filled_manifest <- + metadata_model$populateModelManifest( + paste0(config$community, " ", input$template_type), + input$file1$datapath, + template_type + ) + + show("gsheet_div") + + output$gsheet_link <- renderUI({ + # tags$a(href = filled_manifest, filled_manifest, target = "_blank") + HTML( + paste0( + 'Edit on the Google Sheet.' + ) + ) + }) + + hide("gsheet_btn") # hide btn once link generated + + gsheet_w$hide() + }) + + ## loading screen for submitting data + submit_w <- Waiter$new( + html = tagList( + img(src = "loading.gif"), + h4("Submitting...") + ), + color = "#424874" + ) + + ### submit button + observeEvent(input$submitButton, { + submit_w$show() + + ### reads in csv + infile <- + readr::read_csv(input$file1$datapath, na = c("", "NA")) + + ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + infile <- infile[, !grepl("^X", colnames(infile))] + infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + + ### IF an assay component selected (define assay components) + ## note for future - the type to filter (eg assay) on could probably also be a config choice + assay_schemas <- + config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] + + ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files + if (input$template_type %in% assay_schemas) { + ### make into a csv or table for assay components + ### already has entityId + if ("entityId" %in% colnames(infile)) { + write.csv( + infile, + file = "./files/synapse_storage_manifest.csv", + quote = TRUE, + row.names = FALSE, + na = "" + ) + } else { + # if not get ids + selected_folder <- input$dataset + selected_project <- input$var + + project_synID <- + projects_namedList[[selected_project]] ### get synID of selected project + folder_list <- + synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + + folder_synID <- folders_namedList[[selected_folder]] + + file_list <- + synapse_driver$SynapseStorage$getFilesInStorageDataset(synStore_obj, folder_synID) + file_namedList <- c() + for (i in seq_along(file_list)) { + file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] + } + + files_df <- stack(file_namedList) + colnames(files_df) <- c("entityId", "Filename") + files_entity <- + inner_join(infile, files_df, by = "Filename") + + write.csv( + files_entity, + file = "./files/synapse_storage_manifest.csv", + quote = TRUE, + row.names = FALSE, + na = "" + ) + } + selected_project <- input$var + selected_folder <- input$dataset + + project_synID <- + projects_namedList[[selected_project]] ### get synID of selected project + + folder_list <- + synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### associates metadata with data and returns manifest id + manifest_id <- + synapse_driver$SynapseStorage$associateMetadataWithFiles( + synStore_obj, + "./files/synapse_storage_manifest.csv", + folder_synID + ) + print(manifest_id) + manifest_path <- + paste0("synapse.org/#!Synapse:", manifest_id) + ### if no error + if (startsWith(manifest_id, "syn") == TRUE) { + nx_report_success( + "Success!", + paste0("Manifest submitted to: ", manifest_path) + ) + rm("./files/synapse_storage_manifest.csv") + + ### clear inputs + output$text2 <- renderUI({ + HTML("") + }) + output$submit <- renderUI({ + + }) + + ### rerenders fileinput UI + output$fileInput_ui <- renderUI({ + fileInput( + "file1", + "Upload CSV File", + accept = c( + "text/csv", + "text/comma-separated-values", + ".csv" + ) + ) + }) + ### renders empty df + output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( + 0, + ncol = 0, nrow = 0 + )))) + } else { + submit_w$update(html = tagList( + img(src = "synapse_logo.png", height = "115px"), + h3("Uh oh, looks like something went wrong!"), + span(manifest_id, " is not a valid Synapse ID. Try again?") + )) + rm("/tmp/synapse_storage_manifest.csv") + } + } else { + ## if not assay type tempalte + write.csv( + infile, + file = "./files/synapse_storage_manifest.csv", + quote = TRUE, + row.names = FALSE, + na = "" + ) + + selected_project <- input$var + selected_folder <- input$dataset + + project_synID <- + projects_namedList[[selected_project]] ### get synID of selected project + # folder_synID <- get_folder_synID(synStore_obj, project_synID, selected_folder) + + folder_list <- + synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### associates metadata with data and returns manifest id + manifest_id <- + synapse_driver$SynapseStorage$associateMetadataWithFiles( + synStore_obj, + "./files/synapse_storage_manifest.csv", + folder_synID + ) + print(manifest_id) + manifest_path <- + paste0("synapse.org/#!Synapse:", manifest_id) + + ### if uploaded provided valid synID message + if (startsWith(manifest_id, "syn") == TRUE) { + nx_report_success( + "Success!", + paste0("Manifest submitted to: ", manifest_path) + ) + rm("./files/synapse_storage_manifest.csv") + + ### clear inputs + output$text2 <- renderUI({ + HTML("") + }) + output$submit <- renderUI({ + + }) + + ### rerenders fileinput UI + output$fileInput_ui <- renderUI({ + fileInput( + "file1", + "Upload CSV File", + accept = c( + "text/csv", + "text/comma-separated-values", + ".csv" + ) + ) + }) + ### renders empty df + output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( + 0, + ncol = 0, nrow = 0 + )))) + } else { + submit_w$update(html = tagList( + img(src = "synapse_logo.png", height = "115px"), + h3("Uh oh, looks like something went wrong!"), + span(manifest_id, " is not a valid Synapse ID. Try again?") + )) + rm("/tmp/synapse_storage_manifest.csv") + } + } + Sys.sleep(3) + submit_w$hide() + }) +}) diff --git a/ui.R b/ui.R new file mode 100644 index 00000000..206586da --- /dev/null +++ b/ui.R @@ -0,0 +1,238 @@ +# This is the user-interface definition of a Shiny web application. +# You can find out more about building applications with Shiny here: +# +# http://shiny.rstudio.com +# +# This interface has been modified to be used specifically on Sage Bionetworks Synapse pages +# to log into Synapse as the currently logged in user from the web portal using the session token. +# +# https://www.synapse.org + +library(shiny) +library(shinyjs) +library(dplyr) +library(shinythemes) +library(shinydashboard) +library(stringr) +library(DT) +library(jsonlite) +library(reticulate) +library(ggplot2) +library(purrr) +library(plotly) +library(shinypop) +library(waiter) +library(sass) # read scss file + +ui <- dashboardPage( + skin = "purple", + dashboardHeader( + titleWidth = 250, + title = "Data Curator", + tags$li( + class = "dropdown", + tags$a( + href = "https://humantumoratlas.org/", + target = "_blank", + ## insert links and logos of your choice, this is just an example + tags$img( + height = "40px", alt = "HTAN LOGO", + src = "HTAN_text_logo.png" + ) + ) + ) + ), + dashboardSidebar( + width = 250, + sidebarMenu( + id = "tabs", + menuItem( + "Instructions", + tabName = "instructions", + icon = icon("book-open") + ), + menuItem( + "Select your Dataset", + tabName = "data", + icon = icon("mouse-pointer") + ), + menuItem( + "Get Metadata Template", + tabName = "template", + icon = icon("table") + ), + menuItem( + "Submit & Validate Metadata", + tabName = "upload", + icon = icon("upload") + ), + HTML( + "
+ Supported by the Human Tumor Atlas Network
+ (U24-CA233243-01)
+ Powered by Sage Bionetworks +
" + ) + ) + ), + dashboardBody( + tags$head( + tags$style(sass(sass_file("www/scss/main.scss"))), + singleton( + includeScript("www/readCookie.js") + ) + ), + uiOutput("title"), + use_notiflix_report(), + tabItems( + # First tab content + tabItem( + tabName = "instructions", + h2("Instructions for the Data Curator App:"), + h3( + "1. Go to", + strong("Select your Dataset"), + "tab - select your project; choose your folder and metadata template type matching your metadata." + ), + h3( + "2. Go to", + strong("Get Metadata Template"), + "tab - click on the link to generate the metadata template, then fill out and download the file as a CSV. If you already have an annotated metadata template, you may skip this step." + ), + h3( + "3. Go to", + strong("Submit and Validate Metadata"), + "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata." + ) + ), + # second tab content + tabItem( + tabName = "data", + h2("Set Dataset and Metadata Template for Curation"), + fluidRow( + box( + status = "primary", + solidHeader = TRUE, + width = 6, + title = "Choose a Project and Folder: ", + selectizeInput( + inputId = "var", + label = "Project:", + choices = "Generating..." + ), + uiOutput("folders"), + helpText( + "If your recently updated folder does not appear, please wait for Synapse to sync and refresh" + ) + ), + box( + status = "primary", + solidHeader = TRUE, + width = 6, + title = "Choose a Metadata Template Type: ", + uiOutput("manifest_display_name") + ) + ) + ), + # Third tab item + tabItem( + tabName = "template", + useShinyjs(), + h2("Download Template for Selected Folder"), + fluidRow( + box( + title = "Get Link, Annotate, and Download Template as CSV", + status = "primary", + solidHeader = TRUE, + width = 12, + actionButton("download", "Click to Generate Google Sheets Template"), + hidden( + div( + id = "text_div", + height = "100%", + htmlOutput("text") + ) + ), + helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") + ) + ) + ), + # Fourth tab content + tabItem( + tabName = "upload", + h2("Submit & Validate a Filled Metadata Template"), + fluidRow( + box( + title = "Upload Filled Metadata as a CSV", + solidHeader = TRUE, + status = "primary", + width = 12, + uiOutput("fileInput_ui") + ), + box( + title = "Metadata Preview", + solidHeader = TRUE, + status = "primary", + width = 12, + DT::DTOutput("tbl") + ), + box( + title = "Validate Filled Metadata", + status = "primary", + solidHeader = TRUE, + width = 12, + actionButton("validate", "Validate Metadata"), + hidden( + div( + id = "text_div2", + height = "100%", + htmlOutput("text2") + ), + DT::DTOutput("tbl2"), + actionButton("gsheet_btn", " Click to Generate Google Sheet Link", icon = icon("table")), + div( + id = "gsheet_div", + height = "100%", + htmlOutput("gsheet_link") + ) + ), + helpText( + HTML("If you have an error, please try editing locally or on google sheet.
+ Reupload your CSV and press the validate button as needed.") + ) + ), + box( + title = "Submit Validated Metadata to Synapse", + status = "primary", + solidHeader = TRUE, + width = 12, + uiOutput("submit") + ) + ) + ) + ), + uiOutput("Next_Previous"), + + ## waiter loading screen + use_waiter(), + waiter_show_on_load( + html = tagList( + img(src = "loading.gif"), + h4("Retrieving Synapse information...") + ), + color = "#424874" + ) + ) +) + +uiFunc <- function(req) { + if (!has_auth_code(parseQueryString(req$QUERY_STRING))) { + authorization_url <- oauth2.0_authorize_url(api, app, scope = scope) + return(tags$script(HTML(sprintf( + "location.replace(\"%s\");", + authorization_url + )))) + } else { + ui + } +} From 4694095f228c3960567658a4e1e96b94edcaf1ac Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:19:18 -0700 Subject: [PATCH 028/260] remove app.R --- app.R | 944 ---------------------------------------------------------- 1 file changed, 944 deletions(-) delete mode 100644 app.R diff --git a/app.R b/app.R deleted file mode 100644 index d77701a1..00000000 --- a/app.R +++ /dev/null @@ -1,944 +0,0 @@ -library(shiny) -library(shinyjs) -library(dplyr) -library(shinythemes) -library(shinydashboard) -library(stringr) -library(DT) -library(jsonlite) -library(reticulate) -library(ggplot2) -library(purrr) -library(plotly) -library(shinypop) -library(waiter) -library(sass) # read scss file - -#########global -use_condaenv('data_curator_env', required = TRUE) -reticulate::import("sys") - -source_python("synLoginFun.py") -source_python("metadataModelFuns.py") -options(stringsAsFactors = FALSE) # stringsAsFactors = TRUE by default for R < 4.0 -######### - -ui <- dashboardPage( - skin = "purple", - dashboardHeader( - titleWidth = 250, - title = "Data Curator", - tags$li( - class = "dropdown", - tags$a( - href = "https://humantumoratlas.org/", - target = "_blank", - ## insert links and logos of your choice, this is just an example - tags$img( - height = "40px", alt = "HTAN LOGO", - src = "HTAN_text_logo.png" - ) - ) - ) - ), - dashboardSidebar( - width = 250, - sidebarMenu( - id = "tabs", - menuItem( - "Instructions", - tabName = "instructions", - icon = icon("book-open") - ), - menuItem( - "Select your Dataset", - tabName = "data", - icon = icon("mouse-pointer") - ), - menuItem( - "Get Metadata Template", - tabName = "template", - icon = icon("table") - ), - menuItem( - "Submit & Validate Metadata", - tabName = "upload", - icon = icon("upload") - ), - HTML( - "
- Supported by the Human Tumor Atlas Network
- (U24-CA233243-01)
- Powered by Sage Bionetworks -
" - ) - ) - ), - dashboardBody( - tags$head( - tags$style(sass(sass_file("www/scss/main.scss"))), - singleton( - includeScript("www/readCookie.js") - )), - - uiOutput("title"), - use_notiflix_report(), - tabItems( - # First tab content - tabItem( - tabName = "instructions", - h2("Instructions for the Data Curator App:"), - h3( - "1. Go to", - strong("Select your Dataset"), - "tab - select your project; choose your folder and metadata template type matching your metadata." - ), - h3( - "2. Go to", - strong("Get Metadata Template"), - "tab - click on the link to generate the metadata template, then fill out and download the file as a CSV. If you already have an annotated metadata template, you may skip this step." - ), - h3( - "3. Go to", - strong("Submit and Validate Metadata"), - "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata." - ) - ), - # second tab content - tabItem( - tabName = "data", - h2("Set Dataset and Metadata Template for Curation"), - fluidRow( - box( - status = "primary", - solidHeader = TRUE, - width = 6, - title = "Choose a Project and Folder: ", - selectizeInput( - inputId = "var", - label = "Project:", - choices = "Generating..." - ), - uiOutput("folders"), - helpText( - "If your recently updated folder does not appear, please wait for Synapse to sync and refresh" - ) - ), - box( - status = "primary", - solidHeader = TRUE, - width = 6, - title = "Choose a Metadata Template Type: ", - uiOutput("manifest_display_name") - ) - ) - ), - # Third tab item - tabItem(tabName = "template", - useShinyjs(), - h2("Download Template for Selected Folder"), - fluidRow( - box( - title = "Get Link, Annotate, and Download Template as CSV", - status = "primary", - solidHeader = TRUE, - width = 12, - actionButton("download", "Click to Generate Google Sheets Template"), - hidden( - div( - id = 'text_div', - height = "100%", - htmlOutput("text") - ) - ), - helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") - ) - - ) - ), - # Fourth tab content - tabItem(tabName = "upload", - h2("Submit & Validate a Filled Metadata Template"), - fluidRow( - box( - title = "Upload Filled Metadata as a CSV", - solidHeader = TRUE, - status = "primary", - width = 12, - uiOutput('fileInput_ui') - ), - box( - title = "Metadata Preview", - solidHeader = TRUE, - status = "primary", - width = 12, - DT::DTOutput("tbl") - ), - box( - title = "Validate Filled Metadata", - status = "primary", - solidHeader = TRUE, - width = 12, - actionButton("validate", "Validate Metadata"), - hidden( - div(id = 'text_div2', - height = "100%", - htmlOutput("text2") - ), - DT::DTOutput("tbl2"), - actionButton("gsheet_btn", " Click to Generate Google Sheet Link", icon = icon("table")), - div(id = 'gsheet_div', - height = "100%", - htmlOutput("gsheet_link") - ) - ), - helpText( - HTML("If you have an error, please try editing locally or on google sheet.
- Reupload your CSV and press the validate button as needed.") - ) - ), - box(title = "Submit Validated Metadata to Synapse", - status = "primary", - solidHeader = TRUE, - width = 12, - uiOutput("submit") - ) - ) - ) - ), - uiOutput("Next_Previous"), - - ## waiter loading screen - use_waiter(), - waiter_show_on_load( - html = tagList( - img(src = "loading.gif"), - h4("Retrieving Synapse information...") - ), - color = "#424874" - ) - ) -) - - -server <- function(input, output, session) { - ########### session global variables - reticulate::source_python("synStore_Session.py") - - ### read config in - config <- jsonlite::fromJSON("www/config.json") - - ### logs in and gets list of projects they have access to - synStore_obj <- NULL - # get_projects_list(synStore_obj) - projects_list <- c() - - projects_namedList <- c() - - proj_folder_manifest_cells <- c() - - folder_synID <- NULL - - filename_list <- c() - ############ - - ### synapse cookies - session$sendCustomMessage(type = "readCookie", message = list()) - - ### initial login front page items - observeEvent(input$cookie, { - ## login and update session; otherwise, notify to login to Synapse first - tryCatch( - { - ### logs in - syn_login(sessionToken = input$cookie, rememberMe = FALSE) - - ### welcome message - output$title <- renderUI({ - titlePanel(h4(sprintf( - "Welcome, %s", syn_getUserProfile()$userName - ))) - }) - - ### updating global vars with values for projects - # synStore_obj <<- syn_store(config$main_fileview, token = input$cookie) - synStore_obj <<- syn_store(token = input$cookie) - - # get_projects_list(synStore_obj) - projects_list <<- syn_store$getStorageProjects(synStore_obj) - - for (i in seq_along(projects_list)) { - projects_namedList[projects_list[[i]][[2]]] <<- - projects_list[[i]][[1]] - } - - ### updates project dropdown - updateSelectizeInput(session, "var", choices = sort(names(projects_namedList))) - - ### update waiter loading screen once login successful - waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), - h3(sprintf( - "Welcome, %s!", syn_getUserProfile()$userName - )) - )) - Sys.sleep(2) - waiter_hide() - }, - error = function(err) { - Sys.sleep(2) - waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), - span( - "Please ", - a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), - " to Synapse, then refresh this page." - ) - )) - } - ) - }) - - - ###### BUTTONS STUFF !!! remove last arrow - Previous_Button <- tags$div(actionButton( - "Prev_Tab", - HTML('
') - )) - Next_Button <- div(actionButton( - "Next_Tab", - HTML('
') - )) - - list_tabs <- c("instructions", "data", "template", "upload") - - output$Next_Previous <- renderUI({ - tab_list <- list_tabs - if (input[["tabs"]] == "upload") { - # column(1,offset=1,Previous_Button) - } else if (input[["tabs"]] == "instructions") { - column(1, offset = 10, Next_Button) - } else { - div( - column(1, offset = 1, Previous_Button), - column(1, offset = 8, Next_Button) - ) - } - }) - - observeEvent(input$Prev_Tab, { - tab_list <- list_tabs - current_tab <- which(tab_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tab_list[current_tab - 1]) - }) - - observeEvent(input$Next_Tab, { - tab_list <- list_tabs - current_tab <- which(tab_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tab_list[current_tab + 1]) - }) - - ####### BUTTONS END - - ### lists folder datasets if exists in project - observeEvent( - ignoreNULL = TRUE, - ignoreInit = TRUE, - input$var, - { - output$folders <- renderUI({ - selected_project <- input$var - - # if selected_project not empty - if (!is.null(selected_project)) { - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - ### gets folders per project - folder_list <- - syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folderNames <- names(folders_namedList) - - ### updates foldernames - selectInput( - inputId = "dataset", - label = "Folder:", - choices = folderNames - ) - } - }) - } - ) - - ### mapping from display name to schema name - schema_name <- config$manifest_schemas$schema_name - display_name <- config$manifest_schemas$display_name - - output$manifest_display_name <- renderUI({ - selectInput( - inputId = "template_type", - label = "Template:", - choices = display_name - ) - }) - - observeEvent( - { - input$dataset - input$template_type - }, - { - sapply( - c( - "text_div", - "text_div2", - "tbl2", - "gsheet_btn", - "gsheet_div", - "submitButton" - ), - FUN = hide - ) - } - ) - - schema_to_display_lookup <- data.frame(schema_name, display_name) - - # loading screen for template link generation - manifest_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Generating link...") - ), - color = "rgba(66, 72, 116, .9)" - ) - - ### shows new metadata link when get gsheets template button pressed OR updates old metadata if is exists - observeEvent(input$download, { - manifest_w$show() - - if (is.null(input$template_type)) { - output$text <- renderUI({ - tags$span(class="error_msg", - HTML("Please select a template from the 'Select your Dataset' tab !")) - }) - - } else { - selected_folder <- input$dataset - selected_project <- input$var - - ### lookup schema template name - template_type_df <- - schema_to_display_lookup[match( - input$template_type, - schema_to_display_lookup$display_name - ), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - folder_list <- - syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] - - ### checks if a manifest already exists - existing_manifestID <- - syn_store$getDatasetManifest(synStore_obj, folder_synID) - - ### if there isn't an existing manifest make a new one - if (existing_manifestID == "") { - file_list <- - syn_store$getFilesInStorageDataset(synStore_obj, folder_synID) - file_namedList <- c() - for (i in seq_along(file_list)) { - file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] - } - filename_list <- names(file_namedList) - - manifest_url <- - metadata_model$getModelManifest( - paste0(config$community, " ", input$template_type), - template_type, - filenames = as.list(filename_list) - ) - ### make sure not scalar if length of list is 1 in R - ## add in the step to convert names later ### - } else { - ### if the manifest already exists - manifest_entity <- syn_get(existing_manifestID) - # prepopulatedManifestURL = mm.populateModelManifest("test_update", entity.path, component) - manifest_url <- - metadata_model$populateModelManifest( - paste0(config$community, " ", input$template_type), - manifest_entity$path, - template_type - ) - } - - output$text <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### - }) - } - - ## links shows in text box - show("text_div") - ### if want a progress bar need more feedback from API to know how to increment progress bar ### - - manifest_w$hide() - }) - - ### renders fileInput ui - output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) - }) - - ### reads csv file and previews - rawData <- eventReactive(ignoreNULL = FALSE, input$file1, { - if(is.null(input$file1)) return(NULL) # if no file uploaded, return null - infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), - col_types = readr::cols(.default = "c")) %>% - replace(., is.na(.), "") # change NA to blank to match schema output) - ### remove empty rows/columns where readr called it "X"[digit] for unnamed col - infile <- infile[, !grepl("^X", colnames(infile))] - infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - }) - - observeEvent(input$file1, { - sapply(c( - "text_div2", - "tbl2", - "gsheet_btn", - "gsheet_div", - "submitButton" - ), - FUN = hide - ) - }) - - ### renders in DT for preview - observeEvent(rawData(), { - output$tbl <- DT::renderDT({ - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE - ) - }) - }) - - ## loading screen for validating metadata - validate_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Validating...") - ), - color = "rgba(66, 72, 116, .9)" - ) - - ### toggles validation status when validate button pressed - observeEvent(input$validate, { - validation_res <- NULL - type_error <- NULL - help_msg <- NULL - - validate_w$show() - - if (!is.null(rawData()) & !is.null(input$template_type)) { - ### lookup schema template name - template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) - - if (length(annotation_status) != 0) { - - validation_res <- "invalid" - # mismatched template index - inx_mt <- which(sapply(annotation_status, function(x) grepl("Component value provided is: .*, whereas the Template Type is: .*", x[[3]]))) - # missing column index - inx_ws <- which(sapply(annotation_status, function(x) grepl("Wrong schema", x[[2]]))) - - if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template - - waiter_msg <- "Mismatched Template Found !" - # get all mismatched components - error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% unique() - column_names <- "Component" - - # error messages for mismatch - mismatch_c <- error_values %>% sQuote %>% paste(collapse = ", ") - type_error <- paste0("The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", input$template_type, " >>.") - help_msg <- paste0("Please check that you have selected the correct template in the Select your Dataset tab and - ensure your metadata contains only one template, e.g. ", input$template_type, ".") - - # get wrong columns and values for updating preview table - errorDT <- data.frame(Column=sapply(annotation_status[inx_mt], function(i) i[[2]]), - Value=sapply(annotation_status[inx_mt], function(i) i[[4]][[1]])) - - } else if (length(inx_ws) > 0) { # wrong schema error(s): validating metadata miss any required columns - - waiter_msg <- "Wrong Schema Used !" - type_error <- "The submitted metadata does not contain all required column(s)." - help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and - ensure your metadata contains all required columns." - - } else { - - waiter_msg <- sprintf("%d errors found", length(annotation_status)) - type_error <- paste0("The submitted metadata have ", length(annotation_status), " errors.") - help_msg <- NULL - - errorDT <- data.frame(Column=sapply(annotation_status, function(i) i[[2]]), - Value=sapply(annotation_status, function(i) i[[4]][[1]]), - Error=sapply(annotation_status, function(i) i[[3]])) - # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))),] - - # output error messages as data table - show("tbl2") - output$tbl2 <- DT::renderDT({ - datatable(errorDT, caption = "The errors are also highlighted in the preview table above.", - rownames = FALSE, options = list(pageLength = 50, scrollX = TRUE, - scrollY = min(50*length(annotation_status), 400), - lengthChange = FALSE, info = FALSE, searching = FALSE) - ) - }) - } - - validate_w$update( - html = h3(waiter_msg) - ) - - ### update DT view with incorrect values - ### currently only one column, requires backend support of multiple - output$tbl <- DT::renderDT({ - if (length(inx_ws) > 0) { - # if it is wrong schema error, highlight all cells - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE) ) %>% - formatStyle(1, target = "row", backgroundColor = "yellow") - } else { - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE) ) %>% - formatStyle(errorDT$Column, - backgroundColor = styleEqual(errorDT$Value, rep("yellow", length(errorDT$Value)))) - } - }) - - show('gsheet_btn') - - } else { - - validation_res <- "valid" - ### show submit button - output$submit <- renderUI({ - actionButton("submitButton", "Submit to Synapse") - }) - - } - } - - ### format output text - output$text2 <- renderUI({ - text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg") - - tagList( - if (is.null(input$template_type)) span(class=text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")), - if (is.null(rawData())) span(class=text_class, HTML("Please upload a filled template !")), - if (!is.null(validation_res)) span(class=text_class, HTML(paste0("Your metadata is ", validation_res, " !!!"))), - if (!is.null(type_error)) span(class=text_class, HTML(paste0("

", type_error))), - if (!is.null(help_msg)) span(class=text_class, HTML(paste0("

", help_msg))) - ) - }) - - show('text_div2') - - Sys.sleep(2.5) - - validate_w$hide() - }) - - # if user click gsheet_btn, generating gsheet - observeEvent(input$gsheet_btn, { - # loading screen for Google link generation - gsheet_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Generating link...") - ), - color = "rgba(66, 72, 116, .9)" - ) - - gsheet_w$show() - - ### lookup schema template name - template_type_df <- - schema_to_display_lookup[match( - input$template_type, - schema_to_display_lookup$display_name - ), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - ## if error not empty aka there is an error - filled_manifest <- - metadata_model$populateModelManifest( - paste0(config$community, " ", input$template_type), - input$file1$datapath, - template_type - ) - - show("gsheet_div") - - output$gsheet_link <- renderUI({ - # tags$a(href = filled_manifest, filled_manifest, target = "_blank") - HTML( - paste0( - 'Edit on the Google Sheet.' - ) - ) - }) - - hide("gsheet_btn") # hide btn once link generated - - gsheet_w$hide() - }) - - ## loading screen for submitting data - submit_w <- Waiter$new( - html = tagList( - img(src = "loading.gif"), - h4("Submitting...") - ), - color = "#424874" - ) - - ### submit button - observeEvent(input$submitButton, { - submit_w$show() - - ### reads in csv - infile <- - readr::read_csv(input$file1$datapath, na = c("", "NA")) - - ### remove empty rows/columns where readr called it "X"[digit] for unnamed col - infile <- infile[, !grepl("^X", colnames(infile))] - infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - - ### IF an assay component selected (define assay components) - ## note for future - the type to filter (eg assay) on could probably also be a config choice - assay_schemas <- - config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - - ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files - if (input$template_type %in% assay_schemas) { - ### make into a csv or table for assay components - ### already has entityId - if ("entityId" %in% colnames(infile)) { - write.csv( - infile, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" - ) - } else { - # if not get ids - selected_folder <- input$dataset - selected_project <- input$var - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - folder_list <- - syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - - folder_synID <- folders_namedList[[selected_folder]] - - file_list <- - syn_store$getFilesInStorageDataset(synStore_obj, folder_synID) - file_namedList <- c() - for (i in seq_along(file_list)) { - file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] - } - - files_df <- stack(file_namedList) - colnames(files_df) <- c("entityId", "Filename") - files_entity <- - inner_join(infile, files_df, by = "Filename") - - write.csv( - files_entity, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" - ) - } - selected_project <- input$var - selected_folder <- input$dataset - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - folder_list <- - syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] - - ### associates metadata with data and returns manifest id - manifest_id <- - syn_store$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", - folder_synID - ) - print(manifest_id) - manifest_path <- - paste0("synapse.org/#!Synapse:", manifest_id) - ### if no error - if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success( - "Success!", - paste0("Manifest submitted to: ", manifest_path) - ) - rm("./files/synapse_storage_manifest.csv") - - ### clear inputs - output$text2 <- renderUI({ - HTML("") - }) - output$submit <- renderUI({ - - }) - - ### rerenders fileinput UI - output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) - }) - ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( - 0, - ncol = 0, nrow = 0 - )))) - } else { - submit_w$update(html = tagList( - img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), - span(manifest_id, " is not a valid Synapse ID. Try again?") - )) - rm("/tmp/synapse_storage_manifest.csv") - } - } else { - ## if not assay type tempalte - write.csv( - infile, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" - ) - - selected_project <- input$var - selected_folder <- input$dataset - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - # folder_synID <- get_folder_synID(synStore_obj, project_synID, selected_folder) - - folder_list <- - syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] - - ### associates metadata with data and returns manifest id - manifest_id <- - syn_store$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", - folder_synID - ) - print(manifest_id) - manifest_path <- - paste0("synapse.org/#!Synapse:", manifest_id) - - ### if uploaded provided valid synID message - if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success( - "Success!", - paste0("Manifest submitted to: ", manifest_path) - ) - rm("./files/synapse_storage_manifest.csv") - - ### clear inputs - output$text2 <- renderUI({ - HTML("") - }) - output$submit <- renderUI({ - - }) - - ### rerenders fileinput UI - output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) - }) - ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( - 0, - ncol = 0, nrow = 0 - )))) - } else { - submit_w$update(html = tagList( - img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), - span(manifest_id, " is not a valid Synapse ID. Try again?") - )) - rm("/tmp/synapse_storage_manifest.csv") - } - } - Sys.sleep(3) - submit_w$hide() - }) -} - - -shinyApp(ui, server) From 2312ebf4a42fc95460d4ceda858aeaab60521ae0 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 21 Apr 2021 11:22:06 -0700 Subject: [PATCH 029/260] bump up schematicpy version --- init_python_venv.sh | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/init_python_venv.sh b/init_python_venv.sh index d9ce6532..67250c5f 100644 --- a/init_python_venv.sh +++ b/init_python_venv.sh @@ -12,7 +12,7 @@ # $source init_python_venv.sh python3 -m venv venv -. venv/bin/activate +source venv/bin/activate pip install -r requirements.txt diff --git a/requirements.txt b/requirements.txt index 58e855e1..fa846e13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -47,7 +47,7 @@ rdflib==5.0.0 requests==2.24.0 requests-oauthlib==1.3.0 rsa==4.6 -schematicpy==0.1.11 +schematicpy==0.1.13 SecretStorage==2.3.1 setuptools==52.0.0 six==1.15.0 From 048f3da6f9b803eda6a9323c222d21443d6438d5 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Mon, 26 Apr 2021 14:22:43 -0700 Subject: [PATCH 030/260] config.yml file in root of repo by default --- python/metadata_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/metadata_model.py b/python/metadata_model.py index 92883cb1..dd24e2af 100644 --- a/python/metadata_model.py +++ b/python/metadata_model.py @@ -1,7 +1,7 @@ from schematic.models.metadata import MetadataModel from schematic import CONFIG -config = CONFIG.load_config("./schematic/config.yml") +config = CONFIG.load_config("config.yml") inputMModelLocation = CONFIG["model"]["input"]["location"] inputMModelLocationType = CONFIG["model"]["input"]["file_type"] From aa2f06d934107a45bccfc866d8a36cecddd8ee3d Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 28 Apr 2021 23:55:27 -0700 Subject: [PATCH 031/260] remove call to getModelManifest() in metadata_model.py --- python/metadata_model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/metadata_model.py b/python/metadata_model.py index dd24e2af..378fad67 100644 --- a/python/metadata_model.py +++ b/python/metadata_model.py @@ -1,6 +1,7 @@ from schematic.models.metadata import MetadataModel from schematic import CONFIG + config = CONFIG.load_config("config.yml") inputMModelLocation = CONFIG["model"]["input"]["location"] @@ -10,5 +11,3 @@ manifest_data_type = CONFIG["manifest"]["data_type"] metadata_model = MetadataModel(inputMModelLocation, inputMModelLocationType) -metadata_model.getModelManifest(title=manifest_title, - rootNode=manifest_data_type) From 7af2a1586c9b62997de37eff621c8a358f308cd1 Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Tue, 4 May 2021 16:21:39 -0700 Subject: [PATCH 032/260] change environment name to data_curator_env --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b6e8b85..eb28829e 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ Create a conda environment in the cloned directory from the `environment.yml` fi conda env create -f environment.yml -Here, our conda environment name `data_curator_env_oauth` is set from the `environment.yml` file . +Here, our conda environment name `data_curator_env` is set from the `environment.yml` file . -Activate the `data_curator_env_oauth` environment: +Activate the `data_curator_env` environment: - conda activate data_curator_env_oauth + conda activate data_curator_env ### Schematic Setup From 5b1e706fa17044cc3109bc2a36d12cbfc4f142eb Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 5 May 2021 16:24:16 -0700 Subject: [PATCH 033/260] add readr package to renv.lock --- renv.lock | 302 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 235 insertions(+), 67 deletions(-) diff --git a/renv.lock b/renv.lock index 776c6bfd..aa3faad3 100644 --- a/renv.lock +++ b/renv.lock @@ -4,11 +4,7 @@ "Repositories": [ { "Name": "CRAN", - "URL": "https://cran.rstudio.com" - }, - { - "Name": "Sage", - "URL": "http://ran.synapse.org" + "URL": "https://ftp.osuosl.org/pub/cran" } ] }, @@ -22,10 +18,10 @@ }, "DT": { "Package": "DT", - "Version": "0.17", + "Version": "0.14", "Source": "Repository", "Repository": "CRAN", - "Hash": "56b33b77f4cffd78ff96b8e5a69eabb0" + "Hash": "a3580ce0309c94d061c23b0afb4accbd" }, "MASS": { "Package": "MASS", @@ -69,6 +65,20 @@ "Repository": "CRAN", "Hash": "e8a22846fff485f0be3770c2da758713" }, + "assertthat": { + "Package": "assertthat", + "Version": "0.2.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "50c838a310445e954bc13f26f26a6ecf" + }, + "backports": { + "Package": "backports", + "Version": "1.1.8", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3ef0eac19317fd03c0c854aed581d473" + }, "base64enc": { "Package": "base64enc", "Version": "0.1-3", @@ -76,19 +86,33 @@ "Repository": "CRAN", "Hash": "543776ae6848fde2f48ff3816d0628bc" }, + "callr": { + "Package": "callr", + "Version": "3.4.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "643163a00cb536454c624883a10ae0bc" + }, "cli": { "Package": "cli", - "Version": "2.4.0", + "Version": "2.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ff0becff7bfdfe3f75d29aff8f3172dd" + }, + "clipr": { + "Package": "clipr", + "Version": "0.7.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "be982c9bcbfbe9e59c0225b0ed37d47e" + "Hash": "08cf4045c149a0f0eaf405324c7495bd" }, "colorspace": { "Package": "colorspace", - "Version": "2.0-0", + "Version": "1.4-1", "Source": "Repository", "Repository": "CRAN", - "Hash": "abea3384649ef37f60ef51ce002f3547" + "Hash": "6b436e95723d1f0e861224dd9b094dfb" }, "commonmark": { "Package": "commonmark", @@ -113,10 +137,10 @@ }, "crosstalk": { "Package": "crosstalk", - "Version": "1.1.1", + "Version": "1.1.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "2b06f9e415a62b6762e4b8098d2aecbc" + "Hash": "ae55f5d7c02f0ab43c58dd050694f2b4" }, "curl": { "Package": "curl", @@ -127,10 +151,17 @@ }, "data.table": { "Package": "data.table", - "Version": "1.14.0", + "Version": "1.12.8", "Source": "Repository", "Repository": "CRAN", - "Hash": "d1b8b1a821ee564a3515fa6c6d5c52dc" + "Hash": "cd711af60c47207a776213a368626369" + }, + "desc": { + "Package": "desc", + "Version": "1.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6c8fe8fa26a23b79949375d372c7b395" }, "digest": { "Package": "digest", @@ -141,10 +172,10 @@ }, "dplyr": { "Package": "dplyr", - "Version": "1.0.5", + "Version": "1.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "d0d76c11ec807eb3f000eba4e3eb0f68" + "Hash": "4011f62581a34080e44105d4aa05a97f" }, "ellipsis": { "Package": "ellipsis", @@ -153,19 +184,26 @@ "Repository": "CRAN", "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" }, + "evaluate": { + "Package": "evaluate", + "Version": "0.14", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" + }, "fansi": { "Package": "fansi", - "Version": "0.4.2", + "Version": "0.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "fea074fb67fe4c25d47ad09087da847d" + "Hash": "7fce217eaaf8016e72065e85c73027b5" }, "farver": { "Package": "farver", - "Version": "2.1.0", + "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "c98eb5133d9cb9e1622b8691487f11bb" + "Hash": "dad6793a5a1f73c8e91f1a1e3e834b05" }, "fastmap": { "Package": "fastmap", @@ -176,24 +214,24 @@ }, "fs": { "Package": "fs", - "Version": "1.5.0", + "Version": "1.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "44594a07a42e5f91fac9f93fda6d0109" + "Hash": "8c04112383ca1988e96f429255f95675" }, "generics": { "Package": "generics", - "Version": "0.1.0", + "Version": "0.0.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "4d243a9c10b00589889fe32314ffd902" + "Hash": "b8cff1d1391fd1ad8b65877f4c7f2e53" }, "ggplot2": { "Package": "ggplot2", - "Version": "3.3.3", + "Version": "3.3.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "3eb6477d01eb5bbdc03f7d5f70f2733e" + "Hash": "4ded8b439797f7b1693bd3d238d0106b" }, "glue": { "Package": "glue", @@ -209,19 +247,45 @@ "Repository": "CRAN", "Hash": "ac5c6baf7822ce8732b343f14c072c4d" }, + "hexbin": { + "Package": "hexbin", + "Version": "1.28.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "3d59212f2814d65dff517e6899813c58" + }, + "highr": { + "Package": "highr", + "Version": "0.8", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4dc5bb88961e347a0f4d8aad597cbfac" + }, + "hms": { + "Package": "hms", + "Version": "0.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "726671f634529d470545f9fd1a9d1869" + }, "htmltools": { "Package": "htmltools", - "Version": "0.5.1.1", + "Version": "0.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "af2c2531e55df5cf230c4b5444fc973c" + "Hash": "7d651b7131794fe007b1ad6f21aaa401" }, "htmlwidgets": { "Package": "htmlwidgets", - "Version": "1.5.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6fdaa86d0700f8b3e92ee3c445a5a10d" + "Version": "1.5.1.9001", + "Source": "GitHub", + "RemoteType": "github", + "RemoteHost": "api.github.com", + "RemoteRepo": "htmlwidgets", + "RemoteUsername": "ramnathv", + "RemoteRef": "master", + "RemoteSha": "6fcc4b03ed3fc42be76d4e43d863db3d85c8babb", + "Hash": "43198daf611c2422a3969bf1f02213b4" }, "httpuv": { "Package": "httpuv", @@ -239,24 +303,31 @@ }, "isoband": { "Package": "isoband", - "Version": "0.2.4", + "Version": "0.2.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "b2008df40fb297e3fef135c7e8eeec1a" + "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" }, "jsonlite": { "Package": "jsonlite", - "Version": "1.7.2", + "Version": "1.7.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2657f20b9a74c996c602e74ebe540b06" + }, + "knitr": { + "Package": "knitr", + "Version": "1.29", "Source": "Repository", "Repository": "CRAN", - "Hash": "98138e0994d41508c7a6b84a0600cfcb" + "Hash": "e5f4c41c17df8cdf7b0df12117c0d99a" }, "labeling": { "Package": "labeling", - "Version": "0.4.2", + "Version": "0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "3d5108641f47470611a32d0bdf357a72" + "Hash": "73832978c1de350df58108c745ed0e3e" }, "later": { "Package": "later", @@ -281,10 +352,10 @@ }, "lifecycle": { "Package": "lifecycle", - "Version": "1.0.0", + "Version": "0.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "3471fb65971f1a7b2d4ae7848cf2db8d" + "Hash": "361811f31f71f8a617a9a68bf63f1f42" }, "magrittr": { "Package": "magrittr", @@ -293,6 +364,13 @@ "Repository": "CRAN", "Hash": "1bb58822a20301cee84a41678e25d9b7" }, + "markdown": { + "Package": "markdown", + "Version": "1.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "61e4a10781dd00d7d81dd06ca9b94e95" + }, "mgcv": { "Package": "mgcv", "Version": "1.8-31", @@ -330,10 +408,17 @@ }, "pillar": { "Package": "pillar", - "Version": "1.5.1", + "Version": "1.4.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "24622aa4a0d3de3463c34513edca99b2" + "Hash": "bdf26e55ccb7df3e49a490150277f002" + }, + "pkgbuild": { + "Package": "pkgbuild", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "404684bc4e3685007f9720adf13b06c1" }, "pkgconfig": { "Package": "pkgconfig", @@ -342,12 +427,46 @@ "Repository": "CRAN", "Hash": "01f28d4278f15c76cddbea05899c5d6f" }, + "pkgload": { + "Package": "pkgload", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "b6b150cd4709e0c0c9b5d51ac4376282" + }, "plotly": { "Package": "plotly", - "Version": "4.9.3", + "Version": "4.9.2.9000", + "Source": "GitHub", + "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", + "RemoteType": "github", + "RemoteHost": "api.github.com", + "RemoteRepo": "plotly", + "RemoteUsername": "ropensci", + "RemoteRef": "master", + "RemoteSha": "1d1eddda377685cf900ed4a7b16e7796a24b8fe4", + "Hash": "d2858de9ced9d164806a7aa2eebb8b2c" + }, + "praise": { + "Package": "praise", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a555924add98c99d2f411e37e7d25e9f" + }, + "prettyunits": { + "Package": "prettyunits", + "Version": "1.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "f6b85d9e4ed88074ea0ede1aa74bb00e" + "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" + }, + "processx": { + "Package": "processx", + "Version": "3.4.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f4f13345fcb00c51ace12f65dd18749f" }, "promises": { "Package": "promises", @@ -356,6 +475,13 @@ "Repository": "CRAN", "Hash": "a8730dcbdd19f9047774909f0ec214a4" }, + "ps": { + "Package": "ps", + "Version": "1.3.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "425d938eb9c02906a8ac98c0c2a306b5" + }, "purrr": { "Package": "purrr", "Version": "0.3.4", @@ -370,6 +496,13 @@ "Repository": "CRAN", "Hash": "8c8298583adbbe76f3c2220eef71bebc" }, + "readr": { + "Package": "readr", + "Version": "1.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2639976851f71f330264a9c9c3d43a61" + }, "renv": { "Package": "renv", "Version": "0.11.0-3", @@ -398,10 +531,24 @@ }, "rlang": { "Package": "rlang", - "Version": "0.4.10", + "Version": "0.4.7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "c06d2a6887f4b414f8e927afd9ee976a" + }, + "rmarkdown": { + "Package": "rmarkdown", + "Version": "2.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "599df23c40a4fce9c7b4764f28c37857" + "Hash": "202260e1b2c410edc086d5b8f1ed946e" + }, + "rprojroot": { + "Package": "rprojroot", + "Version": "1.3-2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f6a407ae5dd21f6f80a6708bbb6eb3ae" }, "rstudioapi": { "Package": "rstudioapi", @@ -412,10 +559,10 @@ }, "sass": { "Package": "sass", - "Version": "0.3.1", + "Version": "0.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "3ef1adfe46b7b144b970d74ce33ab0d6" + "Hash": "441417bbd40d5bbd07561cc40fb182ed" }, "scales": { "Package": "scales", @@ -440,29 +587,29 @@ }, "shinyjs": { "Package": "shinyjs", - "Version": "2.0.0", + "Version": "1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "9ddfc91d4280eaa34c2103951538976f" + "Hash": "b40a5207b6624f6e2b8cdb50689cdb69" }, "shinypop": { "Package": "shinypop", - "Version": "0.0.1.930", + "Version": "0.0.1.920", "Source": "GitHub", "RemoteType": "github", "RemoteHost": "api.github.com", "RemoteRepo": "shinypop", "RemoteUsername": "dreamRs", - "RemoteRef": "HEAD", - "RemoteSha": "3ab7e384c835f78c42997618d106e2121f4cc50b", - "Hash": "1d9118cbf95a83cee2f98dd5c0dff105" + "RemoteRef": "master", + "RemoteSha": "e3be83f99e85401c59ec7a1dfafa5c92c4f7367b", + "Hash": "095c2c667d27cd2f5829967a48e14229" }, "shinythemes": { "Package": "shinythemes", - "Version": "1.2.0", + "Version": "1.1.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "30f0ebc41feba25691073626ff5e2cf4" + "Hash": "8f047210d7d68ea4860a3c0d8cced272" }, "sourcetools": { "Package": "sourcetools", @@ -473,10 +620,10 @@ }, "stringi": { "Package": "stringi", - "Version": "1.5.3", + "Version": "1.4.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "a063ebea753c92910a4cca7b18bc1f05" + "Hash": "e99d8d656980d2dd416a962ae55aec90" }, "stringr": { "Package": "stringr", @@ -492,19 +639,26 @@ "Repository": "CRAN", "Hash": "507f3116a38d37ad330a038b3be07b66" }, + "testthat": { + "Package": "testthat", + "Version": "2.3.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "0829b987b8961fb07f3b1b64a2fbc495" + }, "tibble": { "Package": "tibble", - "Version": "3.1.0", + "Version": "3.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "4d894a114dbd4ecafeda5074e7c538e6" + "Hash": "08bd36bd34b20d4f7971d49e81deaab0" }, "tidyr": { "Package": "tidyr", - "Version": "1.1.3", + "Version": "1.1.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "450d7dfaedde58e28586b854eeece4fa" + "Hash": "7395a05640bf91502dd475a84008d87e" }, "tidyselect": { "Package": "tidyselect", @@ -513,19 +667,26 @@ "Repository": "CRAN", "Hash": "6ea435c354e8448819627cf686f66e0a" }, + "tinytex": { + "Package": "tinytex", + "Version": "0.24", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "8f24b65b86f4d6d7b1e2d8a4ce2c02fb" + }, "utf8": { "Package": "utf8", - "Version": "1.2.1", + "Version": "1.1.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "c3ad47dc6da0751f18ed53c4613e3ac7" + "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" }, "vctrs": { "Package": "vctrs", - "Version": "0.3.7", + "Version": "0.3.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "5540dc30a203a43a1ce5dc6a89532b3b" + "Hash": "1739235995f08583db4095a28c357207" }, "viridisLite": { "Package": "viridisLite", @@ -548,6 +709,13 @@ "Repository": "CRAN", "Hash": "ecd17882a0b4419545691e095b74ee89" }, + "xfun": { + "Package": "xfun", + "Version": "0.15", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "ddeca7650052ff9131ac7c41a9a77b3b" + }, "xtable": { "Package": "xtable", "Version": "1.8-4", From ceb76757f02805d601ecddd573e345459961a75a Mon Sep 17 00:00:00 2001 From: Sujay Patil Date: Wed, 5 May 2021 16:25:42 -0700 Subject: [PATCH 034/260] load readr package using library() --- server.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.R b/server.R index 456d54eb..12203bb1 100644 --- a/server.R +++ b/server.R @@ -22,9 +22,10 @@ library(purrr) library(plotly) library(shinypop) library(waiter) +library(readr) # Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env") +reticulate::use_condaenv("data_curator_env_oauth") shinyServer(function(input, output, session) { ########### session global variables From d30e8718c4004b1bc7e2527a688ba8c07df244d4 Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 00:52:57 +0000 Subject: [PATCH 035/260] improve config environment --- .Rprofile | 1 + environment.yml | 2 +- example_config.yaml | 1 + global.R | 4 +++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.Rprofile b/.Rprofile index 2d988993..2d214a61 100644 --- a/.Rprofile +++ b/.Rprofile @@ -7,5 +7,6 @@ ) } +options(stringsAsFactors=FALSE) source("renv/activate.R") diff --git a/environment.yml b/environment.yml index d5e40aa8..325783c6 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: data_curator_env +name: data_curator_env_oauth channels: - defaults dependencies: diff --git a/example_config.yaml b/example_config.yaml index 73014ea2..81fb5268 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -3,3 +3,4 @@ # client_id has to be a string client_id: client_secret: +APP_URL: \ No newline at end of file diff --git a/global.R b/global.R index 03afeffb..167b8b90 100644 --- a/global.R +++ b/global.R @@ -4,7 +4,7 @@ library(rjson) library(yaml) -APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" +# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if @@ -18,8 +18,10 @@ oauth_client = yaml.load_file("config.yaml") client_id <- toString(oauth_client$client_id) client_secret <- oauth_client$client_secret +APP_URL <- oauth_client$APP_URL if (is.null(client_id)) stop("config.yaml is missing client_id") if (is.null(client_secret)) stop("config.yaml is missing client_secret") +if (is.null(APP_URL)) stop("config.yaml is missing client_secret") app <- oauth_app("shinysynapse", key = client_id, From e4f321b8ceb086afe63533101f8e8744e9a0f6e7 Mon Sep 17 00:00:00 2001 From: Rong Chai Date: Thu, 6 May 2021 18:59:19 +0000 Subject: [PATCH 036/260] set projects, folders, templates to server global variables --- .Rprofile | 12 +- example_config.yaml | 4 +- global.R | 1 - server.R | 644 +++++++++++++++++--------------------------- 4 files changed, 261 insertions(+), 400 deletions(-) diff --git a/.Rprofile b/.Rprofile index 2d214a61..175d5f03 100644 --- a/.Rprofile +++ b/.Rprofile @@ -1,10 +1,10 @@ .First <- function() { - options( - repos = c( - CRAN = "https://cran.rstudio.com/", - Sage = "http://ran.synapse.org" - ) - ) + options( + repos = c( + CRAN = "https://cran.rstudio.com/", + Sage = "http://ran.synapse.org" + ) + ) } options(stringsAsFactors=FALSE) diff --git a/example_config.yaml b/example_config.yaml index 81fb5268..3908931e 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -1,6 +1,6 @@ # This file contains the oauth client id and secret required for # the application. This file needs to have chmod 400 permissions -# client_id has to be a string +# client_id and APP_URL has to be a string client_id: client_secret: -APP_URL: \ No newline at end of file +APP_URL: diff --git a/global.R b/global.R index 167b8b90..7eb8e4f8 100644 --- a/global.R +++ b/global.R @@ -3,7 +3,6 @@ library(httr) library(rjson) library(yaml) - # APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" has_auth_code <- function(params) { diff --git a/server.R b/server.R index 12203bb1..aab74e20 100644 --- a/server.R +++ b/server.R @@ -1,12 +1,8 @@ -# This is the server logic for a Shiny web application. -# You can find out more about building applications with Shiny here: -# -# http://shiny.rstudio.com -# -# This server has been modified to be used specifically on Sage Bionetworks Synapse pages -# to log into Synapse as the currently logged in user from the web portal using the session token. -# -# https://www.synapse.org +# This is the server logic for a Shiny web application. You can find out more +# about building applications with Shiny here: http://shiny.rstudio.com This +# server has been modified to be used specifically on Sage Bionetworks Synapse +# pages to log into Synapse as the currently logged in user from the web portal +# using the session token. https://www.synapse.org library(shiny) library(shinyjs) @@ -37,40 +33,40 @@ shinyServer(function(input, output, session) { return() } redirect_url <- paste0( - api$access, "?", "redirect_uri=", - APP_URL, "&grant_type=", + api$access, "?", "redirect_uri=", APP_URL, "&grant_type=", "authorization_code", "&code=", params$code ) # get the access_token and userinfo token - req <- POST(redirect_url, - encode = "form", - body = "", - authenticate(app$key, app$secret, type = "basic"), - config = list() - ) + req <- POST(redirect_url, encode = "form", body = "", authenticate(app$key, app$secret, + type = "basic" + ), config = list()) # Stop the code if anything other than 2XX status code is returned stop_for_status(req, task = "get an access token") token_response <- content(req, type = NULL) access_token <- token_response$access_token # import module that contains SynapseStorage class - synapse_driver <- import("schematic.store.synapse") + synapse_driver <- import("schematic.store.synapse")$SynapseStorage ### read config in config <- jsonlite::fromJSON("www/config.json") ### logs in and gets list of projects they have access to synStore_obj <- NULL - # get_projects_list(synStore_obj) - projects_list <- c() + projects_namedList <- NULL - projects_namedList <- c() + folders_namedList <- NULL + folder_synID <- NULL # selected foler synapse ID - proj_folder_manifest_cells <- c() + schema_name <- NULL # selected template schema name + filename_list <- NULL - folder_synID <- NULL + ### mapping from display name to schema name + schema_name <- config$manifest_schemas$schema_name + display_name <- config$manifest_schemas$display_name + schema_to_display_lookup <- data.frame(schema_name, display_name) - filename_list <- c() + clean_tags <- c("text_div2", "tbl2", "gsheet_btn", "gsheet_div", "submitButton") ############ ### synapse cookies @@ -86,21 +82,19 @@ shinyServer(function(input, output, session) { ### welcome message output$title <- renderUI({ - titlePanel(h4(sprintf( - "Welcome, %s", syn_getUserProfile()$userName - ))) + titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) }) - ### updating global vars with values for projects - # synStore_obj <<- synapse_driver$SynapseStorage(config$main_fileview, token = input$cookie) - synStore_obj <<- synapse_driver$SynapseStorage(token = input$cookie) + ### updating global vars with values for projects synStore_obj <<- + ### synapse_driver(config$main_fileview, token = input$cookie) + synStore_obj <<- synapse_driver(token = input$cookie) # get_projects_list(synStore_obj) - projects_list <<- synapse_driver$SynapseStorage$getStorageProjects(synStore_obj) + projects_list <- synapse_driver$getStorageProjects(synStore_obj) + # projects_namedList <- NULL # may need to uncomment when we have refresh button for (i in seq_along(projects_list)) { - projects_namedList[projects_list[[i]][[2]]] <<- - projects_list[[i]][[1]] + projects_namedList[projects_list[[i]][[2]]] <<- projects_list[[i]][[1]] } ### updates project dropdown @@ -109,9 +103,7 @@ shinyServer(function(input, output, session) { ### update waiter loading screen once login successful waiter_update(html = tagList( img(src = "synapse_logo.png", height = "120px"), - h3(sprintf( - "Welcome, %s!", syn_getUserProfile()$userName - )) + h3(sprintf("Welcome, %s!", syn_getUserProfile()$userName)) )) Sys.sleep(2) waiter_hide() @@ -120,10 +112,10 @@ shinyServer(function(input, output, session) { Sys.sleep(2) waiter_update(html = tagList( img(src = "synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), - span( - "Please ", - a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), + h3("Looks like you're not logged in!"), span( + "Please ", a("login", + href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" + ), " to Synapse, then refresh this page." ) )) @@ -132,29 +124,19 @@ shinyServer(function(input, output, session) { }) - ###### BUTTONS STUFF !!! remove last arrow - Previous_Button <- tags$div(actionButton( - "Prev_Tab", - HTML('
') - )) - Next_Button <- div(actionButton( - "Next_Tab", - HTML('
') - )) + ###### BUTTONS STUFF !!! remove last arrow + Previous_Button <- tags$div(actionButton("Prev_Tab", HTML("
"))) + Next_Button <- div(actionButton("Next_Tab", HTML("
"))) - list_tabs <- c("instructions", "data", "template", "upload") + tabs_list <- c("instructions", "data", "template", "upload") output$Next_Previous <- renderUI({ - tab_list <- list_tabs if (input[["tabs"]] == "upload") { # column(1,offset=1,Previous_Button) } else if (input[["tabs"]] == "instructions") { column(1, offset = 10, Next_Button) } else { - div( - column(1, offset = 1, Previous_Button), - column(1, offset = 8, Next_Button) - ) + div(column(1, offset = 1, Previous_Button), column(1, offset = 8, Next_Button)) } }) @@ -173,49 +155,45 @@ shinyServer(function(input, output, session) { ####### BUTTONS END ### lists folder datasets if exists in project - observeEvent( - ignoreNULL = TRUE, - ignoreInit = TRUE, - input$var, - { - output$folders <- renderUI({ - selected_project <- input$var - - # if selected_project not empty - if (!is.null(selected_project)) { - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - ### gets folders per project - folder_list <- - synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folderNames <- names(folders_namedList) + observeEvent(ignoreInit = TRUE, input$var, { + output$folders <- renderUI({ + # get synID of selected project + project_synID <- projects_namedList[[input$var]] + + ### gets folders per project + folder_list <- synapse_driver$getStorageDatasetsInProject( + synStore_obj, + project_synID + ) - ### updates foldernames - selectInput( - inputId = "dataset", - label = "Folder:", - choices = folderNames - ) - } - }) - } - ) + folders_namedList <<- NULL # need to clean first + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <<- folder_list[[i]][[1]] + } + folderNames <- names(folders_namedList) - ### mapping from display name to schema name - schema_name <- config$manifest_schemas$schema_name - display_name <- config$manifest_schemas$display_name + ### updates foldernames + selectInput(inputId = "dataset", label = "Folder:", choices = folderNames) + }) + }) + + # update selected folder ID + observeEvent(input$dataset, { + # TODO: check how different from using rectivateValues() + folder_synID <<- folders_namedList[[input$dataset]] + }) output$manifest_display_name <- renderUI({ - selectInput( - inputId = "template_type", - label = "Template:", - choices = display_name - ) + selectInput(inputId = "template_type", label = "Template:", choices = display_name) + }) + + # update selected schema template name + observeEvent(input$dataset, { + template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), + 1, + drop = F + ] + schema_name <<- as.character(template_type_df$schema_name) }) observeEvent( @@ -224,97 +202,59 @@ shinyServer(function(input, output, session) { input$template_type }, { - sapply( - c( - "text_div", - "text_div2", - "tbl2", - "gsheet_btn", - "gsheet_div", - "submitButton" - ), - FUN = hide - ) + sapply(c("text_div", clean_tags), FUN = hide) } ) - schema_to_display_lookup <- data.frame(schema_name, display_name) - # loading screen for template link generation manifest_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Generating link...") - ), + html = tagList(spin_plus(), br(), h4("Generating link...")), color = "rgba(66, 72, 116, .9)" ) - ### shows new metadata link when get gsheets template button pressed OR updates old metadata if is exists + ### shows new metadata link when get gsheets template button pressed OR updates old + ### metadata if is exists observeEvent(input$download, { manifest_w$show() if (is.null(input$template_type)) { output$text <- renderUI({ - tags$span( - class = "error_msg", - HTML("Please select a template from the 'Select your Dataset' tab !") - ) + tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) }) } else { - selected_folder <- input$dataset - selected_project <- input$var - - ### lookup schema template name - template_type_df <- - schema_to_display_lookup[match( - input$template_type, - schema_to_display_lookup$display_name - ), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - folder_list <- - synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] - ### checks if a manifest already exists - existing_manifestID <- - synapse_driver$SynapseStorage$getDatasetManifest(synStore_obj, folder_synID) + existing_manifestID <- synapse_driver$getDatasetManifest( + synStore_obj, + folder_synID + ) ### if there isn't an existing manifest make a new one if (existing_manifestID == "") { - file_list <- - synapse_driver$SynapseStorage$getFilesInStorageDataset(synStore_obj, folder_synID) + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) file_namedList <- c() for (i in seq_along(file_list)) { file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] } filename_list <- names(file_namedList) - manifest_url <- - metadata_model$getModelManifest( - paste0(config$community, " ", input$template_type), - template_type, - filenames = as.list(filename_list) - ) - ### make sure not scalar if length of list is 1 in R - ## add in the step to convert names later ### + manifest_url <- metadata_model$getModelManifest(paste0( + config$community, + " ", input$template_type + ), schema_name, filenames = as.list(filename_list)) + ### make sure not scalar if length of list is 1 in R add in the step to convert + ### names later ### } else { ### if the manifest already exists manifest_entity <- syn_get(existing_manifestID) - # prepopulatedManifestURL = mm.populateModelManifest("test_update", entity.path, component) - manifest_url <- - metadata_model$populateModelManifest( - paste0(config$community, " ", input$template_type), - manifest_entity$path, - template_type - ) + # prepopulatedManifestURL = mm.populateModelManifest('test_update', entity.path, + # component) + manifest_url <- metadata_model$populateModelManifest(paste0( + config$community, + " ", input$template_type + ), manifest_entity$path, schema_name) } output$text <- renderUI({ @@ -324,22 +264,18 @@ shinyServer(function(input, output, session) { ## links shows in text box show("text_div") - ### if want a progress bar need more feedback from API to know how to increment progress bar ### + ### if want a progress bar need more feedback from API to know how to increment + ### progress bar ### manifest_w$hide() }) ### renders fileInput ui output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) + fileInput("file1", "Upload CSV File", accept = c( + "text/csv", "text/comma-separated-values", + ".csv" + )) }) ### reads csv file and previews @@ -347,41 +283,30 @@ shinyServer(function(input, output, session) { if (is.null(input$file1)) { return(NULL) } # if no file uploaded, return null - infile <- readr::read_csv(input$file1$datapath, - na = c("", "NA"), - col_types = readr::cols(.default = "c") - ) %>% + infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% replace(., is.na(.), "") # change NA to blank to match schema output) - ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + ### remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] }) observeEvent(input$file1, { - sapply(c( - "text_div2", - "tbl2", - "gsheet_btn", - "gsheet_div", - "submitButton" - ), - FUN = hide - ) + sapply(clean_tags, FUN = hide) }) ### renders in DT for preview observeEvent(rawData(), { output$tbl <- DT::renderDT({ - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE) + datatable(rawData(), + options = list(lengthChange = FALSE, scrollX = TRUE), + rownames = FALSE + ) }) }) ## loading screen for validating metadata validate_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Validating...") - ), + html = tagList(spin_plus(), br(), h4("Validating...")), color = "rgba(66, 72, 116, .9)" ) @@ -394,40 +319,62 @@ shinyServer(function(input, output, session) { validate_w$show() if (!is.null(rawData()) & !is.null(input$template_type)) { - ### lookup schema template name - template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) + annotation_status <- metadata_model$validateModelManifest( + input$file1$datapath, + schema_name + ) if (length(annotation_status) != 0) { validation_res <- "invalid" # mismatched template index - inx_mt <- which(sapply(annotation_status, function(x) grepl("Component value provided is: .*, whereas the Template Type is: .*", x[[3]]))) + inx_mt <- which(sapply(annotation_status, function(x) { + grepl( + "Component value provided is: .*, whereas the Template Type is: .*", + x[[3]] + ) + })) # missing column index - inx_ws <- which(sapply(annotation_status, function(x) grepl("Wrong schema", x[[2]]))) + inx_ws <- which(sapply(annotation_status, function(x) { + grepl( + "Wrong schema", + x[[2]] + ) + })) - if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template + if (length(inx_mt) > 0) { + # mismatched error(s): selected template mismatched with validating template waiter_msg <- "Mismatched Template Found !" # get all mismatched components - error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% unique() + error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% + unique() column_names <- "Component" # error messages for mismatch mismatch_c <- error_values %>% sQuote() %>% paste(collapse = ", ") - type_error <- paste0("The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", input$template_type, " >>.") - help_msg <- paste0("Please check that you have selected the correct template in the Select your Dataset tab and - ensure your metadata contains only one template, e.g. ", input$template_type, ".") + type_error <- paste0( + "The submitted metadata contains << ", + mismatch_c, " >> in the Component column, but requested validation for << ", + input$template_type, " >>." + ) + help_msg <- paste0( + "Please check that you have selected the correct template in the Select your Dataset tab and + ensure your metadata contains only one template, e.g. ", + input$template_type, "." + ) # get wrong columns and values for updating preview table - errorDT <- data.frame( - Column = sapply(annotation_status[inx_mt], function(i) i[[2]]), - Value = sapply(annotation_status[inx_mt], function(i) i[[4]][[1]]) - ) - } else if (length(inx_ws) > 0) { # wrong schema error(s): validating metadata miss any required columns + errorDT <- data.frame(Column = sapply( + annotation_status[inx_mt], + function(i) i[[2]] + ), Value = sapply( + annotation_status[inx_mt], + function(i) i[[4]][[1]] + )) + } else if (length(inx_ws) > 0) { + # wrong schema error(s): validating metadata miss any required columns waiter_msg <- "Wrong Schema Used !" type_error <- "The submitted metadata does not contain all required column(s)." @@ -435,13 +382,18 @@ shinyServer(function(input, output, session) { ensure your metadata contains all required columns." } else { waiter_msg <- sprintf("%d errors found", length(annotation_status)) - type_error <- paste0("The submitted metadata have ", length(annotation_status), " errors.") + type_error <- paste0( + "The submitted metadata have ", length(annotation_status), + " errors." + ) help_msg <- NULL errorDT <- data.frame( Column = sapply(annotation_status, function(i) i[[2]]), - Value = sapply(annotation_status, function(i) i[[4]][[1]]), - Error = sapply(annotation_status, function(i) i[[3]]) + Value = sapply(annotation_status, function(i) i[[4]][[1]]), Error = sapply( + annotation_status, + function(i) i[[3]] + ) ) # sort rows based on input column names errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))), ] @@ -453,19 +405,17 @@ shinyServer(function(input, output, session) { caption = "The errors are also highlighted in the preview table above.", rownames = FALSE, options = list( pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), - lengthChange = FALSE, info = FALSE, searching = FALSE + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE ) ) }) } - validate_w$update( - html = h3(waiter_msg) - ) + validate_w$update(html = h3(waiter_msg)) - ### update DT view with incorrect values - ### currently only one column, requires backend support of multiple + ### update DT view with incorrect values currently only one column, requires + ### backend support of multiple output$tbl <- DT::renderDT({ if (length(inx_ws) > 0) { # if it is wrong schema error, highlight all cells @@ -473,9 +423,10 @@ shinyServer(function(input, output, session) { formatStyle(1, target = "row", backgroundColor = "yellow") } else { datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% - formatStyle(errorDT$Column, - backgroundColor = styleEqual(errorDT$Value, rep("yellow", length(errorDT$Value))) - ) + formatStyle(errorDT$Column, backgroundColor = styleEqual( + errorDT$Value, + rep("yellow", length(errorDT$Value)) + )) } }) @@ -491,14 +442,28 @@ shinyServer(function(input, output, session) { ### format output text output$text2 <- renderUI({ - text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg") + text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", + "success_msg", "error_msg" + ) tagList( - if (is.null(input$template_type)) span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")), - if (is.null(rawData())) span(class = text_class, HTML("Please upload a filled template !")), - if (!is.null(validation_res)) span(class = text_class, HTML(paste0("Your metadata is ", validation_res, " !!!"))), - if (!is.null(type_error)) span(class = text_class, HTML(paste0("

", type_error))), - if (!is.null(help_msg)) span(class = text_class, HTML(paste0("

", help_msg))) + if (is.null(input$template_type)) { + span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) + }, + if (is.null(rawData())) { + span(class = text_class, HTML("Please upload a filled template !")) + }, + if (!is.null(validation_res)) { + span(class = text_class, HTML(paste0( + "Your metadata is ", validation_res, + " !!!" + ))) + }, if (!is.null(type_error)) { + span(class = text_class, HTML(paste0("

", type_error))) + }, + if (!is.null(help_msg)) { + span(class = text_class, HTML(paste0("

", help_msg))) + } ) }) @@ -513,42 +478,22 @@ shinyServer(function(input, output, session) { observeEvent(input$gsheet_btn, { # loading screen for Google link generation gsheet_w <- Waiter$new( - html = tagList( - spin_plus(), br(), - h4("Generating link...") - ), + html = tagList(spin_plus(), br(), h4("Generating link...")), color = "rgba(66, 72, 116, .9)" ) gsheet_w$show() - ### lookup schema template name - template_type_df <- - schema_to_display_lookup[match( - input$template_type, - schema_to_display_lookup$display_name - ), 1, drop = F] - template_type <- as.character(template_type_df$schema_name) - - ## if error not empty aka there is an error - filled_manifest <- - metadata_model$populateModelManifest( - paste0(config$community, " ", input$template_type), - input$file1$datapath, - template_type - ) + filled_manifest <- metadata_model$populateModelManifest(paste0( + config$community, + " ", input$template_type + ), input$file1$datapath, schema_name) show("gsheet_div") output$gsheet_link <- renderUI({ - # tags$a(href = filled_manifest, filled_manifest, target = "_blank") - HTML( - paste0( - 'Edit on the Google Sheet.' - ) - ) + # tags$a(href = filled_manifest, filled_manifest, target = '_blank') + HTML(paste0("Edit on the Google Sheet.")) }) hide("gsheet_btn") # hide btn once link generated @@ -558,10 +503,7 @@ shinyServer(function(input, output, session) { ## loading screen for submitting data submit_w <- Waiter$new( - html = tagList( - img(src = "loading.gif"), - h4("Submitting...") - ), + html = tagList(img(src = "loading.gif"), h4("Submitting...")), color = "#424874" ) @@ -569,49 +511,32 @@ shinyServer(function(input, output, session) { observeEvent(input$submitButton, { submit_w$show() - ### reads in csv - infile <- - readr::read_csv(input$file1$datapath, na = c("", "NA")) + # reads file csv again + infile <- readr::read_csv(input$file1$datapath, na = c("", "NA")) - ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + ### remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - ### IF an assay component selected (define assay components) - ## note for future - the type to filter (eg assay) on could probably also be a config choice - assay_schemas <- - config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] + ### IF an assay component selected (define assay components) note for future - the + ### type to filter (eg assay) on could probably also be a config choice + assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == + "assay"] - ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files + ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates + ### with synapse files if (input$template_type %in% assay_schemas) { - ### make into a csv or table for assay components - ### already has entityId + ### make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(infile)) { - write.csv( - infile, + write.csv(infile, file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" + quote = TRUE, row.names = FALSE, na = "" ) } else { - # if not get ids - selected_folder <- input$dataset - selected_project <- input$var - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - folder_list <- - synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - - folder_synID <- folders_namedList[[selected_folder]] - - file_list <- - synapse_driver$SynapseStorage$getFilesInStorageDataset(synStore_obj, folder_synID) + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) file_namedList <- c() for (i in seq_along(file_list)) { file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] @@ -619,156 +544,93 @@ shinyServer(function(input, output, session) { files_df <- stack(file_namedList) colnames(files_df) <- c("entityId", "Filename") - files_entity <- - inner_join(infile, files_df, by = "Filename") + files_entity <- inner_join(infile, files_df, by = "Filename") - write.csv( - files_entity, + write.csv(files_entity, file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" + quote = TRUE, row.names = FALSE, na = "" ) } - selected_project <- input$var - selected_folder <- input$dataset - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - - folder_list <- - synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] ### associates metadata with data and returns manifest id - manifest_id <- - synapse_driver$SynapseStorage$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", - folder_synID - ) + manifest_id <- synapse_driver$associateMetadataWithFiles( + synStore_obj, + "./files/synapse_storage_manifest.csv", folder_synID + ) print(manifest_id) - manifest_path <- - paste0("synapse.org/#!Synapse:", manifest_id) + manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) ### if no error if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success( - "Success!", - paste0("Manifest submitted to: ", manifest_path) - ) + nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") ### clear inputs - output$text2 <- renderUI({ - HTML("") - }) - output$submit <- renderUI({ - - }) + sapply(clean_tags, FUN = hide) ### rerenders fileinput UI output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) + fileInput("file1", "Upload CSV File", accept = c( + "text/csv", "text/comma-separated-values", + ".csv" + )) }) ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( - 0, - ncol = 0, nrow = 0 + output$tbl <- DT::renderDT(datatable(as.data.frame(matrix(0, + ncol = 0, + nrow = 0 )))) } else { submit_w$update(html = tagList( img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), - span(manifest_id, " is not a valid Synapse ID. Try again?") + h3("Uh oh, looks like something went wrong!"), span( + manifest_id, + " is not a valid Synapse ID. Try again?" + ) )) rm("/tmp/synapse_storage_manifest.csv") } } else { ## if not assay type tempalte - write.csv( - infile, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, - row.names = FALSE, - na = "" + write.csv(infile, + file = "./files/synapse_storage_manifest.csv", quote = TRUE, + row.names = FALSE, na = "" ) - selected_project <- input$var - selected_folder <- input$dataset - - project_synID <- - projects_namedList[[selected_project]] ### get synID of selected project - # folder_synID <- get_folder_synID(synStore_obj, project_synID, selected_folder) - - folder_list <- - synapse_driver$SynapseStorage$getStorageDatasetsInProject(synStore_obj, project_synID) - folders_namedList <- c() - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] - } - folder_synID <- folders_namedList[[selected_folder]] - ### associates metadata with data and returns manifest id - manifest_id <- - synapse_driver$SynapseStorage$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", - folder_synID - ) + manifest_id <- synapse_driver$associateMetadataWithFiles( + synStore_obj, + "./files/synapse_storage_manifest.csv", folder_synID + ) print(manifest_id) - manifest_path <- - paste0("synapse.org/#!Synapse:", manifest_id) + manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) ### if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success( - "Success!", - paste0("Manifest submitted to: ", manifest_path) - ) + nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") ### clear inputs - output$text2 <- renderUI({ - HTML("") - }) - output$submit <- renderUI({ - - }) + sapply(clean_tags, FUN = hide) ### rerenders fileinput UI output$fileInput_ui <- renderUI({ - fileInput( - "file1", - "Upload CSV File", - accept = c( - "text/csv", - "text/comma-separated-values", - ".csv" - ) - ) + fileInput("file1", "Upload CSV File", accept = c( + "text/csv", "text/comma-separated-values", + ".csv" + )) }) ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix( - 0, - ncol = 0, nrow = 0 + output$tbl <- DT::renderDT(datatable(as.data.frame(matrix(0, + ncol = 0, + nrow = 0 )))) } else { submit_w$update(html = tagList( img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), - span(manifest_id, " is not a valid Synapse ID. Try again?") + h3("Uh oh, looks like something went wrong!"), span( + manifest_id, + " is not a valid Synapse ID. Try again?" + ) )) rm("/tmp/synapse_storage_manifest.csv") } From 355fad5bed383f0b9b63e2cf28e96d67769a4fed Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 01:35:41 +0000 Subject: [PATCH 037/260] organize code/comments --- .gitignore | 3 +- global.R | 17 +++++ server.R | 186 ++++++++++++++++++++++------------------------------- ui.R | 16 ----- 4 files changed, 97 insertions(+), 125 deletions(-) diff --git a/.gitignore b/.gitignore index 11623cf0..162d9a21 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ schematic/token.pickle credentials.json token.pickle **/__pycache__ -config.yaml \ No newline at end of file +config.yaml +renv/activate.R \ No newline at end of file diff --git a/global.R b/global.R index 7eb8e4f8..d380375b 100644 --- a/global.R +++ b/global.R @@ -1,7 +1,24 @@ +suppressPackageStartupMessages({ library(shiny) library(httr) library(rjson) library(yaml) +library(shinyjs) +library(dplyr) +library(shinythemes) +library(shinydashboard) +library(stringr) +library(DT) +library(jsonlite) +library(reticulate) +library(ggplot2) +library(purrr) +library(plotly) +library(shinypop) +library(waiter) +library(readr) +library(sass) +}) # APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" diff --git a/server.R b/server.R index aab74e20..55758869 100644 --- a/server.R +++ b/server.R @@ -4,29 +4,10 @@ # pages to log into Synapse as the currently logged in user from the web portal # using the session token. https://www.synapse.org -library(shiny) -library(shinyjs) -library(dplyr) -library(shinythemes) -library(shinydashboard) -library(stringr) -library(DT) -library(jsonlite) -library(reticulate) -library(ggplot2) -library(purrr) -library(plotly) -library(shinypop) -library(waiter) -library(readr) - # Don't necessarily have to set `RETICULATE_PYTHON` env variable reticulate::use_condaenv("data_curator_env_oauth") shinyServer(function(input, output, session) { - ########### session global variables - source_python("python/synapse_func_alias.py") - source_python("python/metadata_model.py") params <- parseQueryString(isolate(session$clientData$url_search)) if (!has_auth_code(params)) { @@ -45,13 +26,15 @@ shinyServer(function(input, output, session) { token_response <- content(req, type = NULL) access_token <- token_response$access_token + ######## session global variables ######## + source_python("python/synapse_func_alias.py") + source_python("python/metadata_model.py") # import module that contains SynapseStorage class synapse_driver <- import("schematic.store.synapse")$SynapseStorage - - ### read config in - config <- jsonlite::fromJSON("www/config.json") - - ### logs in and gets list of projects they have access to + # read config in + config <- fromJSON("www/config.json") + + # logs in and gets list of projects they have access to synStore_obj <- NULL projects_namedList <- NULL @@ -66,27 +49,26 @@ shinyServer(function(input, output, session) { display_name <- config$manifest_schemas$display_name schema_to_display_lookup <- data.frame(schema_name, display_name) + tabs_list <- c("instructions", "data", "template", "upload") clean_tags <- c("text_div2", "tbl2", "gsheet_btn", "gsheet_div", "submitButton") - ############ - ### synapse cookies + ######## Initiate Login Process ######## + # synapse cookies session$sendCustomMessage(type = "readCookie", message = list()) - ### initial login front page items + # login page observeEvent(input$cookie, { - ## login and update session; otherwise, notify to login to Synapse first + # login and update session; otherwise, notify to login to Synapse first tryCatch( { - ### logs in syn_login(sessionToken = input$cookie, rememberMe = FALSE) - ### welcome message + # welcome message output$title <- renderUI({ titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) }) - ### updating global vars with values for projects synStore_obj <<- - ### synapse_driver(config$main_fileview, token = input$cookie) + # updating global vars with values for projects synStore_obj <<- synStore_obj <<- synapse_driver(token = input$cookie) # get_projects_list(synStore_obj) @@ -97,10 +79,10 @@ shinyServer(function(input, output, session) { projects_namedList[projects_list[[i]][[2]]] <<- projects_list[[i]][[1]] } - ### updates project dropdown + # updates project dropdown updateSelectizeInput(session, "var", choices = sort(names(projects_namedList))) - ### update waiter loading screen once login successful + # update waiter loading screen once login successful waiter_update(html = tagList( img(src = "synapse_logo.png", height = "120px"), h3(sprintf("Welcome, %s!", syn_getUserProfile()$userName)) @@ -124,12 +106,10 @@ shinyServer(function(input, output, session) { }) - ###### BUTTONS STUFF !!! remove last arrow + ######## Arrow Button ######## Previous_Button <- tags$div(actionButton("Prev_Tab", HTML("
"))) Next_Button <- div(actionButton("Next_Tab", HTML("
"))) - tabs_list <- c("instructions", "data", "template", "upload") - output$Next_Previous <- renderUI({ if (input[["tabs"]] == "upload") { # column(1,offset=1,Previous_Button) @@ -140,39 +120,33 @@ shinyServer(function(input, output, session) { } }) - observeEvent(input$Prev_Tab, { - tab_list <- list_tabs - current_tab <- which(tab_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tab_list[current_tab - 1]) - }) - - observeEvent(input$Next_Tab, { - tab_list <- list_tabs - current_tab <- which(tab_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tab_list[current_tab + 1]) - }) + lapply(c(-1, 1), function(i) { + tagID <- c("Next_Tab", "Prev_Tab")[i] + observeEvent(input[[tagID]], { + current_tab <- which(tabs_list == input[["tabs"]]) + updateTabItems(session, "tabs", selected = tabs_list[current_tab + i]) + }) + }) - ####### BUTTONS END - - ### lists folder datasets if exists in project + ######## Update Folder List ######## observeEvent(ignoreInit = TRUE, input$var, { output$folders <- renderUI({ # get synID of selected project project_synID <- projects_namedList[[input$var]] - ### gets folders per project + # gets folders per project folder_list <- synapse_driver$getStorageDatasetsInProject( synStore_obj, project_synID ) - folders_namedList <<- NULL # need to clean first + folders_namedList <<- NULL # need to clean first for (i in seq_along(folder_list)) { folders_namedList[folder_list[[i]][[2]]] <<- folder_list[[i]][[1]] } folderNames <- names(folders_namedList) - ### updates foldernames + # updates foldernames selectInput(inputId = "dataset", label = "Folder:", choices = folderNames) }) }) @@ -183,11 +157,11 @@ shinyServer(function(input, output, session) { folder_synID <<- folders_namedList[[input$dataset]] }) + ######## Update Template ######## output$manifest_display_name <- renderUI({ selectInput(inputId = "template_type", label = "Template:", choices = display_name) }) - - # update selected schema template name + # update selected schema template name observeEvent(input$dataset, { template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, @@ -196,6 +170,7 @@ shinyServer(function(input, output, session) { schema_name <<- as.character(template_type_df$schema_name) }) + # hide tags when users select new template observeEvent( { input$dataset @@ -212,8 +187,7 @@ shinyServer(function(input, output, session) { color = "rgba(66, 72, 116, .9)" ) - ### shows new metadata link when get gsheets template button pressed OR updates old - ### metadata if is exists + ######## Template Google Sheet Link ######## observeEvent(input$download, { manifest_w$show() @@ -222,13 +196,13 @@ shinyServer(function(input, output, session) { tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) }) } else { - ### checks if a manifest already exists + # checks if a manifest already exists existing_manifestID <- synapse_driver$getDatasetManifest( synStore_obj, folder_synID ) - ### if there isn't an existing manifest make a new one + # if there isn't an existing manifest make a new one if (existing_manifestID == "") { file_list <- synapse_driver$getFilesInStorageDataset( synStore_obj, @@ -244,13 +218,11 @@ shinyServer(function(input, output, session) { config$community, " ", input$template_type ), schema_name, filenames = as.list(filename_list)) - ### make sure not scalar if length of list is 1 in R add in the step to convert - ### names later ### + # make sure not scalar if length of list is 1 in R + # add in the step to convert names later } else { - ### if the manifest already exists + # if the manifest already exists manifest_entity <- syn_get(existing_manifestID) - # prepopulatedManifestURL = mm.populateModelManifest('test_update', entity.path, - # component) manifest_url <- metadata_model$populateModelManifest(paste0( config$community, " ", input$template_type @@ -262,15 +234,13 @@ shinyServer(function(input, output, session) { }) } - ## links shows in text box - show("text_div") - ### if want a progress bar need more feedback from API to know how to increment - ### progress bar ### + # links shows in text box + show("text_div") # TODO: add progress bar on (loading) screen manifest_w$hide() }) - ### renders fileInput ui + # renders fileInput ui output$fileInput_ui <- renderUI({ fileInput("file1", "Upload CSV File", accept = c( "text/csv", "text/comma-separated-values", @@ -278,14 +248,15 @@ shinyServer(function(input, output, session) { )) }) - ### reads csv file and previews + ######## Reads .csv File ######## rawData <- eventReactive(ignoreNULL = FALSE, input$file1, { - if (is.null(input$file1)) { + # if no file uploaded, return null + if (is.null(input$file1)) { return(NULL) - } # if no file uploaded, return null - infile <- readr::read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% - replace(., is.na(.), "") # change NA to blank to match schema output) - ### remove empty rows/columns where readr called it 'X'[digit] for unnamed col + } + infile <- read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% + replace(., is.na(.), "") # change NA to blank to match schema output) + # remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] }) @@ -294,9 +265,9 @@ shinyServer(function(input, output, session) { sapply(clean_tags, FUN = hide) }) - ### renders in DT for preview + # renders in DT for preview observeEvent(rawData(), { - output$tbl <- DT::renderDT({ + output$tbl <- renderDT({ datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE @@ -304,13 +275,13 @@ shinyServer(function(input, output, session) { }) }) - ## loading screen for validating metadata + # loading screen for validating metadata validate_w <- Waiter$new( html = tagList(spin_plus(), br(), h4("Validating...")), color = "rgba(66, 72, 116, .9)" ) - ### toggles validation status when validate button pressed + ######## Validation Section ####### observeEvent(input$validate, { validation_res <- NULL type_error <- NULL @@ -400,7 +371,7 @@ shinyServer(function(input, output, session) { # output error messages as data table show("tbl2") - output$tbl2 <- DT::renderDT({ + output$tbl2 <- renderDT({ datatable(errorDT, caption = "The errors are also highlighted in the preview table above.", rownames = FALSE, options = list( @@ -414,9 +385,8 @@ shinyServer(function(input, output, session) { validate_w$update(html = h3(waiter_msg)) - ### update DT view with incorrect values currently only one column, requires - ### backend support of multiple - output$tbl <- DT::renderDT({ + # highlight invalue cells in preview table + output$tbl <- renderDT({ if (length(inx_ws) > 0) { # if it is wrong schema error, highlight all cells datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% @@ -433,14 +403,14 @@ shinyServer(function(input, output, session) { show("gsheet_btn") } else { validation_res <- "valid" - ### show submit button + # show submit button output$submit <- renderUI({ actionButton("submitButton", "Submit to Synapse") }) } } - ### format output text + # validation messages output$text2 <- renderUI({ text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg" @@ -501,32 +471,32 @@ shinyServer(function(input, output, session) { gsheet_w$hide() }) - ## loading screen for submitting data + # loading screen for submitting data submit_w <- Waiter$new( html = tagList(img(src = "loading.gif"), h4("Submitting...")), color = "#424874" ) - ### submit button + ######## Submission Section ######## observeEvent(input$submitButton, { submit_w$show() # reads file csv again - infile <- readr::read_csv(input$file1$datapath, na = c("", "NA")) + infile <- read_csv(input$file1$datapath, na = c("", "NA")) - ### remove empty rows/columns where readr called it 'X'[digit] for unnamed col + # remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - ### IF an assay component selected (define assay components) note for future - the - ### type to filter (eg assay) on could probably also be a config choice + # IF an assay component selected (define assay components) note for future + # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates - ### with synapse files + # and adds entityID, saves it as synapse_storage_manifest.csv, then associates + # with synapse files if (input$template_type %in% assay_schemas) { - ### make into a csv or table for assay components already has entityId + # make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(infile)) { write.csv(infile, file = "./files/synapse_storage_manifest.csv", @@ -552,30 +522,30 @@ shinyServer(function(input, output, session) { ) } - ### associates metadata with data and returns manifest id + # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID ) print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) - ### if no error + # if no error if (startsWith(manifest_id, "syn") == TRUE) { nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") - ### clear inputs + # clear inputs sapply(clean_tags, FUN = hide) - ### rerenders fileinput UI + # rerenders fileinput UI output$fileInput_ui <- renderUI({ fileInput("file1", "Upload CSV File", accept = c( "text/csv", "text/comma-separated-values", ".csv" )) }) - ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix(0, + # renders empty df + output$tbl <- renderDT(datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0 )))) @@ -590,13 +560,13 @@ shinyServer(function(input, output, session) { rm("/tmp/synapse_storage_manifest.csv") } } else { - ## if not assay type tempalte + # if not assay type tempalte write.csv(infile, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) - ### associates metadata with data and returns manifest id + # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID @@ -604,23 +574,23 @@ shinyServer(function(input, output, session) { print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) - ### if uploaded provided valid synID message + # if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") - ### clear inputs + # clear inputs sapply(clean_tags, FUN = hide) - ### rerenders fileinput UI + # rerenders fileinput UI output$fileInput_ui <- renderUI({ fileInput("file1", "Upload CSV File", accept = c( "text/csv", "text/comma-separated-values", ".csv" )) }) - ### renders empty df - output$tbl <- DT::renderDT(datatable(as.data.frame(matrix(0, + # renders empty df + output$tbl <- renderDT(datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0 )))) diff --git a/ui.R b/ui.R index 206586da..176fcfbf 100644 --- a/ui.R +++ b/ui.R @@ -8,22 +8,6 @@ # # https://www.synapse.org -library(shiny) -library(shinyjs) -library(dplyr) -library(shinythemes) -library(shinydashboard) -library(stringr) -library(DT) -library(jsonlite) -library(reticulate) -library(ggplot2) -library(purrr) -library(plotly) -library(shinypop) -library(waiter) -library(sass) # read scss file - ui <- dashboardPage( skin = "purple", dashboardHeader( From fe2b1c13e6ee0852245746005dbe98bd8f2a544a Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 01:43:05 +0000 Subject: [PATCH 038/260] format 355fad5 --- global.R | 87 ++++++++++++++++++++++++++++---------------------------- server.R | 47 +++++++++++++++--------------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/global.R b/global.R index d380375b..58a7f17a 100644 --- a/global.R +++ b/global.R @@ -1,23 +1,23 @@ suppressPackageStartupMessages({ -library(shiny) -library(httr) -library(rjson) -library(yaml) -library(shinyjs) -library(dplyr) -library(shinythemes) -library(shinydashboard) -library(stringr) -library(DT) -library(jsonlite) -library(reticulate) -library(ggplot2) -library(purrr) -library(plotly) -library(shinypop) -library(waiter) -library(readr) -library(sass) + library(shiny) + library(httr) + library(rjson) + library(yaml) + library(shinyjs) + library(dplyr) + library(shinythemes) + library(shinydashboard) + library(stringr) + library(DT) + library(jsonlite) + library(reticulate) + library(ggplot2) + library(purrr) + library(plotly) + library(shinypop) + library(waiter) + library(readr) + library(sass) }) # APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" @@ -30,7 +30,7 @@ has_auth_code <- function(params) { return(!is.null(params$code)) } -oauth_client = yaml.load_file("config.yaml") +oauth_client <- yaml.load_file("config.yaml") client_id <- toString(oauth_client$client_id) client_secret <- oauth_client$client_secret @@ -40,34 +40,35 @@ if (is.null(client_secret)) stop("config.yaml is missing client_secret") if (is.null(APP_URL)) stop("config.yaml is missing client_secret") app <- oauth_app("shinysynapse", - key = client_id, - secret = client_secret, - redirect_uri = APP_URL) + key = client_id, + secret = client_secret, + redirect_uri = APP_URL +) # These are the user info details ('claims') requested from Synapse: -claims=list( - family_name=NULL, - given_name=NULL, - email=NULL, - email_verified=NULL, - userid=NULL, - orcid=NULL, - is_certified=NULL, - is_validated=NULL, - validated_given_name=NULL, - validated_family_name=NULL, - validated_location=NULL, - validated_email=NULL, - validated_company=NULL, - validated_at=NULL, - validated_orcid=NULL, - company=NULL +claims <- list( + family_name = NULL, + given_name = NULL, + email = NULL, + email_verified = NULL, + userid = NULL, + orcid = NULL, + is_certified = NULL, + is_validated = NULL, + validated_given_name = NULL, + validated_family_name = NULL, + validated_location = NULL, + validated_email = NULL, + validated_company = NULL, + validated_at = NULL, + validated_orcid = NULL, + company = NULL ) -claimsParam<-toJSON(list(id_token = claims, userinfo = claims)) +claimsParam <- toJSON(list(id_token = claims, userinfo = claims)) api <- oauth_endpoint( - authorize=paste0("https://signin.synapse.org?claims=", claimsParam), - access="https://repo-prod.prod.sagebase.org/auth/v1/oauth2/token" + authorize = paste0("https://signin.synapse.org?claims=", claimsParam), + access = "https://repo-prod.prod.sagebase.org/auth/v1/oauth2/token" ) # The 'openid' scope is required by the protocol for retrieving user information. diff --git a/server.R b/server.R index 55758869..6af29c28 100644 --- a/server.R +++ b/server.R @@ -8,7 +8,6 @@ reticulate::use_condaenv("data_curator_env_oauth") shinyServer(function(input, output, session) { - params <- parseQueryString(isolate(session$clientData$url_search)) if (!has_auth_code(params)) { return() @@ -31,9 +30,9 @@ shinyServer(function(input, output, session) { source_python("python/metadata_model.py") # import module that contains SynapseStorage class synapse_driver <- import("schematic.store.synapse")$SynapseStorage - # read config in - config <- fromJSON("www/config.json") - + # read config in + config <- fromJSON("www/config.json") + # logs in and gets list of projects they have access to synStore_obj <- NULL projects_namedList <- NULL @@ -49,11 +48,11 @@ shinyServer(function(input, output, session) { display_name <- config$manifest_schemas$display_name schema_to_display_lookup <- data.frame(schema_name, display_name) - tabs_list <- c("instructions", "data", "template", "upload") + tabs_list <- c("instructions", "data", "template", "upload") clean_tags <- c("text_div2", "tbl2", "gsheet_btn", "gsheet_div", "submitButton") - ######## Initiate Login Process ######## - # synapse cookies + ######## Initiate Login Process ######## + # synapse cookies session$sendCustomMessage(type = "readCookie", message = list()) # login page @@ -120,13 +119,13 @@ shinyServer(function(input, output, session) { } }) - lapply(c(-1, 1), function(i) { - tagID <- c("Next_Tab", "Prev_Tab")[i] - observeEvent(input[[tagID]], { - current_tab <- which(tabs_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tabs_list[current_tab + i]) - }) - }) + lapply(c(-1, 1), function(i) { + tagID <- c("Next_Tab", "Prev_Tab")[i] + observeEvent(input[[tagID]], { + current_tab <- which(tabs_list == input[["tabs"]]) + updateTabItems(session, "tabs", selected = tabs_list[current_tab + i]) + }) + }) ######## Update Folder List ######## observeEvent(ignoreInit = TRUE, input$var, { @@ -140,7 +139,7 @@ shinyServer(function(input, output, session) { project_synID ) - folders_namedList <<- NULL # need to clean first + folders_namedList <<- NULL # need to clean first for (i in seq_along(folder_list)) { folders_namedList[folder_list[[i]][[2]]] <<- folder_list[[i]][[1]] } @@ -157,11 +156,11 @@ shinyServer(function(input, output, session) { folder_synID <<- folders_namedList[[input$dataset]] }) - ######## Update Template ######## + ######## Update Template ######## output$manifest_display_name <- renderUI({ selectInput(inputId = "template_type", label = "Template:", choices = display_name) }) - # update selected schema template name + # update selected schema template name observeEvent(input$dataset, { template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, @@ -170,7 +169,7 @@ shinyServer(function(input, output, session) { schema_name <<- as.character(template_type_df$schema_name) }) - # hide tags when users select new template + # hide tags when users select new template observeEvent( { input$dataset @@ -218,8 +217,8 @@ shinyServer(function(input, output, session) { config$community, " ", input$template_type ), schema_name, filenames = as.list(filename_list)) - # make sure not scalar if length of list is 1 in R - # add in the step to convert names later + # make sure not scalar if length of list is 1 in R + # add in the step to convert names later } else { # if the manifest already exists manifest_entity <- syn_get(existing_manifestID) @@ -235,7 +234,7 @@ shinyServer(function(input, output, session) { } # links shows in text box - show("text_div") # TODO: add progress bar on (loading) screen + show("text_div") # TODO: add progress bar on (loading) screen manifest_w$hide() }) @@ -251,11 +250,11 @@ shinyServer(function(input, output, session) { ######## Reads .csv File ######## rawData <- eventReactive(ignoreNULL = FALSE, input$file1, { # if no file uploaded, return null - if (is.null(input$file1)) { + if (is.null(input$file1)) { return(NULL) } infile <- read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% - replace(., is.na(.), "") # change NA to blank to match schema output) + replace(., is.na(.), "") # change NA to blank to match schema output) # remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] @@ -488,7 +487,7 @@ shinyServer(function(input, output, session) { infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - # IF an assay component selected (define assay components) note for future + # IF an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] From dc88daf59c1db86c35f8d9848c6cba6f9ab04384 Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 02:15:06 +0000 Subject: [PATCH 039/260] rename selectors to more descriptive names --- server.R | 102 ++++++++++++++++----------------- ui.R | 42 +++++++------- www/scss/section/_content.scss | 2 +- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/server.R b/server.R index 6af29c28..ecfd2d95 100644 --- a/server.R +++ b/server.R @@ -44,12 +44,12 @@ shinyServer(function(input, output, session) { filename_list <- NULL ### mapping from display name to schema name - schema_name <- config$manifest_schemas$schema_name + template_name <- config$manifest_schemas$schema_name display_name <- config$manifest_schemas$display_name - schema_to_display_lookup <- data.frame(schema_name, display_name) + schema_to_display_lookup <- data.frame(template_name, display_name) - tabs_list <- c("instructions", "data", "template", "upload") - clean_tags <- c("text_div2", "tbl2", "gsheet_btn", "gsheet_div", "submitButton") + tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") + clean_tags <- c("div_validate", "tbl_validate", "btn_val_gsheet", "div_val_gsheet", "btn_submit") ######## Initiate Login Process ######## # synapse cookies @@ -79,7 +79,7 @@ shinyServer(function(input, output, session) { } # updates project dropdown - updateSelectizeInput(session, "var", choices = sort(names(projects_namedList))) + updateSelectizeInput(session, "dropdown_project", choices = sort(names(projects_namedList))) # update waiter loading screen once login successful waiter_update(html = tagList( @@ -110,9 +110,9 @@ shinyServer(function(input, output, session) { Next_Button <- div(actionButton("Next_Tab", HTML("
"))) output$Next_Previous <- renderUI({ - if (input[["tabs"]] == "upload") { + if (input[["tabs"]] == "tab_upload") { # column(1,offset=1,Previous_Button) - } else if (input[["tabs"]] == "instructions") { + } else if (input[["tabs"]] == "tab_instructions") { column(1, offset = 10, Next_Button) } else { div(column(1, offset = 1, Previous_Button), column(1, offset = 8, Next_Button)) @@ -128,10 +128,10 @@ shinyServer(function(input, output, session) { }) ######## Update Folder List ######## - observeEvent(ignoreInit = TRUE, input$var, { + observeEvent(ignoreInit = TRUE, input$dropdown_project, { output$folders <- renderUI({ # get synID of selected project - project_synID <- projects_namedList[[input$var]] + project_synID <- projects_namedList[[input$dropdown_project]] # gets folders per project folder_list <- synapse_driver$getStorageDatasetsInProject( @@ -146,14 +146,14 @@ shinyServer(function(input, output, session) { folderNames <- names(folders_namedList) # updates foldernames - selectInput(inputId = "dataset", label = "Folder:", choices = folderNames) + selectInput(inputId = "dropdown_folder", label = "Folder:", choices = folderNames) }) }) # update selected folder ID - observeEvent(input$dataset, { + observeEvent(input$dropdown_folder, { # TODO: check how different from using rectivateValues() - folder_synID <<- folders_namedList[[input$dataset]] + folder_synID <<- folders_namedList[[input$dropdown_folder]] }) ######## Update Template ######## @@ -161,22 +161,22 @@ shinyServer(function(input, output, session) { selectInput(inputId = "template_type", label = "Template:", choices = display_name) }) # update selected schema template name - observeEvent(input$dataset, { - template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), + observeEvent(input$dropdown_template, { + template_type_df <- schema_to_display_lookup[match(input$dropdown_template, schema_to_display_lookup$display_name), 1, drop = F ] - schema_name <<- as.character(template_type_df$schema_name) + template_name <<- as.character(template_type_df$schema_name) }) # hide tags when users select new template observeEvent( { - input$dataset - input$template_type + input$dropdown_folder + input$dropdown_template }, { - sapply(c("text_div", clean_tags), FUN = hide) + sapply(c("div_download", clean_tags), FUN = hide) } ) @@ -187,11 +187,11 @@ shinyServer(function(input, output, session) { ) ######## Template Google Sheet Link ######## - observeEvent(input$download, { + observeEvent(input$btn_download, { manifest_w$show() - if (is.null(input$template_type)) { - output$text <- renderUI({ + if (is.null(input$dropdown_template)) { + output$text_download <- renderUI({ tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) }) } else { @@ -215,8 +215,8 @@ shinyServer(function(input, output, session) { manifest_url <- metadata_model$getModelManifest(paste0( config$community, - " ", input$template_type - ), schema_name, filenames = as.list(filename_list)) + " ", input$dropdown_template + ), template_name, filenames = as.list(filename_list)) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { @@ -224,17 +224,17 @@ shinyServer(function(input, output, session) { manifest_entity <- syn_get(existing_manifestID) manifest_url <- metadata_model$populateModelManifest(paste0( config$community, - " ", input$template_type - ), manifest_entity$path, schema_name) + " ", input$temdropdown_templateplate_type + ), manifest_entity$path, template_name) } - output$text <- renderUI({ + output$text_download <- renderUI({ tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### }) } # links shows in text box - show("text_div") # TODO: add progress bar on (loading) screen + show("div_download") # TODO: add progress bar on (loading) screen manifest_w$hide() }) @@ -266,7 +266,7 @@ shinyServer(function(input, output, session) { # renders in DT for preview observeEvent(rawData(), { - output$tbl <- renderDT({ + output$tbl_preview <- renderDT({ datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE @@ -281,17 +281,17 @@ shinyServer(function(input, output, session) { ) ######## Validation Section ####### - observeEvent(input$validate, { + observeEvent(input$btn_validate, { validation_res <- NULL type_error <- NULL help_msg <- NULL validate_w$show() - if (!is.null(rawData()) & !is.null(input$template_type)) { + if (!is.null(rawData()) & !is.null(input$dropdown_template)) { annotation_status <- metadata_model$validateModelManifest( input$file1$datapath, - schema_name + template_name ) if (length(annotation_status) != 0) { @@ -327,12 +327,12 @@ shinyServer(function(input, output, session) { type_error <- paste0( "The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", - input$template_type, " >>." + input$dropdown_template, " >>." ) help_msg <- paste0( "Please check that you have selected the correct template in the Select your Dataset tab and ensure your metadata contains only one template, e.g. ", - input$template_type, "." + input$dropdown_template, "." ) # get wrong columns and values for updating preview table @@ -369,8 +369,8 @@ shinyServer(function(input, output, session) { errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))), ] # output error messages as data table - show("tbl2") - output$tbl2 <- renderDT({ + show("tbl_validate") + output$tbl_validate <- renderDT({ datatable(errorDT, caption = "The errors are also highlighted in the preview table above.", rownames = FALSE, options = list( @@ -385,7 +385,7 @@ shinyServer(function(input, output, session) { validate_w$update(html = h3(waiter_msg)) # highlight invalue cells in preview table - output$tbl <- renderDT({ + output$tbl_preview <- renderDT({ if (length(inx_ws) > 0) { # if it is wrong schema error, highlight all cells datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% @@ -399,24 +399,24 @@ shinyServer(function(input, output, session) { } }) - show("gsheet_btn") + show("btn_val_gsheet") } else { validation_res <- "valid" # show submit button output$submit <- renderUI({ - actionButton("submitButton", "Submit to Synapse") + actionButton("btn_submit", "Submit to Synapse") }) } } # validation messages - output$text2 <- renderUI({ + output$text_validate <- renderUI({ text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", "success_msg", "error_msg" ) tagList( - if (is.null(input$template_type)) { + if (is.null(input$dropdown_template)) { span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) }, if (is.null(rawData())) { @@ -436,7 +436,7 @@ shinyServer(function(input, output, session) { ) }) - show("text_div2") + show("div_validate") Sys.sleep(2.5) @@ -444,7 +444,7 @@ shinyServer(function(input, output, session) { }) # if user click gsheet_btn, generating gsheet - observeEvent(input$gsheet_btn, { + observeEvent(input$btn_val_gsheet, { # loading screen for Google link generation gsheet_w <- Waiter$new( html = tagList(spin_plus(), br(), h4("Generating link...")), @@ -455,17 +455,17 @@ shinyServer(function(input, output, session) { filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, - " ", input$template_type - ), input$file1$datapath, schema_name) + " ", input$dropdown_template + ), input$file1$datapath, template_name) - show("gsheet_div") + show("div_val_gsheet") - output$gsheet_link <- renderUI({ + output$text_val_gsheet <- renderUI({ # tags$a(href = filled_manifest, filled_manifest, target = '_blank') HTML(paste0("Edit on the Google Sheet.")) }) - hide("gsheet_btn") # hide btn once link generated + hide("btn_val_gsheet") # hide btn once link generated gsheet_w$hide() }) @@ -477,7 +477,7 @@ shinyServer(function(input, output, session) { ) ######## Submission Section ######## - observeEvent(input$submitButton, { + observeEvent(input$btn_submit, { submit_w$show() # reads file csv again @@ -494,7 +494,7 @@ shinyServer(function(input, output, session) { # and adds entityID, saves it as synapse_storage_manifest.csv, then associates # with synapse files - if (input$template_type %in% assay_schemas) { + if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(infile)) { write.csv(infile, @@ -544,7 +544,7 @@ shinyServer(function(input, output, session) { )) }) # renders empty df - output$tbl <- renderDT(datatable(as.data.frame(matrix(0, + output$tbl_preview <- renderDT(datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0 )))) @@ -589,7 +589,7 @@ shinyServer(function(input, output, session) { )) }) # renders empty df - output$tbl <- renderDT(datatable(as.data.frame(matrix(0, + output$tbl_preview <- renderDT(datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0 )))) diff --git a/ui.R b/ui.R index 176fcfbf..44ab6938 100644 --- a/ui.R +++ b/ui.R @@ -32,22 +32,22 @@ ui <- dashboardPage( id = "tabs", menuItem( "Instructions", - tabName = "instructions", + tabName = "tab_instructions", icon = icon("book-open") ), menuItem( "Select your Dataset", - tabName = "data", + tabName = "tab_data", icon = icon("mouse-pointer") ), menuItem( "Get Metadata Template", - tabName = "template", + tabName = "tab_template", icon = icon("table") ), menuItem( "Submit & Validate Metadata", - tabName = "upload", + tabName = "tab_upload", icon = icon("upload") ), HTML( @@ -71,7 +71,7 @@ ui <- dashboardPage( tabItems( # First tab content tabItem( - tabName = "instructions", + tabName = "tab_instructions", h2("Instructions for the Data Curator App:"), h3( "1. Go to", @@ -91,7 +91,7 @@ ui <- dashboardPage( ), # second tab content tabItem( - tabName = "data", + tabName = "tab_data", h2("Set Dataset and Metadata Template for Curation"), fluidRow( box( @@ -100,7 +100,7 @@ ui <- dashboardPage( width = 6, title = "Choose a Project and Folder: ", selectizeInput( - inputId = "var", + inputId = "dropdown_project", label = "Project:", choices = "Generating..." ), @@ -120,7 +120,7 @@ ui <- dashboardPage( ), # Third tab item tabItem( - tabName = "template", + tabName = "tab_template", useShinyjs(), h2("Download Template for Selected Folder"), fluidRow( @@ -129,12 +129,12 @@ ui <- dashboardPage( status = "primary", solidHeader = TRUE, width = 12, - actionButton("download", "Click to Generate Google Sheets Template"), + actionButton("btn_download", "Click to Generate Google Sheets Template"), hidden( div( - id = "text_div", + id = "div_download", height = "100%", - htmlOutput("text") + htmlOutput("text_download") ) ), helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") @@ -143,7 +143,7 @@ ui <- dashboardPage( ), # Fourth tab content tabItem( - tabName = "upload", + tabName = "tab_upload", h2("Submit & Validate a Filled Metadata Template"), fluidRow( box( @@ -158,26 +158,26 @@ ui <- dashboardPage( solidHeader = TRUE, status = "primary", width = 12, - DT::DTOutput("tbl") + DT::DTOutput("tbl_preview") ), box( title = "Validate Filled Metadata", status = "primary", solidHeader = TRUE, width = 12, - actionButton("validate", "Validate Metadata"), + actionButton("btn_validate", "Validate Metadata"), hidden( div( - id = "text_div2", + id = "div_validate", height = "100%", - htmlOutput("text2") + htmlOutput("text_validate") ), - DT::DTOutput("tbl2"), - actionButton("gsheet_btn", " Click to Generate Google Sheet Link", icon = icon("table")), + DT::DTOutput("tbl_validate"), + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")), div( - id = "gsheet_div", + id = "div_val_gsheet", height = "100%", - htmlOutput("gsheet_link") + htmlOutput("text_val_gsheet") ) ), helpText( @@ -190,7 +190,7 @@ ui <- dashboardPage( status = "primary", solidHeader = TRUE, width = 12, - uiOutput("submit") + uiOutput("btn_submit") ) ) ) diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 7b330116..4fa62e4e 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -1,5 +1,5 @@ // specify div -#text_div, #text_div2, #gsheet_div { +#div_download, #div_validate, #div_val_gsheet { font-size: 18px; background-color: white; margin: 10px 0; From b10dc1b30383b82c05f9ab8f2965f68a3f4ae06a Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 02:17:07 +0000 Subject: [PATCH 040/260] format .Rprofile --- .Rprofile | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.Rprofile b/.Rprofile index 175d5f03..407da0f4 100644 --- a/.Rprofile +++ b/.Rprofile @@ -1,12 +1,11 @@ .First <- function() { - options( - repos = c( - CRAN = "https://cran.rstudio.com/", - Sage = "http://ran.synapse.org" - ) - ) + options( + repos = c( + CRAN = "https://cran.rstudio.com/", + Sage = "http://ran.synapse.org" + ) + ) } -options(stringsAsFactors=FALSE) +options(stringsAsFactors = FALSE) source("renv/activate.R") - From 611e6949d390477ca05cc0374254a6519110639e Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 08:56:22 +0000 Subject: [PATCH 041/260] create module for next/previous button --- global.R | 4 ++++ server.R | 21 ++------------------- ui.R | 13 ++++++++----- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/global.R b/global.R index 58a7f17a..d331c40e 100644 --- a/global.R +++ b/global.R @@ -73,3 +73,7 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" + +# Import modules +source.files <- list.files("modules", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) +sapply(ource.files, FUN=source) \ No newline at end of file diff --git a/server.R b/server.R index ecfd2d95..9a532624 100644 --- a/server.R +++ b/server.R @@ -106,25 +106,8 @@ shinyServer(function(input, output, session) { ######## Arrow Button ######## - Previous_Button <- tags$div(actionButton("Prev_Tab", HTML("
"))) - Next_Button <- div(actionButton("Next_Tab", HTML("
"))) - - output$Next_Previous <- renderUI({ - if (input[["tabs"]] == "tab_upload") { - # column(1,offset=1,Previous_Button) - } else if (input[["tabs"]] == "tab_instructions") { - column(1, offset = 10, Next_Button) - } else { - div(column(1, offset = 1, Previous_Button), column(1, offset = 8, Next_Button)) - } - }) - - lapply(c(-1, 1), function(i) { - tagID <- c("Next_Tab", "Prev_Tab")[i] - observeEvent(input[[tagID]], { - current_tab <- which(tabs_list == input[["tabs"]]) - updateTabItems(session, "tabs", selected = tabs_list[current_tab + i]) - }) + lapply(1:3, function(i) { + switchTabServer(id = paste0("Next_Previous", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) }) ######## Update Folder List ######## diff --git a/ui.R b/ui.R index 44ab6938..6fc92a4e 100644 --- a/ui.R +++ b/ui.R @@ -87,7 +87,8 @@ ui <- dashboardPage( "3. Go to", strong("Submit and Validate Metadata"), "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata." - ) + ), + switchTabUI("switch-instructions", direction = "right") ), # second tab content tabItem( @@ -116,7 +117,8 @@ ui <- dashboardPage( title = "Choose a Metadata Template Type: ", uiOutput("manifest_display_name") ) - ) + ), + switchTabUI("switch-data", direction = "both") ), # Third tab item tabItem( @@ -139,7 +141,8 @@ ui <- dashboardPage( ), helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") ) - ) + ), + switchTabUI("switch-tab_template", direction = "both") ), # Fourth tab content tabItem( @@ -195,8 +198,8 @@ ui <- dashboardPage( ) ) ), - uiOutput("Next_Previous"), - + # uiOutput("Next_Previous"), + # switchPageUI("Next_Previous"), ## waiter loading screen use_waiter(), waiter_show_on_load( From d361aaf8bc6a62cf3fca6bb782b258430470722e Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 11:09:46 +0000 Subject: [PATCH 042/260] wrap up waiter screens --- global.R | 6 ++-- server.R | 100 ++++++++++++++++--------------------------------------- ui.R | 20 ++++------- 3 files changed, 38 insertions(+), 88 deletions(-) diff --git a/global.R b/global.R index d331c40e..f175aa4c 100644 --- a/global.R +++ b/global.R @@ -74,6 +74,6 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" -# Import modules -source.files <- list.files("modules", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) -sapply(ource.files, FUN=source) \ No newline at end of file +# Import functions/modules +source.files <- list.files("functions", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) +sapply(source.files, FUN=source) \ No newline at end of file diff --git a/server.R b/server.R index 9a532624..3484ef81 100644 --- a/server.R +++ b/server.R @@ -40,13 +40,13 @@ shinyServer(function(input, output, session) { folders_namedList <- NULL folder_synID <- NULL # selected foler synapse ID - schema_name <- NULL # selected template schema name + template_name <- NULL # selected template schema name filename_list <- NULL ### mapping from display name to schema name - template_name <- config$manifest_schemas$schema_name + schema_name <- config$manifest_schemas$schema_name display_name <- config$manifest_schemas$display_name - schema_to_display_lookup <- data.frame(template_name, display_name) + schema_to_display_lookup <- data.frame(schema_name, display_name) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") clean_tags <- c("div_validate", "tbl_validate", "btn_val_gsheet", "div_val_gsheet", "btn_submit") @@ -82,24 +82,10 @@ shinyServer(function(input, output, session) { updateSelectizeInput(session, "dropdown_project", choices = sort(names(projects_namedList))) # update waiter loading screen once login successful - waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), - h3(sprintf("Welcome, %s!", syn_getUserProfile()$userName)) - )) - Sys.sleep(2) - waiter_hide() + dc_waiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) }, error = function(err) { - Sys.sleep(2) - waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), span( - "Please ", a("login", - href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" - ), - " to Synapse, then refresh this page." - ) - )) + dc_waiter("update", isLogin = TRUE, isPass = FALSE) } ) }) @@ -107,7 +93,7 @@ shinyServer(function(input, output, session) { ######## Arrow Button ######## lapply(1:3, function(i) { - switchTabServer(id = paste0("Next_Previous", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) + switchTabServer(id = paste0("switchTab", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) }) ######## Update Folder List ######## @@ -141,7 +127,7 @@ shinyServer(function(input, output, session) { ######## Update Template ######## output$manifest_display_name <- renderUI({ - selectInput(inputId = "template_type", label = "Template:", choices = display_name) + selectInput(inputId = "dropdown_template", label = "Template:", choices = display_name) }) # update selected schema template name observeEvent(input$dropdown_template, { @@ -163,15 +149,11 @@ shinyServer(function(input, output, session) { } ) - # loading screen for template link generation - manifest_w <- Waiter$new( - html = tagList(spin_plus(), br(), h4("Generating link...")), - color = "rgba(66, 72, 116, .9)" - ) - ######## Template Google Sheet Link ######## observeEvent(input$btn_download, { - manifest_w$show() + + # loading screen for template link generation + dc_waiter("show", msg="Generating link...") if (is.null(input$dropdown_template)) { output$text_download <- renderUI({ @@ -216,10 +198,10 @@ shinyServer(function(input, output, session) { }) } - # links shows in text box - show("div_download") # TODO: add progress bar on (loading) screen + dc_waiter("hide", sleep = 1) + # display link + show("div_download") # TODO: add progress bar on (loading) screen - manifest_w$hide() }) # renders fileInput ui @@ -257,20 +239,15 @@ shinyServer(function(input, output, session) { }) }) - # loading screen for validating metadata - validate_w <- Waiter$new( - html = tagList(spin_plus(), br(), h4("Validating...")), - color = "rgba(66, 72, 116, .9)" - ) - ######## Validation Section ####### observeEvent(input$btn_validate, { + # loading screen for validating metadata + dc_waiter("show", msg = "Validating...") + validation_res <- NULL type_error <- NULL help_msg <- NULL - validate_w$show() - if (!is.null(rawData()) & !is.null(input$dropdown_template)) { annotation_status <- metadata_model$validateModelManifest( input$file1$datapath, @@ -365,8 +342,6 @@ shinyServer(function(input, output, session) { }) } - validate_w$update(html = h3(waiter_msg)) - # highlight invalue cells in preview table output$tbl_preview <- renderDT({ if (length(inx_ws) > 0) { @@ -382,6 +357,11 @@ shinyServer(function(input, output, session) { } }) + # validate_w$update(html = h3(waiter_msg)) + # TODO: fix issue: + # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 + dc_waiter("update", msg = waiter_msg, sleep = 2.5) + show("btn_val_gsheet") } else { validation_res <- "valid" @@ -420,21 +400,12 @@ shinyServer(function(input, output, session) { }) show("div_validate") - - Sys.sleep(2.5) - - validate_w$hide() }) # if user click gsheet_btn, generating gsheet observeEvent(input$btn_val_gsheet, { # loading screen for Google link generation - gsheet_w <- Waiter$new( - html = tagList(spin_plus(), br(), h4("Generating link...")), - color = "rgba(66, 72, 116, .9)" - ) - - gsheet_w$show() + dc_waiter("show", msg = "Generating link...") filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, @@ -450,18 +421,14 @@ shinyServer(function(input, output, session) { hide("btn_val_gsheet") # hide btn once link generated - gsheet_w$hide() + dc_waiter("hide") }) - # loading screen for submitting data - submit_w <- Waiter$new( - html = tagList(img(src = "loading.gif"), h4("Submitting...")), - color = "#424874" - ) ######## Submission Section ######## observeEvent(input$btn_submit, { - submit_w$show() + # loading screen for submitting data + dc_waiter("show", msg = "Submitting...") # reads file csv again infile <- read_csv(input$file1$datapath, na = c("", "NA")) @@ -532,13 +499,11 @@ shinyServer(function(input, output, session) { nrow = 0 )))) } else { - submit_w$update(html = tagList( - img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), span( + dc_waiter("update", msg= HTML(paste0("Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" ) - )) + ), sleep = 3) rm("/tmp/synapse_storage_manifest.csv") } } else { @@ -577,17 +542,10 @@ shinyServer(function(input, output, session) { nrow = 0 )))) } else { - submit_w$update(html = tagList( - img(src = "synapse_logo.png", height = "115px"), - h3("Uh oh, looks like something went wrong!"), span( - manifest_id, - " is not a valid Synapse ID. Try again?" - ) - )) + dc_waiter("update", msg= HTML(paste0("Uh oh, looks like something went wrong!", + manifest_id, " is not a valid Synapse ID. Try again?")), sleep = 3) rm("/tmp/synapse_storage_manifest.csv") } } - Sys.sleep(3) - submit_w$hide() }) }) diff --git a/ui.R b/ui.R index 6fc92a4e..37d3b814 100644 --- a/ui.R +++ b/ui.R @@ -68,6 +68,7 @@ ui <- dashboardPage( ), uiOutput("title"), use_notiflix_report(), + use_waiter(), tabItems( # First tab content tabItem( @@ -88,7 +89,7 @@ ui <- dashboardPage( strong("Submit and Validate Metadata"), "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata." ), - switchTabUI("switch-instructions", direction = "right") + switchTabUI("switchTab1", direction = "right") ), # second tab content tabItem( @@ -118,7 +119,7 @@ ui <- dashboardPage( uiOutput("manifest_display_name") ) ), - switchTabUI("switch-data", direction = "both") + switchTabUI("switchTab2", direction = "both") ), # Third tab item tabItem( @@ -142,7 +143,7 @@ ui <- dashboardPage( helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") ) ), - switchTabUI("switch-tab_template", direction = "both") + switchTabUI("switchTab3", direction = "both") ), # Fourth tab content tabItem( @@ -198,17 +199,8 @@ ui <- dashboardPage( ) ) ), - # uiOutput("Next_Previous"), - # switchPageUI("Next_Previous"), - ## waiter loading screen - use_waiter(), - waiter_show_on_load( - html = tagList( - img(src = "loading.gif"), - h4("Retrieving Synapse information...") - ), - color = "#424874" - ) + # waiter loading screen + dc_waiter("show", isLogin = TRUE) ) ) From 74d391cbae3b179edf892dfe275ec58c87ad0d18 Mon Sep 17 00:00:00 2001 From: rrchai Date: Sun, 9 May 2021 20:56:52 +0000 Subject: [PATCH 043/260] add modules; create modules for reading csv file --- global.R | 2 +- modules/dc_waiter.R | 61 ++++++++++++++++++++++++++++ modules/read_csvFile.R | 47 ++++++++++++++++++++++ modules/switch_tabs.R | 42 ++++++++++++++++++++ server.R | 90 +++++++++++++++++------------------------- ui.R | 2 +- 6 files changed, 189 insertions(+), 55 deletions(-) create mode 100644 modules/dc_waiter.R create mode 100644 modules/read_csvFile.R create mode 100644 modules/switch_tabs.R diff --git a/global.R b/global.R index f175aa4c..fa4048af 100644 --- a/global.R +++ b/global.R @@ -75,5 +75,5 @@ api <- oauth_endpoint( scope <- "openid view download modify" # Import functions/modules -source.files <- list.files("functions", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) +source.files <- list.files("modules", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source.files, FUN=source) \ No newline at end of file diff --git a/modules/dc_waiter.R b/modules/dc_waiter.R new file mode 100644 index 00000000..b325eb07 --- /dev/null +++ b/modules/dc_waiter.R @@ -0,0 +1,61 @@ +# This is script to wrap up the waiter screen for data curator app +# TODO: maybe we could split into UI and server if we need + +dc_waiter <- function(stage=c("show", "update", "hide"), + isLogin=FALSE, isPass=TRUE, usrName = NULL, + sleep=2, msg=NULL) { + # validate arguments + if(!is.logical(isLogin)) stop("isLogin must be a boolean") + if(!is.logical(isPass)) stop("isPass must be a boolean") + if(!is.numeric(sleep)) stop("sleep must be a numeric") + if (!stage %in% c("show", "update", "hide")) { + stop("Please provide a value for stage: 'show', 'update' or 'hide'.") + } + + # if "hide", proceed hiding process immediately and exit function + if (stage == "hide") { + Sys.sleep(sleep) + return(waiter_hide()) + } + + # log in screen + if (isLogin) { + # The message on initial loading page are not customizable + if (!is.null(msg)) message("message for log in screen can be changed in dc_waiter.R") + + if (stage == "show") { + waiter_show_on_load( + html = tagList( + img(src = "loading.gif"), + h4("Retrieving Synapse information...") + ), + color = "#424874" + ) + } else if (isPass) { + waiter_update(html = tagList(img(src = "synapse_logo.png", height = "120px"), + h3(sprintf("Welcome, %s!", usrName)))) + Sys.sleep(sleep) + waiter_hide() + } else { + # ensure the synapse logo image is stored in www/ + waiter_update(html = tagList(img(src = "synapse_logo.png", height = "120px"), + h3("Looks like you're not logged in!"), span("Please ", a("login", + href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), + " to Synapse, then refresh this page."))) + } + } else { + # other loading screens + if (is.null(msg)) msg <- "Loading ..." + + if (stage == "show") { + waiter_show(html = tagList(spin_plus(), br(), h3(msg)), + color = "rgba(66, 72, 116, .9)") + } else { + Sys.sleep(2) # has to put at least 2s before to make update work + waiter_update(html = tagList(spin_loaders(32), br(), h3(msg))) + Sys.sleep(sleep) + waiter_hide() + } + } + +} \ No newline at end of file diff --git a/modules/read_csvFile.R b/modules/read_csvFile.R new file mode 100644 index 00000000..1cc12b24 --- /dev/null +++ b/modules/read_csvFile.R @@ -0,0 +1,47 @@ +# This module is to read csv file + +csvInfileUI <- function(id) { + ns <- NS(id) + tagList( + # renders fileInput ui + fileInput(ns("file"), "Upload CSV File", accept = c( + "text/csv", "text/comma-separated-values", + ".csv" + )) + ) +} + +csvInfileServer <- function(id, na = c("", "NA"), colsAsCharacters = FALSE, keepBlank = FALSE) { + moduleServer( + id, + function(input, output, session) { + usrFile <- eventReactive(ignoreNULL = FALSE, input$file, { + # if no file uploaded, return null + if (is.null(input$file)) { + return(NULL) + } + + if (colsAsCharacters) { + infile <- read_csv(input$file$datapath, na = na, col_types = cols(.default = "c")) + } else { + infile <- read_csv(input$file$datapath, na = na) + } + + if (keepBlank) { + # change NA to blank to match schema output) + infile <- infile %>% replace(., is.na(.), "") + } + + # remove empty rows/columns where readr called it 'X'[digit] for unnamed col + infile <- infile[, !grepl("^X", colnames(infile))] + infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + }) + return(list( + raw = reactive({ + input$file + }), + data = usrFile + )) + } + ) +} diff --git a/modules/switch_tabs.R b/modules/switch_tabs.R new file mode 100644 index 00000000..85c3a382 --- /dev/null +++ b/modules/switch_tabs.R @@ -0,0 +1,42 @@ +# This is the module to create one/two buttons to switch to previous/next tab +# TODO: Add more descriptions + +tagID <- c("Next", "Prev") # Do not change order, to ensure server works properly + +switchTabUI <- function(id, direction = c("left", "right", "both")) { + + # namespace + ns <- NS(id) + # if we put buttons in server, buttons will change after observing tabs' change delay + # which cause some add-remove tranisition in delay + # now, put buttons in UI + btn_prev <- actionButton(ns(tagID[2]), HTML("
"), style = "margin-top: 20px;") + btn_next <- actionButton(ns(tagID[1]), HTML("
"), style = "margin-top: 20px;") + fluidRow( + if (direction == "right") { + column(1, offset = 10, btn_next) + } else if (direction == "left") { + column(1, offset = 1, btn_prev) + } else { + div(column(1, offset = 1, btn_prev), column(1, offset = 8, btn_next)) + } + ) +} + + +switchTabServer <- function(id, tabId, tab, tabList, parent) { + moduleServer( + id, + function(input, output, session) { + lapply(c(-1, 1), function(i) { + tagName <- tagID[i] + observeEvent(input[[tagName]], { + current_tab <- which(tabList == tab) + # need to use parent session to update tab + # TODO: figure out how to call parent inputs in module to minimize args + updateTabItems(parent, tabId, selected = tabList[current_tab + i]) + }) + }) + } + ) +} diff --git a/server.R b/server.R index 3484ef81..338e4b53 100644 --- a/server.R +++ b/server.R @@ -153,7 +153,7 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_download, { # loading screen for template link generation - dc_waiter("show", msg="Generating link...") + dc_waiter("show", msg = "Generating link...") if (is.null(input$dropdown_template)) { output$text_download <- renderUI({ @@ -200,39 +200,19 @@ shinyServer(function(input, output, session) { dc_waiter("hide", sleep = 1) # display link - show("div_download") # TODO: add progress bar on (loading) screen - + show("div_download") # TODO: add progress bar on (loading) screen }) - # renders fileInput ui - output$fileInput_ui <- renderUI({ - fileInput("file1", "Upload CSV File", accept = c( - "text/csv", "text/comma-separated-values", - ".csv" - )) - }) ######## Reads .csv File ######## - rawData <- eventReactive(ignoreNULL = FALSE, input$file1, { - # if no file uploaded, return null - if (is.null(input$file1)) { - return(NULL) - } - infile <- read_csv(input$file1$datapath, na = c("", "NA"), col_types = readr::cols(.default = "c")) %>% - replace(., is.na(.), "") # change NA to blank to match schema output) - # remove empty rows/columns where readr called it 'X'[digit] for unnamed col - infile <- infile[, !grepl("^X", colnames(infile))] - infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - }) - - observeEvent(input$file1, { - sapply(clean_tags, FUN = hide) - }) + inFile <- csvInfileServer("inputFile", colsAsCharacters = TRUE, keepBlank = TRUE) # renders in DT for preview - observeEvent(rawData(), { + observeEvent(inFile$data(), { + # hide the validation section when upload a new file + sapply(clean_tags, FUN = hide) output$tbl_preview <- renderDT({ - datatable(rawData(), + datatable(inFile$data(), options = list(lengthChange = FALSE, scrollX = TRUE), rownames = FALSE ) @@ -243,14 +223,13 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_validate, { # loading screen for validating metadata dc_waiter("show", msg = "Validating...") - validation_res <- NULL type_error <- NULL help_msg <- NULL - if (!is.null(rawData()) & !is.null(input$dropdown_template)) { + if (!is.null(inFile$data()) & !is.null(input$dropdown_template)) { annotation_status <- metadata_model$validateModelManifest( - input$file1$datapath, + inFile$raw()$datapath, template_name ) @@ -326,7 +305,7 @@ shinyServer(function(input, output, session) { ) ) # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))), ] + errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile$data()))), ] # output error messages as data table show("tbl_validate") @@ -346,10 +325,10 @@ shinyServer(function(input, output, session) { output$tbl_preview <- renderDT({ if (length(inx_ws) > 0) { # if it is wrong schema error, highlight all cells - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% + datatable(inFile$data(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% formatStyle(1, target = "row", backgroundColor = "yellow") } else { - datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% + datatable(inFile$data(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% formatStyle(errorDT$Column, backgroundColor = styleEqual( errorDT$Value, rep("yellow", length(errorDT$Value)) @@ -382,7 +361,7 @@ shinyServer(function(input, output, session) { if (is.null(input$dropdown_template)) { span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) }, - if (is.null(rawData())) { + if (is.null(inFile$data())) { span(class = text_class, HTML("Please upload a filled template !")) }, if (!is.null(validation_res)) { @@ -410,7 +389,7 @@ shinyServer(function(input, output, session) { filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, " ", input$dropdown_template - ), input$file1$datapath, template_name) + ), inFile$datapath, template_name) show("div_val_gsheet") @@ -431,11 +410,7 @@ shinyServer(function(input, output, session) { dc_waiter("show", msg = "Submitting...") # reads file csv again - infile <- read_csv(input$file1$datapath, na = c("", "NA")) - - # remove empty rows/columns where readr called it 'X'[digit] for unnamed col - infile <- infile[, !grepl("^X", colnames(infile))] - infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + inFile <- csvInfileServer("inputFile") # IF an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice @@ -483,27 +458,34 @@ shinyServer(function(input, output, session) { nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") + # TODO: + # we could either hide or restart everything + # wait until testing on submit functions + # clear inputs sapply(clean_tags, FUN = hide) + # TODO: consider removing this chunk, + # could change to reset('inFile') if reset works # rerenders fileinput UI - output$fileInput_ui <- renderUI({ - fileInput("file1", "Upload CSV File", accept = c( - "text/csv", "text/comma-separated-values", - ".csv" - )) - }) + # output$fileInput_ui <- renderUI({ + # fileInput("file1", "Upload CSV File", accept = c( + # "text/csv", "text/comma-separated-values", + # ".csv" + # )) + # }) + # renders empty df output$tbl_preview <- renderDT(datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0 )))) } else { - dc_waiter("update", msg= HTML(paste0("Uh oh, looks like something went wrong!", - manifest_id, - " is not a valid Synapse ID. Try again?" - ) - ), sleep = 3) + dc_waiter("update", msg = HTML(paste0( + "Uh oh, looks like something went wrong!", + manifest_id, + " is not a valid Synapse ID. Try again?" + )), sleep = 3) rm("/tmp/synapse_storage_manifest.csv") } } else { @@ -542,8 +524,10 @@ shinyServer(function(input, output, session) { nrow = 0 )))) } else { - dc_waiter("update", msg= HTML(paste0("Uh oh, looks like something went wrong!", - manifest_id, " is not a valid Synapse ID. Try again?")), sleep = 3) + dc_waiter("update", msg = HTML(paste0( + "Uh oh, looks like something went wrong!", + manifest_id, " is not a valid Synapse ID. Try again?" + )), sleep = 3) rm("/tmp/synapse_storage_manifest.csv") } } diff --git a/ui.R b/ui.R index 37d3b814..4a89ac78 100644 --- a/ui.R +++ b/ui.R @@ -155,7 +155,7 @@ ui <- dashboardPage( solidHeader = TRUE, status = "primary", width = 12, - uiOutput("fileInput_ui") + csvInfileUI("inputFile") ), box( title = "Metadata Preview", From 86ed98f838f1ea2838aa23cf00221cc8f0827a25 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 10 May 2021 15:26:54 +0000 Subject: [PATCH 044/260] create modules for validation and renderTable & collect validation contents in one div --- modules/render_table.R | 43 +++++++++ modules/validation.R | 133 ++++++++++++++++++++++++++ server.R | 211 +++++++++-------------------------------- ui.R | 14 ++- 4 files changed, 228 insertions(+), 173 deletions(-) create mode 100644 modules/render_table.R create mode 100644 modules/validation.R diff --git a/modules/render_table.R b/modules/render_table.R new file mode 100644 index 00000000..0acf7f50 --- /dev/null +++ b/modules/render_table.R @@ -0,0 +1,43 @@ +# This moduel is to peformrender DT table function for preview/highlight + +DTableUI <- function(id) { + ns <- NS(id) + DT::DTOutput(ns("table")) +} + +DTableServer <- function(id, data, + rownames = FALSE, caption = NULL, + options = list(lengthChange = FALSE, scrollX = TRUE), + highlight = NULL, hightlight.col = NULL, hightlight.value = NULL) { + if (!is.null(highlight)) { + if (!highlight %in% c("full", "partial")) { + Stop("Please choose a value for highlight: 'full', 'partial'.") + } + + column <- hightlight.col + value <- hightlight.value + } + + df <- datatable(data, + caption = caption, + rownames = rownames, + options = options + ) + if (!is.null(highlight)) { + if (highlight == "full") { + df <- df %>% + formatStyle(1, target = "row", backgroundColor = "yellow") + } else if (highlight == "partial") { + df <- df %>% + formatStyle(column, backgroundColor = styleEqual( + value, rep("yellow", length(value)) + )) + } + } + moduleServer( + id, + function(input, output, session) { + output$table <- renderDT(df) + } + ) +} diff --git a/modules/validation.R b/modules/validation.R new file mode 100644 index 00000000..bc445f11 --- /dev/null +++ b/modules/validation.R @@ -0,0 +1,133 @@ + +# format and process validation results from schematic + +validationResult <- function(valRes, template, inFile) { + validation_res <- NULL + error_msg <- NULL + help_msg <- NULL + errorDT <- NULL + waiter_msg <- NULL + errorType <- NULL + + if (!is.null(inFile) & !is.null(template)) { + if (length(valRes) != 0) { + validation_res <- "invalid" + # mismatched template index + inx_mt <- which(sapply(valRes, function(x) { + grepl( + "Component value provided is: .*, whereas the Template Type is: .*", + x[[3]] + ) + })) + # missing column index + inx_ws <- which(sapply(valRes, function(x) { + grepl( + "Wrong schema", + x[[2]] + ) + })) + + if (length(inx_mt) > 0) { + # mismatched error(s): selected template mismatched with validating template + waiter_msg <- "Mismatched Template Found !" + # get all mismatched components + error_values <- sapply(valRes[inx_mt], function(x) x[[4]][[1]]) %>% + unique() + + # error messages for mismatch + mismatch_c <- error_values %>% + sQuote() %>% + paste(collapse = ", ") + error_msg <- paste0( + "The submitted metadata contains << ", + mismatch_c, " >> in the Component column, but requested validation for << ", + template, " >>." + ) + help_msg <- paste0( + "Please check that you have selected the correct template in the Select your Dataset tab and + ensure your metadata contains only one template, e.g. ", + template, "." + ) + + # get wrong columns and values for updating preview table + errorDT <- data.frame( + Column = sapply(valRes[inx_mt], function(i) i[[2]]), + Value = sapply(valRes[inx_mt], function(i) i[[4]][[1]]), + Error = "" + ) + } else if (length(inx_ws) > 0) { + # wrong schema error(s): validating metadata miss any required columns + waiter_msg <- "Wrong Schema Used !" + error_msg <- "The submitted metadata does not contain all required column(s)." + help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and + ensure your metadata contains all required columns." + } else { + waiter_msg <- sprintf("%d errors found", length(valRes)) + error_msg <- paste0( + "The submitted metadata have ", length(valRes), + " errors." + ) + + errorDT <- data.frame( + Column = sapply(valRes, function(i) i[[2]]), + Value = sapply(valRes, function(i) i[[4]][[1]]), + Error = sapply(valRes, function(i) i[[3]]) + ) + # sort rows based on input column names + errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] + # TODO: to reduce parameter, sort just based on alphabetic + # errorDT <- errorDT[order(errorDT$Column),] + } + + + errorType <- ifelse(length(inx_ws) > 0, "Wrong Schema", + ifelse(length(inx_mt) > 0, "Mismatch Template", "Invalid Value") + ) + } else { + validation_res <- "valid" + } + + outMsg <- paste0(c( + paste0("Your metadata is ", validation_res, " !!!"), + error_msg, help_msg + ), collapse = "

") + } + + return(list( + validationRes = validation_res, + outMsg = outMsg, + errorDT = errorDT, + errorType = errorType, + waiterMsg = waiter_msg + )) +} + +ValidationMsgUI <- function(id) { + ns <- NS(id) + tagList( + htmlOutput(ns("results")) + ) +} + +ValidationMsgServer <- function(id, valRes, template, inFile) { + moduleServer( + id, + function(input, output, session) { + output$results <- renderUI({ + text_class <- ifelse(!is.null(valRes$validationRes) && valRes$validationRes == "valid", + "success_msg", "error_msg" + ) + + tagList( + if (is.null(template)) { + span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) + }, + if (is.null(inFile)) { + span(class = text_class, HTML("Please upload a filled template !")) + }, + span(class = text_class, HTML(valRes$outMsg)) + ) + }) + } + ) +} diff --git a/server.R b/server.R index 338e4b53..a12828c9 100644 --- a/server.R +++ b/server.R @@ -49,7 +49,7 @@ shinyServer(function(input, output, session) { schema_to_display_lookup <- data.frame(schema_name, display_name) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_validate", "tbl_validate", "btn_val_gsheet", "div_val_gsheet", "btn_submit") + clean_tags <- c("div_download", "div_validate", "btn_submit") ######## Initiate Login Process ######## # synapse cookies @@ -145,7 +145,7 @@ shinyServer(function(input, output, session) { input$dropdown_template }, { - sapply(c("div_download", clean_tags), FUN = hide) + sapply(clean_tags, FUN = hide) } ) @@ -207,177 +207,64 @@ shinyServer(function(input, output, session) { ######## Reads .csv File ######## inFile <- csvInfileServer("inputFile", colsAsCharacters = TRUE, keepBlank = TRUE) - # renders in DT for preview + observeEvent(inFile$data(), { # hide the validation section when upload a new file - sapply(clean_tags, FUN = hide) - output$tbl_preview <- renderDT({ - datatable(inFile$data(), - options = list(lengthChange = FALSE, scrollX = TRUE), - rownames = FALSE - ) - }) + sapply(clean_tags[-1], FUN = hide) + # renders in DT for preview + DTableServer("tbl_preview", inFile$data()) }) ######## Validation Section ####### observeEvent(input$btn_validate, { + annotation_status <- metadata_model$validateModelManifest( + inFile$raw()$datapath, + template_name + ) + # validation messages + valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) + ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) + # loading screen for validating metadata dc_waiter("show", msg = "Validating...") - validation_res <- NULL - type_error <- NULL - help_msg <- NULL - - if (!is.null(inFile$data()) & !is.null(input$dropdown_template)) { - annotation_status <- metadata_model$validateModelManifest( - inFile$raw()$datapath, - template_name - ) - if (length(annotation_status) != 0) { - validation_res <- "invalid" - # mismatched template index - inx_mt <- which(sapply(annotation_status, function(x) { - grepl( - "Component value provided is: .*, whereas the Template Type is: .*", - x[[3]] - ) - })) - # missing column index - inx_ws <- which(sapply(annotation_status, function(x) { - grepl( - "Wrong schema", - x[[2]] - ) - })) - - if (length(inx_mt) > 0) { - # mismatched error(s): selected template mismatched with validating template - - waiter_msg <- "Mismatched Template Found !" - # get all mismatched components - error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% - unique() - column_names <- "Component" - - # error messages for mismatch - mismatch_c <- error_values %>% - sQuote() %>% - paste(collapse = ", ") - type_error <- paste0( - "The submitted metadata contains << ", - mismatch_c, " >> in the Component column, but requested validation for << ", - input$dropdown_template, " >>." - ) - help_msg <- paste0( - "Please check that you have selected the correct template in the Select your Dataset tab and - ensure your metadata contains only one template, e.g. ", - input$dropdown_template, "." - ) - - # get wrong columns and values for updating preview table - errorDT <- data.frame(Column = sapply( - annotation_status[inx_mt], - function(i) i[[2]] - ), Value = sapply( - annotation_status[inx_mt], - function(i) i[[4]][[1]] - )) - } else if (length(inx_ws) > 0) { - # wrong schema error(s): validating metadata miss any required columns - - waiter_msg <- "Wrong Schema Used !" - type_error <- "The submitted metadata does not contain all required column(s)." - help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and - ensure your metadata contains all required columns." - } else { - waiter_msg <- sprintf("%d errors found", length(annotation_status)) - type_error <- paste0( - "The submitted metadata have ", length(annotation_status), - " errors." - ) - help_msg <- NULL - - errorDT <- data.frame( - Column = sapply(annotation_status, function(i) i[[2]]), - Value = sapply(annotation_status, function(i) i[[4]][[1]]), Error = sapply( - annotation_status, - function(i) i[[3]] - ) - ) - # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile$data()))), ] - - # output error messages as data table - show("tbl_validate") - output$tbl_validate <- renderDT({ - datatable(errorDT, - caption = "The errors are also highlighted in the preview table above.", - rownames = FALSE, options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE - ) - ) - }) - } - - # highlight invalue cells in preview table - output$tbl_preview <- renderDT({ - if (length(inx_ws) > 0) { - # if it is wrong schema error, highlight all cells - datatable(inFile$data(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% - formatStyle(1, target = "row", backgroundColor = "yellow") - } else { - datatable(inFile$data(), options = list(lengthChange = FALSE, scrollX = TRUE)) %>% - formatStyle(errorDT$Column, backgroundColor = styleEqual( - errorDT$Value, - rep("yellow", length(errorDT$Value)) - )) - } - }) + # output error messages as data table + if (valRes$errorType == "Invalid Value") { + # renders in DT for preview + # show(NS("tbl_validate", "table")) # NS is used in module + DTableServer("tbl_validate", valRes$errorDT, + options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE + ) + ) + } - # validate_w$update(html = h3(waiter_msg)) - # TODO: fix issue: - # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 - dc_waiter("update", msg = waiter_msg, sleep = 2.5) + # highlight invalue cells in preview table - show("btn_val_gsheet") - } else { - validation_res <- "valid" - # show submit button - output$submit <- renderUI({ - actionButton("btn_submit", "Submit to Synapse") - }) - } + if (valRes$errorType == "Wrong Schema") { + DTableServer("tbl_preview", data = inFile$data(), highlight = "full") + } else { + DTableServer("tbl_preview", + data = inFile$data(), + highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + ) } - # validation messages - output$text_validate <- renderUI({ - text_class <- ifelse(!is.null(validation_res) && validation_res == "valid", - "success_msg", "error_msg" - ) - tagList( - if (is.null(input$dropdown_template)) { - span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) - }, - if (is.null(inFile$data())) { - span(class = text_class, HTML("Please upload a filled template !")) - }, - if (!is.null(validation_res)) { - span(class = text_class, HTML(paste0( - "Your metadata is ", validation_res, - " !!!" - ))) - }, if (!is.null(type_error)) { - span(class = text_class, HTML(paste0("

", type_error))) - }, - if (!is.null(help_msg)) { - span(class = text_class, HTML(paste0("

", help_msg))) - } - ) - }) + # validate_w$update(html = h3(waiter_msg)) + # TODO: fix issue: + # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 + dc_waiter("update", msg = valRes$waiterMsg, sleep = 2.5) + if (valRes$validationRes == "valid") { + # show submit button + output$submit <- renderUI({ + actionButton("btn_submit", "Submit to Synapse") + }) + hide("btn_val_gsheet") + } show("div_validate") }) @@ -389,9 +276,7 @@ shinyServer(function(input, output, session) { filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, " ", input$dropdown_template - ), inFile$datapath, template_name) - - show("div_val_gsheet") + ), inFile$raw()$datapath, template_name) output$text_val_gsheet <- renderUI({ # tags$a(href = filled_manifest, filled_manifest, target = '_blank') @@ -458,10 +343,6 @@ shinyServer(function(input, output, session) { nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") - # TODO: - # we could either hide or restart everything - # wait until testing on submit functions - # clear inputs sapply(clean_tags, FUN = hide) diff --git a/ui.R b/ui.R index 4a89ac78..06a3f40a 100644 --- a/ui.R +++ b/ui.R @@ -162,7 +162,7 @@ ui <- dashboardPage( solidHeader = TRUE, status = "primary", width = 12, - DT::DTOutput("tbl_preview") + DTableUI("tbl_preview") ), box( title = "Validate Filled Metadata", @@ -171,16 +171,14 @@ ui <- dashboardPage( width = 12, actionButton("btn_validate", "Validate Metadata"), hidden( + # TODO: 1. create module for gsheet + # 2. wrap up all validatio section in to one module div( id = "div_validate", height = "100%", - htmlOutput("text_validate") - ), - DT::DTOutput("tbl_validate"), - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")), - div( - id = "div_val_gsheet", - height = "100%", + ValidationMsgUI("text_validate"), + DTableUI("tbl_validate"), + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")), htmlOutput("text_val_gsheet") ) ), From ff7a8258513f8eedf2a9847edb1b5cbef026e0bf Mon Sep 17 00:00:00 2001 From: Rongrong Chai Date: Mon, 10 May 2021 11:50:10 -0400 Subject: [PATCH 045/260] improve gsheet button --- server.R | 12 +++++++----- ui.R | 3 +-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/server.R b/server.R index a12828c9..df1c0113 100644 --- a/server.R +++ b/server.R @@ -263,7 +263,11 @@ shinyServer(function(input, output, session) { output$submit <- renderUI({ actionButton("btn_submit", "Submit to Synapse") }) - hide("btn_val_gsheet") + } else { + # render gsheet button + output$val_gsheet <- renderUI({ + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) + }) } show("div_validate") }) @@ -278,13 +282,11 @@ shinyServer(function(input, output, session) { " ", input$dropdown_template ), inFile$raw()$datapath, template_name) - output$text_val_gsheet <- renderUI({ - # tags$a(href = filled_manifest, filled_manifest, target = '_blank') + # rerender and change button to link + output$val_gsheet <- renderUI({ HTML(paste0("Edit on the Google Sheet.")) }) - hide("btn_val_gsheet") # hide btn once link generated - dc_waiter("hide") }) diff --git a/ui.R b/ui.R index 06a3f40a..e080f6ba 100644 --- a/ui.R +++ b/ui.R @@ -178,8 +178,7 @@ ui <- dashboardPage( height = "100%", ValidationMsgUI("text_validate"), DTableUI("tbl_validate"), - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")), - htmlOutput("text_val_gsheet") + uiOutput("val_gsheet") ) ), helpText( From ca80832ae10974a251bc49998e86112f52425e1d Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 11 May 2021 14:26:45 +0000 Subject: [PATCH 046/260] improve codes and fix some errors --- functions/create_validation_msg.R | 88 ++++++++++++++++ functions/dc_waiter.R | 69 +++++++++++++ functions/list_to_vector.R | 1 + {python => functions}/metadata_model.py | 0 {python => functions}/synapse_func_alias.py | 0 global.R | 8 +- modules/dc_waiter.R | 61 ----------- modules/render_table.R | 1 + modules/switch_tabs.R | 2 +- modules/validation.R | 106 +------------------- server.R | 41 ++++---- ui.R | 2 - 12 files changed, 186 insertions(+), 193 deletions(-) create mode 100644 functions/create_validation_msg.R create mode 100644 functions/dc_waiter.R create mode 100644 functions/list_to_vector.R rename {python => functions}/metadata_model.py (100%) rename {python => functions}/synapse_func_alias.py (100%) delete mode 100644 modules/dc_waiter.R diff --git a/functions/create_validation_msg.R b/functions/create_validation_msg.R new file mode 100644 index 00000000..da5e5b86 --- /dev/null +++ b/functions/create_validation_msg.R @@ -0,0 +1,88 @@ +validationResult <- function(valRes, template, inFile) { + validation_res <- NULL + error_msg <- NULL + help_msg <- NULL + errorType <- NULL + + if (!is.null(inFile) & !is.null(template)) { + if (length(valRes) != 0) { + validation_res <- "invalid" + # mismatched template index + inx_mt <- which(sapply(valRes, function(x) { + grepl( + "Component value provided is: .*, whereas the Template Type is: .*", + x[[3]] + ) + })) + # missing column index + inx_ws <- which(sapply(valRes, function(x) { + grepl( + "Wrong schema", + x[[2]] + ) + })) + + if (length(inx_mt) > 0) { + # mismatched error(s): selected template mismatched with validating template + errorType <- "Mismatched Template" + # get all mismatched components + error_values <- sapply(valRes[inx_mt], function(x) x[[4]][[1]]) %>% + unique() + + # error messages for mismatch + mismatch_c <- error_values %>% + sQuote() %>% + paste(collapse = ", ") + error_msg <- paste0( + "The submitted metadata contains << ", + mismatch_c, " >> in the Component column, but requested validation for << ", + template, " >>." + ) + help_msg <- paste0( + "Please check that you have selected the correct template in the Select your Dataset tab and + ensure your metadata contains only one template, e.g. ", + template, "." + ) + } else if (length(inx_ws) > 0) { + # wrong schema error(s): validating metadata miss any required columns + errorType <- "Wrong Schema" + error_msg <- "The submitted metadata does not contain all required column(s)." + help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and + ensure your metadata contains all required columns." + } else { + errorType <- "Invalid Value" + error_msg <- paste0( + "The submitted metadata have ", length(valRes), + " errors." + ) + } + + errorDT <- data.frame( + Column = sapply(valRes, function(i) i[[2]]), + Value = sapply(valRes, function(i) i[[4]][[1]]), + Error = sapply(valRes, function(i) i[[3]]) + ) + + # sort rows based on input column names + errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] + # TODO: to reduce parameter, sort just based on alphabetic + # errorDT <- errorDT[order(errorDT$Column),] + } else { + validation_res <- "valid" + } + + # combine all error messages into one, add an extra empty line to bottom + outMsg <- paste0( + "Your metadata is ", validation_res, " !!!", "

", + error_msg, "

", + help_msg + ) + } + + return(list( + validationRes = validation_res, + outMsg = outMsg, + errorDT = errorDT, + errorType = errorType + )) +} diff --git a/functions/dc_waiter.R b/functions/dc_waiter.R new file mode 100644 index 00000000..c858aa5f --- /dev/null +++ b/functions/dc_waiter.R @@ -0,0 +1,69 @@ +# This is script to wrap up the waiter screen for data curator app +# TODO: maybe we could split into UI and server if we need + +dc_waiter <- function(stage = c("show", "update", "hide"), + isLogin = FALSE, isPass = TRUE, usrName = NULL, + sleep = 2, msg = NULL) { + # validate arguments + if (!is.logical(isLogin)) stop("isLogin must be a boolean") + if (!is.logical(isPass)) stop("isPass must be a boolean") + if (!is.numeric(sleep)) stop("sleep must be a numeric") + if (!stage %in% c("show", "update", "hide")) { + stop("Please provide a value for stage: 'show', 'update' or 'hide'.") + } + + # if "hide", proceed hiding process immediately and exit function + if (stage == "hide") { + Sys.sleep(sleep) + return(waiter_hide()) + } + + # log in screen + if (isLogin) { + # The message on initial loading page are not customizable + if (!is.null(msg)) message("message for log in screen can be changed in dc_waiter.R") + + if (stage == "show") { + waiter_show_on_load( + html = tagList( + img(src = "loading.gif"), + h4("Retrieving Synapse information...") + ), + color = "#424874" + ) + } else if (isPass) { + waiter_update(html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3(sprintf("Welcome, %s!", usrName)) + )) + Sys.sleep(sleep) + waiter_hide() + } else { + # ensure the synapse logo image is stored in www/ + waiter_update(html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3("Looks like you're not logged in!"), span( + "Please ", a("login", + href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" + ), + " to Synapse, then refresh this page." + ) + )) + } + } else { + # other loading screens + if (is.null(msg)) msg <- "Loading ..." + + if (stage == "show") { + waiter_show( + html = tagList(spin_plus(), br(), h3(msg)), + color = "rgba(66, 72, 116, .9)" + ) + } else { + Sys.sleep(2) # has to put at least 2s before to make update work + waiter_update(html = tagList(spin_loaders(32), br(), h3(msg))) + Sys.sleep(sleep) + waiter_hide() + } + } +} diff --git a/functions/list_to_vector.R b/functions/list_to_vector.R new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/functions/list_to_vector.R @@ -0,0 +1 @@ + diff --git a/python/metadata_model.py b/functions/metadata_model.py similarity index 100% rename from python/metadata_model.py rename to functions/metadata_model.py diff --git a/python/synapse_func_alias.py b/functions/synapse_func_alias.py similarity index 100% rename from python/synapse_func_alias.py rename to functions/synapse_func_alias.py diff --git a/global.R b/global.R index fa4048af..18912f83 100644 --- a/global.R +++ b/global.R @@ -74,6 +74,10 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" +# Activate conda env +# Don't necessarily have to set `RETICULATE_PYTHON` env variable +reticulate::use_condaenv("data_curator_env_oauth") + # Import functions/modules -source.files <- list.files("modules", pattern="*\\.R$", recursive = TRUE, full.names = TRUE) -sapply(source.files, FUN=source) \ No newline at end of file +source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) +sapply(source_files, FUN = source) diff --git a/modules/dc_waiter.R b/modules/dc_waiter.R deleted file mode 100644 index b325eb07..00000000 --- a/modules/dc_waiter.R +++ /dev/null @@ -1,61 +0,0 @@ -# This is script to wrap up the waiter screen for data curator app -# TODO: maybe we could split into UI and server if we need - -dc_waiter <- function(stage=c("show", "update", "hide"), - isLogin=FALSE, isPass=TRUE, usrName = NULL, - sleep=2, msg=NULL) { - # validate arguments - if(!is.logical(isLogin)) stop("isLogin must be a boolean") - if(!is.logical(isPass)) stop("isPass must be a boolean") - if(!is.numeric(sleep)) stop("sleep must be a numeric") - if (!stage %in% c("show", "update", "hide")) { - stop("Please provide a value for stage: 'show', 'update' or 'hide'.") - } - - # if "hide", proceed hiding process immediately and exit function - if (stage == "hide") { - Sys.sleep(sleep) - return(waiter_hide()) - } - - # log in screen - if (isLogin) { - # The message on initial loading page are not customizable - if (!is.null(msg)) message("message for log in screen can be changed in dc_waiter.R") - - if (stage == "show") { - waiter_show_on_load( - html = tagList( - img(src = "loading.gif"), - h4("Retrieving Synapse information...") - ), - color = "#424874" - ) - } else if (isPass) { - waiter_update(html = tagList(img(src = "synapse_logo.png", height = "120px"), - h3(sprintf("Welcome, %s!", usrName)))) - Sys.sleep(sleep) - waiter_hide() - } else { - # ensure the synapse logo image is stored in www/ - waiter_update(html = tagList(img(src = "synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), span("Please ", a("login", - href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), - " to Synapse, then refresh this page."))) - } - } else { - # other loading screens - if (is.null(msg)) msg <- "Loading ..." - - if (stage == "show") { - waiter_show(html = tagList(spin_plus(), br(), h3(msg)), - color = "rgba(66, 72, 116, .9)") - } else { - Sys.sleep(2) # has to put at least 2s before to make update work - waiter_update(html = tagList(spin_loaders(32), br(), h3(msg))) - Sys.sleep(sleep) - waiter_hide() - } - } - -} \ No newline at end of file diff --git a/modules/render_table.R b/modules/render_table.R index 0acf7f50..1208a329 100644 --- a/modules/render_table.R +++ b/modules/render_table.R @@ -23,6 +23,7 @@ DTableServer <- function(id, data, rownames = rownames, options = options ) + if (!is.null(highlight)) { if (highlight == "full") { df <- df %>% diff --git a/modules/switch_tabs.R b/modules/switch_tabs.R index 85c3a382..03a77794 100644 --- a/modules/switch_tabs.R +++ b/modules/switch_tabs.R @@ -33,7 +33,7 @@ switchTabServer <- function(id, tabId, tab, tabList, parent) { observeEvent(input[[tagName]], { current_tab <- which(tabList == tab) # need to use parent session to update tab - # TODO: figure out how to call parent inputs in module to minimize args + # TODO: figure out how to call parent inputs in module to minimize args updateTabItems(parent, tabId, selected = tabList[current_tab + i]) }) }) diff --git a/modules/validation.R b/modules/validation.R index bc445f11..52e30498 100644 --- a/modules/validation.R +++ b/modules/validation.R @@ -1,112 +1,9 @@ # format and process validation results from schematic -validationResult <- function(valRes, template, inFile) { - validation_res <- NULL - error_msg <- NULL - help_msg <- NULL - errorDT <- NULL - waiter_msg <- NULL - errorType <- NULL - - if (!is.null(inFile) & !is.null(template)) { - if (length(valRes) != 0) { - validation_res <- "invalid" - # mismatched template index - inx_mt <- which(sapply(valRes, function(x) { - grepl( - "Component value provided is: .*, whereas the Template Type is: .*", - x[[3]] - ) - })) - # missing column index - inx_ws <- which(sapply(valRes, function(x) { - grepl( - "Wrong schema", - x[[2]] - ) - })) - - if (length(inx_mt) > 0) { - # mismatched error(s): selected template mismatched with validating template - waiter_msg <- "Mismatched Template Found !" - # get all mismatched components - error_values <- sapply(valRes[inx_mt], function(x) x[[4]][[1]]) %>% - unique() - - # error messages for mismatch - mismatch_c <- error_values %>% - sQuote() %>% - paste(collapse = ", ") - error_msg <- paste0( - "The submitted metadata contains << ", - mismatch_c, " >> in the Component column, but requested validation for << ", - template, " >>." - ) - help_msg <- paste0( - "Please check that you have selected the correct template in the Select your Dataset tab and - ensure your metadata contains only one template, e.g. ", - template, "." - ) - - # get wrong columns and values for updating preview table - errorDT <- data.frame( - Column = sapply(valRes[inx_mt], function(i) i[[2]]), - Value = sapply(valRes[inx_mt], function(i) i[[4]][[1]]), - Error = "" - ) - } else if (length(inx_ws) > 0) { - # wrong schema error(s): validating metadata miss any required columns - waiter_msg <- "Wrong Schema Used !" - error_msg <- "The submitted metadata does not contain all required column(s)." - help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and - ensure your metadata contains all required columns." - } else { - waiter_msg <- sprintf("%d errors found", length(valRes)) - error_msg <- paste0( - "The submitted metadata have ", length(valRes), - " errors." - ) - - errorDT <- data.frame( - Column = sapply(valRes, function(i) i[[2]]), - Value = sapply(valRes, function(i) i[[4]][[1]]), - Error = sapply(valRes, function(i) i[[3]]) - ) - # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] - # TODO: to reduce parameter, sort just based on alphabetic - # errorDT <- errorDT[order(errorDT$Column),] - } - - - errorType <- ifelse(length(inx_ws) > 0, "Wrong Schema", - ifelse(length(inx_mt) > 0, "Mismatch Template", "Invalid Value") - ) - } else { - validation_res <- "valid" - } - - outMsg <- paste0(c( - paste0("Your metadata is ", validation_res, " !!!"), - error_msg, help_msg - ), collapse = "

") - } - - return(list( - validationRes = validation_res, - outMsg = outMsg, - errorDT = errorDT, - errorType = errorType, - waiterMsg = waiter_msg - )) -} - ValidationMsgUI <- function(id) { ns <- NS(id) - tagList( - htmlOutput(ns("results")) - ) + htmlOutput(ns("results")) } ValidationMsgServer <- function(id, valRes, template, inFile) { @@ -119,6 +16,7 @@ ValidationMsgServer <- function(id, valRes, template, inFile) { ) tagList( + # TODO: remove first two checking once we set dropdown value as 1st selection by default if (is.null(template)) { span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) }, diff --git a/server.R b/server.R index df1c0113..a8195848 100644 --- a/server.R +++ b/server.R @@ -4,9 +4,6 @@ # pages to log into Synapse as the currently logged in user from the web portal # using the session token. https://www.synapse.org -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") - shinyServer(function(input, output, session) { params <- parseQueryString(isolate(session$clientData$url_search)) if (!has_auth_code(params)) { @@ -26,8 +23,8 @@ shinyServer(function(input, output, session) { access_token <- token_response$access_token ######## session global variables ######## - source_python("python/synapse_func_alias.py") - source_python("python/metadata_model.py") + source_python("functions/synapse_func_alias.py") + source_python("functions/metadata_model.py") # import module that contains SynapseStorage class synapse_driver <- import("schematic.store.synapse")$SynapseStorage # read config in @@ -189,7 +186,7 @@ shinyServer(function(input, output, session) { manifest_entity <- syn_get(existing_manifestID) manifest_url <- metadata_model$populateModelManifest(paste0( config$community, - " ", input$temdropdown_templateplate_type + " ", input$dropdown_template ), manifest_entity$path, template_name) } @@ -207,7 +204,6 @@ shinyServer(function(input, output, session) { ######## Reads .csv File ######## inFile <- csvInfileServer("inputFile", colsAsCharacters = TRUE, keepBlank = TRUE) - observeEvent(inFile$data(), { # hide the validation section when upload a new file sapply(clean_tags[-1], FUN = hide) @@ -217,6 +213,10 @@ shinyServer(function(input, output, session) { ######## Validation Section ####### observeEvent(input$btn_validate, { + + # loading screen for validating metadata + dc_waiter("show", msg = "Validating...") + annotation_status <- metadata_model$validateModelManifest( inFile$raw()$datapath, template_name @@ -225,24 +225,20 @@ shinyServer(function(input, output, session) { valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) - # loading screen for validating metadata - dc_waiter("show", msg = "Validating...") + # output error messages as data table if it is invalid value type - # output error messages as data table - if (valRes$errorType == "Invalid Value") { - # renders in DT for preview - # show(NS("tbl_validate", "table")) # NS is used in module - DTableServer("tbl_validate", valRes$errorDT, - options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE - ) + # renders in DT for preview + # render empty if error is not "invaid value" type - ifelse() will not work + show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) + DTableServer("tbl_validate", show_df, + options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE ) - } + ) # highlight invalue cells in preview table - if (valRes$errorType == "Wrong Schema") { DTableServer("tbl_preview", data = inFile$data(), highlight = "full") } else { @@ -252,11 +248,10 @@ shinyServer(function(input, output, session) { ) } - # validate_w$update(html = h3(waiter_msg)) # TODO: fix issue: # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 - dc_waiter("update", msg = valRes$waiterMsg, sleep = 2.5) + dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), sleep = 2.5) if (valRes$validationRes == "valid") { # show submit button diff --git a/ui.R b/ui.R index e080f6ba..a6af5fc8 100644 --- a/ui.R +++ b/ui.R @@ -171,8 +171,6 @@ ui <- dashboardPage( width = 12, actionButton("btn_validate", "Validate Metadata"), hidden( - # TODO: 1. create module for gsheet - # 2. wrap up all validatio section in to one module div( id = "div_validate", height = "100%", From 19e8b48a9b7ac981e2d1b0c3434265d34b71fdd2 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 11 May 2021 16:06:52 +0000 Subject: [PATCH 047/260] add utils --- .gitignore | 3 +- functions/list_to_vector.R | 1 - functions/utils.R | 8 ++++ modules/render_table.R | 1 + server.R | 77 +++++++++++++------------------------- 5 files changed, 35 insertions(+), 55 deletions(-) delete mode 100644 functions/list_to_vector.R create mode 100644 functions/utils.R diff --git a/.gitignore b/.gitignore index 162d9a21..11623cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ schematic/token.pickle credentials.json token.pickle **/__pycache__ -config.yaml -renv/activate.R \ No newline at end of file +config.yaml \ No newline at end of file diff --git a/functions/list_to_vector.R b/functions/list_to_vector.R deleted file mode 100644 index 8b137891..00000000 --- a/functions/list_to_vector.R +++ /dev/null @@ -1 +0,0 @@ - diff --git a/functions/utils.R b/functions/utils.R new file mode 100644 index 00000000..76e230fc --- /dev/null +++ b/functions/utils.R @@ -0,0 +1,8 @@ + +list2Vector <- function(list) { + vector <- c() + for (i in seq_along(list)) { + vector[list[[i]][[2]]] <- list[[i]][[1]] + } + return(vector) +} diff --git a/modules/render_table.R b/modules/render_table.R index 1208a329..9aca7a4c 100644 --- a/modules/render_table.R +++ b/modules/render_table.R @@ -35,6 +35,7 @@ DTableServer <- function(id, data, )) } } + moduleServer( id, function(input, output, session) { diff --git a/server.R b/server.R index a8195848..7a440a3c 100644 --- a/server.R +++ b/server.R @@ -37,8 +37,8 @@ shinyServer(function(input, output, session) { folders_namedList <- NULL folder_synID <- NULL # selected foler synapse ID - template_name <- NULL # selected template schema name - filename_list <- NULL + template_schema_name <- NULL # selected template schema name + file_namedlist <- NULL ### mapping from display name to schema name schema_name <- config$manifest_schemas$schema_name @@ -64,16 +64,12 @@ shinyServer(function(input, output, session) { titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) }) - # updating global vars with values for projects synStore_obj <<- + # updating global vars with values for projects synStore_obj <<- synapse_driver(token = input$cookie) # get_projects_list(synStore_obj) projects_list <- synapse_driver$getStorageProjects(synStore_obj) - - # projects_namedList <- NULL # may need to uncomment when we have refresh button - for (i in seq_along(projects_list)) { - projects_namedList[projects_list[[i]][[2]]] <<- projects_list[[i]][[1]] - } + projects_namedList <<- list2Vector(projects_list) # updates project dropdown updateSelectizeInput(session, "dropdown_project", choices = sort(names(projects_namedList))) @@ -104,15 +100,10 @@ shinyServer(function(input, output, session) { synStore_obj, project_synID ) - - folders_namedList <<- NULL # need to clean first - for (i in seq_along(folder_list)) { - folders_namedList[folder_list[[i]][[2]]] <<- folder_list[[i]][[1]] - } - folderNames <- names(folders_namedList) + folders_namedList <<- list2Vector(folder_list) # updates foldernames - selectInput(inputId = "dropdown_folder", label = "Folder:", choices = folderNames) + selectInput(inputId = "dropdown_folder", label = "Folder:", choices = names(folders_namedList)) }) }) @@ -132,7 +123,7 @@ shinyServer(function(input, output, session) { 1, drop = F ] - template_name <<- as.character(template_type_df$schema_name) + template_schema_name <<- as.character(template_type_df$schema_name) }) # hide tags when users select new template @@ -162,23 +153,21 @@ shinyServer(function(input, output, session) { synStore_obj, folder_synID ) - # if there isn't an existing manifest make a new one if (existing_manifestID == "") { + # get file list in selected folder + # don't put in the observation of folder dropdown + # it will crash if users switch folders too often file_list <- synapse_driver$getFilesInStorageDataset( synStore_obj, folder_synID ) - file_namedList <- c() - for (i in seq_along(file_list)) { - file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] - } - filename_list <- names(file_namedList) + file_namedlist <<- list2Vector(file_list) manifest_url <- metadata_model$getModelManifest(paste0( config$community, " ", input$dropdown_template - ), template_name, filenames = as.list(filename_list)) + ), template_schema_name, filenames = as.list(names(file_namedlist))) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { @@ -187,7 +176,7 @@ shinyServer(function(input, output, session) { manifest_url <- metadata_model$populateModelManifest(paste0( config$community, " ", input$dropdown_template - ), manifest_entity$path, template_name) + ), manifest_entity$path, template_schema_name) } output$text_download <- renderUI({ @@ -219,7 +208,7 @@ shinyServer(function(input, output, session) { annotation_status <- metadata_model$validateModelManifest( inFile$raw()$datapath, - template_name + template_schema_name ) # validation messages valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) @@ -275,7 +264,7 @@ shinyServer(function(input, output, session) { filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, " ", input$dropdown_template - ), inFile$raw()$datapath, template_name) + ), inFile$raw()$datapath, template_schema_name) # rerender and change button to link output$val_gsheet <- renderUI({ @@ -309,15 +298,13 @@ shinyServer(function(input, output, session) { quote = TRUE, row.names = FALSE, na = "" ) } else { - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - file_namedList <- c() - for (i in seq_along(file_list)) { - file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] + if (is.null(file_namedlist)) { # if user do not generate gsheet of template before + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + file_namedlist <<- list2Vector(file_list) } - files_df <- stack(file_namedList) colnames(files_df) <- c("entityId", "Filename") files_entity <- inner_join(infile, files_df, by = "Filename") @@ -333,31 +320,17 @@ shinyServer(function(input, output, session) { synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID ) - print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") - # clear inputs + # clean up inputfile sapply(clean_tags, FUN = hide) - - # TODO: consider removing this chunk, - # could change to reset('inFile') if reset works - # rerenders fileinput UI - # output$fileInput_ui <- renderUI({ - # fileInput("file1", "Upload CSV File", accept = c( - # "text/csv", "text/comma-separated-values", - # ".csv" - # )) - # }) - - # renders empty df - output$tbl_preview <- renderDT(datatable(as.data.frame(matrix(0, - ncol = 0, - nrow = 0 - )))) + DTableServer("tbl_preview", data.frame(NULL)) + # TODO: input file not reset yet + # reset(c(clean_tags, "inputFile", "tbl_preview")) if reset works } else { dc_waiter("update", msg = HTML(paste0( "Uh oh, looks like something went wrong!", From b2721478dbfc1e7d72f9c4e06d00a67b172943d9 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 13 May 2021 15:47:55 +0000 Subject: [PATCH 048/260] feature - show users' datatypes selections and be able to modify --- functions/create_validation_msg.R | 12 +- functions/dc_waiter.R | 10 +- global.R | 4 + renv.lock | 103 ++++++++++------- server.R | 179 +++++++++++++++++++----------- ui.R | 50 +++++++-- www/js/onclick.js | 17 +++ www/{ => js}/readCookie.js | 14 +-- www/scss/basic/_animation.scss | 18 +++ www/scss/basic/_button.scss | 63 ++++++++++- www/scss/basic/_variables.scss | 8 +- www/scss/main.scss | 5 +- www/scss/section/_content.scss | 9 ++ www/scss/section/_header.scss | 64 ++++++++++- www/scss/section/_navigation.scss | 3 - www/scss/section/_sidebar.scss | 8 +- 16 files changed, 418 insertions(+), 149 deletions(-) create mode 100644 www/js/onclick.js rename www/{ => js}/readCookie.js (72%) create mode 100644 www/scss/basic/_animation.scss delete mode 100644 www/scss/section/_navigation.scss diff --git a/functions/create_validation_msg.R b/functions/create_validation_msg.R index da5e5b86..7067a9ba 100644 --- a/functions/create_validation_msg.R +++ b/functions/create_validation_msg.R @@ -2,6 +2,8 @@ validationResult <- function(valRes, template, inFile) { validation_res <- NULL error_msg <- NULL help_msg <- NULL + outMsg <- NULL + errorDT <- NULL errorType <- NULL if (!is.null(inFile) & !is.null(template)) { @@ -69,14 +71,14 @@ validationResult <- function(valRes, template, inFile) { # errorDT <- errorDT[order(errorDT$Column),] } else { validation_res <- "valid" + errorType <- "No Error" } # combine all error messages into one, add an extra empty line to bottom - outMsg <- paste0( - "Your metadata is ", validation_res, " !!!", "

", - error_msg, "

", - help_msg - ) + outMsg <- paste0(c( + paste0("Your metadata is ", validation_res, " !!!"), + error_msg, help_msg + ), collapse = "

") } return(list( diff --git a/functions/dc_waiter.R b/functions/dc_waiter.R index c858aa5f..6813b5b3 100644 --- a/functions/dc_waiter.R +++ b/functions/dc_waiter.R @@ -3,7 +3,7 @@ dc_waiter <- function(stage = c("show", "update", "hide"), isLogin = FALSE, isPass = TRUE, usrName = NULL, - sleep = 2, msg = NULL) { + sleep = 2, msg = NULL, spin = NULL) { # validate arguments if (!is.logical(isLogin)) stop("isLogin must be a boolean") if (!is.logical(isPass)) stop("isPass must be a boolean") @@ -11,7 +11,8 @@ dc_waiter <- function(stage = c("show", "update", "hide"), if (!stage %in% c("show", "update", "hide")) { stop("Please provide a value for stage: 'show', 'update' or 'hide'.") } - + if (is.null(msg)) msg <- "Loading ..." + if (is.null(spin)) spin <- spin_plus() # if "hide", proceed hiding process immediately and exit function if (stage == "hide") { Sys.sleep(sleep) @@ -52,16 +53,15 @@ dc_waiter <- function(stage = c("show", "update", "hide"), } } else { # other loading screens - if (is.null(msg)) msg <- "Loading ..." if (stage == "show") { waiter_show( - html = tagList(spin_plus(), br(), h3(msg)), + html = tagList(spin, br(), h3(msg)), color = "rgba(66, 72, 116, .9)" ) } else { Sys.sleep(2) # has to put at least 2s before to make update work - waiter_update(html = tagList(spin_loaders(32), br(), h3(msg))) + waiter_update(html = tagList(spin, br(), h3(msg))) Sys.sleep(sleep) waiter_hide() } diff --git a/global.R b/global.R index 18912f83..acb9bcaf 100644 --- a/global.R +++ b/global.R @@ -18,6 +18,7 @@ suppressPackageStartupMessages({ library(waiter) library(readr) library(sass) + library(shinydashboardPlus) }) # APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" @@ -81,3 +82,6 @@ reticulate::use_condaenv("data_curator_env_oauth") # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) + +# Global variables +datatypes <- c("project", "folder", "template") diff --git a/renv.lock b/renv.lock index aa3faad3..9804e4f4 100644 --- a/renv.lock +++ b/renv.lock @@ -4,7 +4,11 @@ "Repositories": [ { "Name": "CRAN", - "URL": "https://ftp.osuosl.org/pub/cran" + "URL": "https://cran.rstudio.com" + }, + { + "Name": "Sage", + "URL": "http://ran.synapse.org" } ] }, @@ -37,6 +41,34 @@ "Repository": "CRAN", "Hash": "08588806cba69f04797dab50627428ed" }, + "R.cache": { + "Package": "R.cache", + "Version": "0.15.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "e92a8ea8388c47c82ed8aa435ed3be50" + }, + "R.methodsS3": { + "Package": "R.methodsS3", + "Version": "1.8.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4bf6453323755202d5909697b6f7c109" + }, + "R.oo": { + "Package": "R.oo", + "Version": "1.24.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5709328352717e2f0a9c012be8a97554" + }, + "R.utils": { + "Package": "R.utils", + "Version": "2.10.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "a9e316277ff12a43997266f2f6567780" + }, "R6": { "Package": "R6", "Version": "2.4.1", @@ -212,6 +244,13 @@ "Repository": "CRAN", "Hash": "83ab58a0518afe3d17e41da01af13b60" }, + "fresh": { + "Package": "fresh", + "Version": "0.2.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "fa54367040deb4537da49b7ac0ee5770" + }, "fs": { "Package": "fs", "Version": "1.4.2", @@ -254,13 +293,6 @@ "Repository": "CRAN", "Hash": "3d59212f2814d65dff517e6899813c58" }, - "highr": { - "Package": "highr", - "Version": "0.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4dc5bb88961e347a0f4d8aad597cbfac" - }, "hms": { "Package": "hms", "Version": "0.5.3", @@ -315,13 +347,6 @@ "Repository": "CRAN", "Hash": "2657f20b9a74c996c602e74ebe540b06" }, - "knitr": { - "Package": "knitr", - "Version": "1.29", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e5f4c41c17df8cdf7b0df12117c0d99a" - }, "labeling": { "Package": "labeling", "Version": "0.3", @@ -359,17 +384,10 @@ }, "magrittr": { "Package": "magrittr", - "Version": "1.5", + "Version": "2.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "1bb58822a20301cee84a41678e25d9b7" - }, - "markdown": { - "Package": "markdown", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "61e4a10781dd00d7d81dd06ca9b94e95" + "Hash": "41287f1ac7d28a92f0a286ed507928d3" }, "mgcv": { "Package": "mgcv", @@ -438,8 +456,8 @@ "Package": "plotly", "Version": "4.9.2.9000", "Source": "GitHub", - "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", "RemoteType": "github", + "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", "RemoteHost": "api.github.com", "RemoteRepo": "plotly", "RemoteUsername": "ropensci", @@ -503,6 +521,13 @@ "Repository": "CRAN", "Hash": "2639976851f71f330264a9c9c3d43a61" }, + "rematch2": { + "Package": "rematch2", + "Version": "2.1.2", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "76c9e04c712a05848ae7a23d2f170a40" + }, "renv": { "Package": "renv", "Version": "0.11.0-3", @@ -536,13 +561,6 @@ "Repository": "CRAN", "Hash": "c06d2a6887f4b414f8e927afd9ee976a" }, - "rmarkdown": { - "Package": "rmarkdown", - "Version": "2.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "202260e1b2c410edc086d5b8f1ed946e" - }, "rprojroot": { "Package": "rprojroot", "Version": "1.3-2", @@ -585,6 +603,13 @@ "Repository": "CRAN", "Hash": "133639dc106955eee4ffb8ec73edac37" }, + "shinydashboardPlus": { + "Package": "shinydashboardPlus", + "Version": "2.0.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "1abe63cd90fe33d3ca211525a0b39af9" + }, "shinyjs": { "Package": "shinyjs", "Version": "1.1", @@ -632,6 +657,13 @@ "Repository": "CRAN", "Hash": "0759e6b6c0957edb1311028a49a35e76" }, + "styler": { + "Package": "styler", + "Version": "1.4.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2ec6308547ffe73208cef3ef3766fc33" + }, "sys": { "Package": "sys", "Version": "3.3", @@ -667,13 +699,6 @@ "Repository": "CRAN", "Hash": "6ea435c354e8448819627cf686f66e0a" }, - "tinytex": { - "Package": "tinytex", - "Version": "0.24", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f24b65b86f4d6d7b1e2d8a4ce2c02fb" - }, "utf8": { "Package": "utf8", "Version": "1.1.4", diff --git a/server.R b/server.R index 7a440a3c..0a598c16 100644 --- a/server.R +++ b/server.R @@ -30,20 +30,22 @@ shinyServer(function(input, output, session) { # read config in config <- fromJSON("www/config.json") - # logs in and gets list of projects they have access to - synStore_obj <- NULL - projects_namedList <- NULL + # mapping from display name to schema name + schema_name <- config$manifest_schemas$schema_name + display_name <- config$manifest_schemas$display_name + template_namedList <- schema_name + names(template_namedList) <- display_name - folders_namedList <- NULL + synStore_obj <- NULL # gets list of projects they have access to folder_synID <- NULL # selected foler synapse ID - template_schema_name <- NULL # selected template schema name - file_namedlist <- NULL - ### mapping from display name to schema name - schema_name <- config$manifest_schemas$schema_name - display_name <- config$manifest_schemas$display_name - schema_to_display_lookup <- data.frame(schema_name, display_name) + datatype_list <- list( + projects_namedList = NULL, + folders_namedList = NULL, + display_name = template_namedList + ) + file_namedlist <- NULL tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") clean_tags <- c("div_download", "div_validate", "btn_submit") @@ -69,15 +71,22 @@ shinyServer(function(input, output, session) { # get_projects_list(synStore_obj) projects_list <- synapse_driver$getStorageProjects(synStore_obj) - projects_namedList <<- list2Vector(projects_list) + datatype_list[["projects_namedList"]] <<- list2Vector(projects_list) # updates project dropdown - updateSelectizeInput(session, "dropdown_project", choices = sort(names(projects_namedList))) + lapply(c("header_dropdown_", "dropdown_"), function(x) { + lapply(c(1, 3), function(i) { + updateSelectizeInput(session, paste0(x, datatypes[i]), + choices = sort(names(datatype_list[[i]])) + ) + }) + }) # update waiter loading screen once login successful dc_waiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) }, error = function(err) { + message(err) # write log error dc_waiter("update", isLogin = TRUE, isPass = FALSE) } ) @@ -90,40 +99,74 @@ shinyServer(function(input, output, session) { }) ######## Update Folder List ######## - observeEvent(ignoreInit = TRUE, input$dropdown_project, { - output$folders <- renderUI({ + lapply(c("header_dropdown_", "dropdown_"), function(x) { + observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { # get synID of selected project - project_synID <- projects_namedList[[input$dropdown_project]] + project_synID <- datatype_list[["projects_namedList"]][[input[[paste0(x, "project")]]]] # gets folders per project folder_list <- synapse_driver$getStorageDatasetsInProject( synStore_obj, project_synID ) - folders_namedList <<- list2Vector(folder_list) + datatype_list[["folders_namedList"]] <<- list2Vector(folder_list) + folders <- sort(names(datatype_list[["folders_namedList"]])) # updates foldernames - selectInput(inputId = "dropdown_folder", label = "Folder:", choices = names(folders_namedList)) + updateSelectizeInput(session, paste0(x, "folder"), + choices = folders + ) }) }) + # Adjust header selection dropdown based on tabs + observe({ + if (input[["tabs"]] %in% c("tab_instructions", "tab_data")) { + hide("header_selection_dropdown") + } else { + show("header_selection_dropdown") + } + }) + + + lapply(datatypes, function(i) { + observeEvent(input[[paste0("dropdown_", i)]], { + updateSelectizeInput(session, paste0("header_dropdown_", i), + selected = input[[paste0("dropdown_", i)]] + ) + }) + }) + + observeEvent(input$btn_header_update, { + nx_confirm( + inputId = "update_confirm", + title = "Are you sure to update?", + message = "previous selections will also change", + button_ok = "Sure!", + button_cancel = "Nope!" + ) + }) + + observeEvent(input$update_confirm, { + if (input$update_confirm == TRUE) { + lapply(datatypes, function(i) { + updateSelectizeInput(session, paste0("dropdown_", i), + selected = input[[paste0("header_dropdown_", i)]] + ) + }) + } + }) + # update selected folder ID observeEvent(input$dropdown_folder, { # TODO: check how different from using rectivateValues() - folder_synID <<- folders_namedList[[input$dropdown_folder]] + folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] }) ######## Update Template ######## - output$manifest_display_name <- renderUI({ - selectInput(inputId = "dropdown_template", label = "Template:", choices = display_name) - }) # update selected schema template name observeEvent(input$dropdown_template, { - template_type_df <- schema_to_display_lookup[match(input$dropdown_template, schema_to_display_lookup$display_name), - 1, - drop = F - ] - template_schema_name <<- as.character(template_type_df$schema_name) + template_schema_name <<- template_namedList[match(input$dropdown_template, names(template_namedList))] }) # hide tags when users select new template @@ -167,7 +210,7 @@ shinyServer(function(input, output, session) { manifest_url <- metadata_model$getModelManifest(paste0( config$community, " ", input$dropdown_template - ), template_schema_name, filenames = as.list(names(file_namedlist))) + ), template_schema_name, filenames = as.list(names(datatype_list[["file_namedlist"]]))) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { @@ -205,54 +248,60 @@ shinyServer(function(input, output, session) { # loading screen for validating metadata dc_waiter("show", msg = "Validating...") - - annotation_status <- metadata_model$validateModelManifest( - inFile$raw()$datapath, - template_schema_name + try( + silent = TRUE, + annotation_status <- metadata_model$validateModelManifest( + inFile$raw()$datapath, + template_schema_name + ) ) + # validation messages valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) - # output error messages as data table if it is invalid value type - - # renders in DT for preview - # render empty if error is not "invaid value" type - ifelse() will not work - show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) - DTableServer("tbl_validate", show_df, - options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE - ) - ) - - # highlight invalue cells in preview table - if (valRes$errorType == "Wrong Schema") { - DTableServer("tbl_preview", data = inFile$data(), highlight = "full") - } else { - DTableServer("tbl_preview", - data = inFile$data(), - highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + # if there is a file uploaded + if (!is.null(valRes$validationRes)) { + + # output error messages as data table if it is invalid value type + # render empty if error is not "invaid value" type - ifelse() will not work + show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) + DTableServer("tbl_validate", show_df, + options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE + ) ) - } - # validate_w$update(html = h3(waiter_msg)) - # TODO: fix issue: - # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), sleep = 2.5) + # highlight invalue cells in preview table + if (valRes$errorType == "Wrong Schema") { + DTableServer("tbl_preview", data = inFile$data(), highlight = "full") + } else { + DTableServer("tbl_preview", + data = inFile$data(), + highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + ) + } - if (valRes$validationRes == "valid") { - # show submit button - output$submit <- renderUI({ - actionButton("btn_submit", "Submit to Synapse") - }) + if (valRes$validationRes == "valid") { + # show submit button + output$submit <- renderUI({ + actionButton("btn_submit", "Submit to Synapse") + }) + output$val_gsheet <- renderUI(NULL) + dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) + } else { + # render gsheet button + output$val_gsheet <- renderUI({ + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) + }) + dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) + } } else { - # render gsheet button - output$val_gsheet <- renderUI({ - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) - }) + dc_waiter("hide") } + show("div_validate") }) diff --git a/ui.R b/ui.R index a6af5fc8..2de0a98a 100644 --- a/ui.R +++ b/ui.R @@ -8,17 +8,40 @@ # # https://www.synapse.org -ui <- dashboardPage( +ui <- shinydashboardPlus::dashboardPage( skin = "purple", dashboardHeader( titleWidth = 250, - title = "Data Curator", + title = tagList( + span(class = "logo-lg", "Data Curator"), + span(class = "logo-mini", "DCA") + ), + leftUi = tagList( + dropdownBlock( + id = "header_selection_dropdown", + title = "Selection", + icon = icon("sliders"), + badgeStatus = "info", + fluidRow( + lapply(datatypes, function(x) { + div( + id = paste0("hover_text_", x), + selectizeInput( + inputId = paste0("header_dropdown_", x), + label = NULL, + choices = character(0) + ) + ) + }), + actionButton(inputId = "btn_header_update", label = NULL, icon = icon("sync-alt")) + ) + ) + ), tags$li( - class = "dropdown", + class = "dropdown", id = "HTAN_logo", tags$a( href = "https://humantumoratlas.org/", target = "_blank", - ## insert links and logos of your choice, this is just an example tags$img( height = "40px", alt = "HTAN LOGO", src = "HTAN_text_logo.png" @@ -62,17 +85,16 @@ ui <- dashboardPage( dashboardBody( tags$head( tags$style(sass(sass_file("www/scss/main.scss"))), - singleton( - includeScript("www/readCookie.js") - ) + singleton(includeScript("www/js/readCookie.js")), + singleton(includeScript("www/js/onclick.js")) ), - uiOutput("title"), use_notiflix_report(), use_waiter(), tabItems( # First tab content tabItem( tabName = "tab_instructions", + uiOutput("title"), h2("Instructions for the Data Curator App:"), h3( "1. Go to", @@ -106,7 +128,11 @@ ui <- dashboardPage( label = "Project:", choices = "Generating..." ), - uiOutput("folders"), + selectizeInput( + inputId = "dropdown_folder", + label = "Folder:", + choices = "Generating..." + ), helpText( "If your recently updated folder does not appear, please wait for Synapse to sync and refresh" ) @@ -116,7 +142,11 @@ ui <- dashboardPage( solidHeader = TRUE, width = 6, title = "Choose a Metadata Template Type: ", - uiOutput("manifest_display_name") + selectizeInput( + inputId = "dropdown_template", + label = "Template:", + choices = "Generating..." + ) ) ), switchTabUI("switchTab2", direction = "both") diff --git a/www/js/onclick.js b/www/js/onclick.js new file mode 100644 index 00000000..366deaaf --- /dev/null +++ b/www/js/onclick.js @@ -0,0 +1,17 @@ +// this script is to adjust the distance btw #header_selection_dropdown and content + +$(document).on('shiny:connected', function (event) { + $('#header_selection_dropdown').on('click', function () { + if ($('#header_selection_dropdown')[0].className != 'dropdown open') { + $('.content').css('padding-top', '50px') + } else { + $('.content').css('padding-top', '15px') + } + }) +}); + +$(document).on('click', function (e) { + if (e.target.id != '#header_selection_dropdown') { + $('.content').css('padding-top', '15px'); + } +}) diff --git a/www/readCookie.js b/www/js/readCookie.js similarity index 72% rename from www/readCookie.js rename to www/js/readCookie.js index 8300f1c7..d5a56c5e 100644 --- a/www/readCookie.js +++ b/www/js/readCookie.js @@ -17,18 +17,18 @@ // } // read the user login token from a cookie (new protocol) -Shiny.addCustomMessageHandler("readCookie", function(message) { - readCookie(); +Shiny.addCustomMessageHandler("readCookie", function (message) { + readCookie(); }); function readCookie() { const xhr = new XMLHttpRequest(); - const url='https://www.synapse.org/Portal/sessioncookie'; + const url = 'https://www.synapse.org/Portal/sessioncookie'; xhr.withCredentials = true; - xhr.onreadystatechange = function() { - if (xhr.readyState == XMLHttpRequest.DONE) { - Shiny.onInputChange("cookie",xhr.responseText); - } + xhr.onreadystatechange = function () { + if (xhr.readyState == XMLHttpRequest.DONE) { + Shiny.onInputChange("cookie", xhr.responseText); + } } xhr.open("GET", url); xhr.send(); diff --git a/www/scss/basic/_animation.scss b/www/scss/basic/_animation.scss new file mode 100644 index 00000000..83e6c4b4 --- /dev/null +++ b/www/scss/basic/_animation.scss @@ -0,0 +1,18 @@ +@keyframes fadeIn { + 0% {transform:scale(0); opacity: 0} + 30% {transform: scale(0.3)} + 70% {transform: scale(0.7)} + 100% {transform: scale(1); opacity: 1} +} + +@keyframes TransitioningBackground { + 0% { + background-position: 1% 0%; + } + 50% { + background-position: 99% 100%; + } + 100% { + background-position: 1% 0%; + } +} \ No newline at end of file diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index b1edd959..d74ddf1a 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -1 +1,62 @@ -// styles of button are collected in here \ No newline at end of file +// styles of button are collected in here + + + +// https://paigen11.medium.com/ +#btn_header_update +{ + position: relative; + background: #27022d; + color: #fff; + text-decoration: none; + letter-spacing: 1px; + border-radius: 5px; + box-shadow: $simple_shadow; + transition: 500ms; + overflow: hidden; + // for background color shift + background-image: (linear-gradient(270deg, #8e9ac2, #42579a)); + background-size: 400% 400%; + animation: TransitioningBackground 10s ease infinite; + + &:hover { + background-image: (linear-gradient(to left, #2d8fe5, #d155b8)); + transform: scale(1.05); + cursor: pointer; + } + // shine animation left side + &::before { + content: ''; + display: block; + position: absolute; + background: rgba(255, 255, 255, 0.5); + width: 60px; + height: 100%; + top: 0; + filter: blur(30px); + transform: translateX(-100px) skewX(-15deg); + } + // shine animation right side + &::after { + content: ''; + display: block; + position: absolute; + background: rgba(255, 255, 255, 0.2); + width: 30px; + height: 100%; + top: 0; + filter: blur(5px); + transform: translateX(-100px) skewX(-15deg); + } + + &::before, + &::after { + transform: translateX(300px) skewX(-15deg); + transition: 0.7s; + } +} + + + + + diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index f4b38557..23079b5f 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -6,4 +6,10 @@ $success_col: #28a745; $notif_process_col: #F7DC6F; $notif_success_col: #82E0AA; $footer_col: #465362; -$footer_bg_col: #D0D6DC; \ No newline at end of file +$footer_bg_col: #D0D6DC; + +// box shadow +$simple_shadow: 0 10px 10px -5px; +$float_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), + 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), + 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); \ No newline at end of file diff --git a/www/scss/main.scss b/www/scss/main.scss index f8b2829e..d9991cca 100644 --- a/www/scss/main.scss +++ b/www/scss/main.scss @@ -3,14 +3,11 @@ // dashboard sections @import 'section/header'; -@import 'section/navigation'; @import 'section/sidebar'; @import 'section/content'; @import 'section/footer'; // feature styles +@import 'basic/animation'; @import 'basic/button'; @import 'basic/message'; - - - diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 4fa62e4e..e22bae94 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -6,3 +6,12 @@ padding: 10px 0; } +.option { + &:hover, &:focus { + transform: scale(1.02); + font-size: 1.1em; + box-shadow: $float_shadow; + border-radius: 20px; + transition: transform 50ms; + } +} \ No newline at end of file diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index f824c55c..4d5c355e 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -1,9 +1,63 @@ .main-header { - max-height: 50px; + + .logo { + font-size: 1.8em; + } - .logo { - height: 70px; - font-size: 21px; - padding-top: 10px; + #HTAN_logo a { + height: 50px; + display: table-cell; + vertical-align: middle; + padding: 0 15px; + } + + .dropdown-menu { + left: auto !important; // stick with the button left + box-shadow: $float_shadow; + animation: fadeIn 100ms; + + + ul.menu { + + padding: 0 5px !important; + // reset all margin + & * { + margin: 0px; + } + + &>div, .row { + display: flex; + align-items: center; + justify-content: flex-start; + width: 100% !important; + } + + .shiny-input-container{ + width: 250px; + margin: 5px; + height: 34px; // remove extra space bottom + } } + } +} + +.main-header .dropdown-menu #hover_text_folder div .selectize-dropdown { + // due to long names, increase the width of folder dropdown in header + width: 150% !important; } + + +@media (max-width:1146px){ + .shiny-input-container{ + width: 200px !important; + } +} + +@media (max-width:973px){ + ul.menu { + &>div, .row { + flex-wrap: wrap; + justify-content: center + } + } +} \ No newline at end of file diff --git a/www/scss/section/_navigation.scss b/www/scss/section/_navigation.scss deleted file mode 100644 index c06cdc59..00000000 --- a/www/scss/section/_navigation.scss +++ /dev/null @@ -1,3 +0,0 @@ -.navbar { - min-height: 50px !important -} \ No newline at end of file diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss index cd482add..07810a2d 100644 --- a/www/scss/section/_sidebar.scss +++ b/www/scss/section/_sidebar.scss @@ -1,7 +1,7 @@ -.sidebar-toggle { - height: 15px; - padding-top: 25px !important -} +// .sidebar-toggle { +// height: 15px; +// padding-top: 25px !important +// } /*** Sidebar ***/ .left-side, .main-sidebar { From 6f9db3f42f9ed19147da351cb34ecaa826a4392c Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 13 May 2021 16:08:50 +0000 Subject: [PATCH 049/260] improve waiter, catch the errors on detecting no file in val --- functions/create_validation_msg.R | 12 +++-- functions/dc_waiter.R | 9 ++-- server.R | 81 +++++++++++++++++-------------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/functions/create_validation_msg.R b/functions/create_validation_msg.R index da5e5b86..7067a9ba 100644 --- a/functions/create_validation_msg.R +++ b/functions/create_validation_msg.R @@ -2,6 +2,8 @@ validationResult <- function(valRes, template, inFile) { validation_res <- NULL error_msg <- NULL help_msg <- NULL + outMsg <- NULL + errorDT <- NULL errorType <- NULL if (!is.null(inFile) & !is.null(template)) { @@ -69,14 +71,14 @@ validationResult <- function(valRes, template, inFile) { # errorDT <- errorDT[order(errorDT$Column),] } else { validation_res <- "valid" + errorType <- "No Error" } # combine all error messages into one, add an extra empty line to bottom - outMsg <- paste0( - "Your metadata is ", validation_res, " !!!", "

", - error_msg, "

", - help_msg - ) + outMsg <- paste0(c( + paste0("Your metadata is ", validation_res, " !!!"), + error_msg, help_msg + ), collapse = "

") } return(list( diff --git a/functions/dc_waiter.R b/functions/dc_waiter.R index c858aa5f..81375a66 100644 --- a/functions/dc_waiter.R +++ b/functions/dc_waiter.R @@ -3,7 +3,7 @@ dc_waiter <- function(stage = c("show", "update", "hide"), isLogin = FALSE, isPass = TRUE, usrName = NULL, - sleep = 2, msg = NULL) { + sleep = 2, msg = NULL, spin = NULL) { # validate arguments if (!is.logical(isLogin)) stop("isLogin must be a boolean") if (!is.logical(isPass)) stop("isPass must be a boolean") @@ -11,6 +11,8 @@ dc_waiter <- function(stage = c("show", "update", "hide"), if (!stage %in% c("show", "update", "hide")) { stop("Please provide a value for stage: 'show', 'update' or 'hide'.") } + if (is.null(msg)) msg <- "Loading ..." + if (is.null(spin)) spin <- spin_plus() # if "hide", proceed hiding process immediately and exit function if (stage == "hide") { @@ -52,16 +54,15 @@ dc_waiter <- function(stage = c("show", "update", "hide"), } } else { # other loading screens - if (is.null(msg)) msg <- "Loading ..." if (stage == "show") { waiter_show( - html = tagList(spin_plus(), br(), h3(msg)), + html = tagList(spin, br(), h3(msg)), color = "rgba(66, 72, 116, .9)" ) } else { Sys.sleep(2) # has to put at least 2s before to make update work - waiter_update(html = tagList(spin_loaders(32), br(), h3(msg))) + waiter_update(html = tagList(spin, br(), h3(msg))) Sys.sleep(sleep) waiter_hide() } diff --git a/server.R b/server.R index 7a440a3c..c2f1c981 100644 --- a/server.R +++ b/server.R @@ -206,53 +206,60 @@ shinyServer(function(input, output, session) { # loading screen for validating metadata dc_waiter("show", msg = "Validating...") - annotation_status <- metadata_model$validateModelManifest( - inFile$raw()$datapath, - template_schema_name + try( + silent = TRUE, + annotation_status <- metadata_model$validateModelManifest( + inFile$raw()$datapath, + template_schema_name + ) ) + # validation messages valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) - # output error messages as data table if it is invalid value type - - # renders in DT for preview - # render empty if error is not "invaid value" type - ifelse() will not work - show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) - DTableServer("tbl_validate", show_df, - options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE - ) - ) - - # highlight invalue cells in preview table - if (valRes$errorType == "Wrong Schema") { - DTableServer("tbl_preview", data = inFile$data(), highlight = "full") - } else { - DTableServer("tbl_preview", - data = inFile$data(), - highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + # if there is a file uploaded + if (!is.null(valRes$validationRes)) { + + # output error messages as data table if it is invalid value type + # render empty if error is not "invaid value" type - ifelse() will not work + show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) + DTableServer("tbl_validate", show_df, + options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE + ) ) - } - # validate_w$update(html = h3(waiter_msg)) - # TODO: fix issue: - # https://github.com/Sage-Bionetworks/data_curator/issues/160#issuecomment-828911353 - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), sleep = 2.5) + # highlight invalue cells in preview table + if (valRes$errorType == "Wrong Schema") { + DTableServer("tbl_preview", data = inFile$data(), highlight = "full") + } else { + DTableServer("tbl_preview", + data = inFile$data(), + highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + ) + } - if (valRes$validationRes == "valid") { - # show submit button - output$submit <- renderUI({ - actionButton("btn_submit", "Submit to Synapse") - }) + if (valRes$validationRes == "valid") { + # show submit button + output$submit <- renderUI({ + actionButton("btn_submit", "Submit to Synapse") + }) + output$val_gsheet <- renderUI(NULL) + dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) + } else { + # render gsheet button + output$val_gsheet <- renderUI({ + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) + }) + dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) + } } else { - # render gsheet button - output$val_gsheet <- renderUI({ - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) - }) + dc_waiter("hide") } + show("div_validate") }) From 13fb8ec20073b8340c85a5409ba6b9bc6f101132 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 13 May 2021 17:53:24 +0000 Subject: [PATCH 050/260] move folder_synID to download_btn and submit_btn, it seems like the folder_synID observation has high priority than updating folders, which will crash app --- functions/dc_waiter.R | 2 -- server.R | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/functions/dc_waiter.R b/functions/dc_waiter.R index 81375a66..9978b008 100644 --- a/functions/dc_waiter.R +++ b/functions/dc_waiter.R @@ -23,8 +23,6 @@ dc_waiter <- function(stage = c("show", "update", "hide"), # log in screen if (isLogin) { # The message on initial loading page are not customizable - if (!is.null(msg)) message("message for log in screen can be changed in dc_waiter.R") - if (stage == "show") { waiter_show_on_load( html = tagList( diff --git a/server.R b/server.R index b13be218..34b7dcf5 100644 --- a/server.R +++ b/server.R @@ -119,6 +119,7 @@ shinyServer(function(input, output, session) { }) }) + # Adjust header selection dropdown based on tabs observe({ if (input[["tabs"]] %in% c("tab_instructions", "tab_data")) { @@ -157,12 +158,6 @@ shinyServer(function(input, output, session) { } }) - # update selected folder ID - observeEvent(input$dropdown_folder, { - # TODO: check how different from using rectivateValues() - folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] - }) - ######## Update Template ######## # update selected schema template name observeEvent(input$dropdown_template, { @@ -186,6 +181,9 @@ shinyServer(function(input, output, session) { # loading screen for template link generation dc_waiter("show", msg = "Generating link...") + # update selected folder ID + folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] + if (is.null(input$dropdown_template)) { output$text_download <- renderUI({ tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) @@ -337,6 +335,8 @@ shinyServer(function(input, output, session) { # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] + # folder_ID has not been updated yet + if (is.null(folder_synID)) folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] # and adds entityID, saves it as synapse_storage_manifest.csv, then associates # with synapse files From 54f2327813feb82d3bce4e5b77e0617b0b2a6846 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 13 May 2021 18:47:46 +0000 Subject: [PATCH 051/260] fix 159 - app crash when empty manifest loaded --- functions/create_validation_msg.R | 2 +- modules/validation.R | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/functions/create_validation_msg.R b/functions/create_validation_msg.R index 7067a9ba..2d9983f4 100644 --- a/functions/create_validation_msg.R +++ b/functions/create_validation_msg.R @@ -6,7 +6,7 @@ validationResult <- function(valRes, template, inFile) { errorDT <- NULL errorType <- NULL - if (!is.null(inFile) & !is.null(template)) { + if (!is.null(inFile) && !is.null(template) && length(inFile) != 0) { if (length(valRes) != 0) { validation_res <- "invalid" # mismatched template index diff --git a/modules/validation.R b/modules/validation.R index 52e30498..7fc81c0c 100644 --- a/modules/validation.R +++ b/modules/validation.R @@ -11,9 +11,10 @@ ValidationMsgServer <- function(id, valRes, template, inFile) { id, function(input, output, session) { output$results <- renderUI({ - text_class <- ifelse(!is.null(valRes$validationRes) && valRes$validationRes == "valid", - "success_msg", "error_msg" - ) + text_class <- + ifelse(!is.null(valRes$validationRes) && valRes$validationRes == "valid" && length(valRes$validationRes) != 0, + "success_msg", "error_msg" + ) tagList( # TODO: remove first two checking once we set dropdown value as 1st selection by default @@ -23,6 +24,9 @@ ValidationMsgServer <- function(id, valRes, template, inFile) { if (is.null(inFile)) { span(class = text_class, HTML("Please upload a filled template !")) }, + if (length(inFile) == 0) { + span(class = text_class, HTML("File is empty. Please upload a filled template !")) + }, span(class = text_class, HTML(valRes$outMsg)) ) }) From e8a97aadc06eccc06971144f38e45cd32adb81c7 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 14 May 2021 12:25:02 +0000 Subject: [PATCH 052/260] change selectiveInput to selectInput --- server.R | 8 ++++---- ui.R | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server.R b/server.R index 34b7dcf5..5b67de8b 100644 --- a/server.R +++ b/server.R @@ -76,7 +76,7 @@ shinyServer(function(input, output, session) { # updates project dropdown lapply(c("header_dropdown_", "dropdown_"), function(x) { lapply(c(1, 3), function(i) { - updateSelectizeInput(session, paste0(x, datatypes[i]), + updateSelectInput(session, paste0(x, datatypes[i]), choices = sort(names(datatype_list[[i]])) ) }) @@ -113,7 +113,7 @@ shinyServer(function(input, output, session) { folders <- sort(names(datatype_list[["folders_namedList"]])) # updates foldernames - updateSelectizeInput(session, paste0(x, "folder"), + updateSelectInput(session, paste0(x, "folder"), choices = folders ) }) @@ -132,7 +132,7 @@ shinyServer(function(input, output, session) { lapply(datatypes, function(i) { observeEvent(input[[paste0("dropdown_", i)]], { - updateSelectizeInput(session, paste0("header_dropdown_", i), + updateSelectInput(session, paste0("header_dropdown_", i), selected = input[[paste0("dropdown_", i)]] ) }) @@ -151,7 +151,7 @@ shinyServer(function(input, output, session) { observeEvent(input$update_confirm, { if (input$update_confirm == TRUE) { lapply(datatypes, function(i) { - updateSelectizeInput(session, paste0("dropdown_", i), + updateSelectInput(session, paste0("dropdown_", i), selected = input[[paste0("header_dropdown_", i)]] ) }) diff --git a/ui.R b/ui.R index 2de0a98a..38ae12a1 100644 --- a/ui.R +++ b/ui.R @@ -26,7 +26,7 @@ ui <- shinydashboardPlus::dashboardPage( lapply(datatypes, function(x) { div( id = paste0("hover_text_", x), - selectizeInput( + selectInput( inputId = paste0("header_dropdown_", x), label = NULL, choices = character(0) @@ -123,12 +123,12 @@ ui <- shinydashboardPlus::dashboardPage( solidHeader = TRUE, width = 6, title = "Choose a Project and Folder: ", - selectizeInput( + selectInput( inputId = "dropdown_project", label = "Project:", choices = "Generating..." ), - selectizeInput( + selectInput( inputId = "dropdown_folder", label = "Folder:", choices = "Generating..." @@ -142,7 +142,7 @@ ui <- shinydashboardPlus::dashboardPage( solidHeader = TRUE, width = 6, title = "Choose a Metadata Template Type: ", - selectizeInput( + selectInput( inputId = "dropdown_template", label = "Template:", choices = "Generating..." From 068327ba5c5694c63cddb66515a6f69526e7d8a3 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 14 May 2021 13:13:14 +0000 Subject: [PATCH 053/260] change selectizeInput to selectInput --- server.R | 2 +- ui.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index 12203bb1..9e6ac509 100644 --- a/server.R +++ b/server.R @@ -104,7 +104,7 @@ shinyServer(function(input, output, session) { } ### updates project dropdown - updateSelectizeInput(session, "var", choices = sort(names(projects_namedList))) + updateSelectInput(session, "var", choices = sort(names(projects_namedList))) ### update waiter loading screen once login successful waiter_update(html = tagList( diff --git a/ui.R b/ui.R index 206586da..18006cef 100644 --- a/ui.R +++ b/ui.R @@ -115,7 +115,7 @@ ui <- dashboardPage( solidHeader = TRUE, width = 6, title = "Choose a Project and Folder: ", - selectizeInput( + selectInput( inputId = "var", label = "Project:", choices = "Generating..." From 6b6a4bc34b30389cdde6d0a720d8d252a0f164d7 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 1 Jun 2021 14:38:17 +0000 Subject: [PATCH 054/260] enhance sidebar UI --- functions/dc_waiter.R | 6 +- ui.R | 15 ++--- www/{ => img}/HTAN_text_logo.png | Bin www/{ => img}/loading.gif | Bin www/{ => img}/synapse_logo.png | Bin www/{ => img}/synapse_logo_blk.png | Bin www/scss/basic/_variables.scss | 19 ++++-- www/scss/section/_footer.scss | 57 ++++++++++++++---- www/scss/section/_sidebar.scss | 89 ++++++++++++++++++++++++++--- 9 files changed, 152 insertions(+), 34 deletions(-) rename www/{ => img}/HTAN_text_logo.png (100%) rename www/{ => img}/loading.gif (100%) rename www/{ => img}/synapse_logo.png (100%) rename www/{ => img}/synapse_logo_blk.png (100%) diff --git a/functions/dc_waiter.R b/functions/dc_waiter.R index 9978b008..cc186ec8 100644 --- a/functions/dc_waiter.R +++ b/functions/dc_waiter.R @@ -26,14 +26,14 @@ dc_waiter <- function(stage = c("show", "update", "hide"), if (stage == "show") { waiter_show_on_load( html = tagList( - img(src = "loading.gif"), + img(src = "img/loading.gif"), h4("Retrieving Synapse information...") ), color = "#424874" ) } else if (isPass) { waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), + img(src = "img/synapse_logo.png", height = "120px"), h3(sprintf("Welcome, %s!", usrName)) )) Sys.sleep(sleep) @@ -41,7 +41,7 @@ dc_waiter <- function(stage = c("show", "update", "hide"), } else { # ensure the synapse logo image is stored in www/ waiter_update(html = tagList( - img(src = "synapse_logo.png", height = "120px"), + img(src = "img/synapse_logo.png", height = "120px"), h3("Looks like you're not logged in!"), span( "Please ", a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" diff --git a/ui.R b/ui.R index f214e737..b10d9164 100644 --- a/ui.R +++ b/ui.R @@ -44,7 +44,7 @@ ui <- shinydashboardPlus::dashboardPage( target = "_blank", tags$img( height = "40px", alt = "HTAN LOGO", - src = "HTAN_text_logo.png" + src = "img/HTAN_text_logo.png" ) ) ) @@ -73,12 +73,13 @@ ui <- shinydashboardPlus::dashboardPage( tabName = "tab_upload", icon = icon("upload") ), - HTML( - "
- Supported by the Human Tumor Atlas Network
- (U24-CA233243-01)
- Powered by Sage Bionetworks -
" + # add sidebar footer here + tags$a( + id = "sidebar_footer", `data-toggle` = "tab", + tags$div(icon("heart")), + tags$footer(HTML('Supported by the Human Tumor Atlas Network
+ (U24-CA233243-01)
+ Powered by and Sage Bionetworks')) ) ) ), diff --git a/www/HTAN_text_logo.png b/www/img/HTAN_text_logo.png similarity index 100% rename from www/HTAN_text_logo.png rename to www/img/HTAN_text_logo.png diff --git a/www/loading.gif b/www/img/loading.gif similarity index 100% rename from www/loading.gif rename to www/img/loading.gif diff --git a/www/synapse_logo.png b/www/img/synapse_logo.png similarity index 100% rename from www/synapse_logo.png rename to www/img/synapse_logo.png diff --git a/www/synapse_logo_blk.png b/www/img/synapse_logo_blk.png similarity index 100% rename from www/synapse_logo_blk.png rename to www/img/synapse_logo_blk.png diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index 23079b5f..bb0db5d8 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -1,15 +1,24 @@ -// global variables are collected here +/*** Global Variables ***/ // colors +$primary_col: #605ca8; + +$htan_col: rgb(95,0,140); +$light: #f8f9fa; +$dark: #343a40; $error_col: #E53935; $success_col: #28a745; $notif_process_col: #F7DC6F; $notif_success_col: #82E0AA; -$footer_col: #465362; -$footer_bg_col: #D0D6DC; + +$sidebar_col: #191919; +$sidebar_pink: #A63FAA; +$footer_col: #878787; +$footer_bg_col: #202020; // box shadow -$simple_shadow: 0 10px 10px -5px; +$simple_shadow:rgba(50, 50, 105, 0.15) 0px 2px 5px 0px, + rgba(0, 0, 0, 0.05) 0px 1px 1px 0px; $float_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), - 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); \ No newline at end of file + 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); diff --git a/www/scss/section/_footer.scss b/www/scss/section/_footer.scss index c72f65eb..2bb0e8b7 100644 --- a/www/scss/section/_footer.scss +++ b/www/scss/section/_footer.scss @@ -1,12 +1,47 @@ -footer { - position: absolute; - padding: 18px; - left: 0; - bottom: 0; - width: 100%; - background-color: $footer_bg_col; - color: $footer_col; - font-size: 10px; - text-align: center; - z-index: 1000 +/*** Footer ***/ + +// footer in sidebar +#sidebar_footer { + position: absolute; + padding: 5px 15px 0px 15px; + left: 0; + bottom: 0; + width: 100%; + background-color: $footer_bg_col; + color: $footer_col; + font-size: 0.7em; + text-align: center; + z-index: 1000; + opacity: 0.8; + // white-space: nowrap; + overflow: hidden; + display: flex; + align-items: center; + + // heart color + div>.fa{ + visibility: hidden !important; + } + + footer { + padding: 10px 0; + margin-left: -20px; + line-height: 2; + } +} + +// sidebar footer when sidebar collapsed +.sidebar-collapse #sidebar_footer { + div>.fa{ + color: transparent; + padding: 2px; + transform: scale(2.2); + background: linear-gradient(45deg, purple, #7590d6); + -webkit-background-clip: text; + visibility: visible !important; + transition: 100ms ease-in-out; + } + footer { + visibility: hidden; + } } diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss index 07810a2d..8ff537ef 100644 --- a/www/scss/section/_sidebar.scss +++ b/www/scss/section/_sidebar.scss @@ -1,11 +1,84 @@ -// .sidebar-toggle { -// height: 15px; -// padding-top: 25px !important -// } - /*** Sidebar ***/ + .left-side, .main-sidebar { - padding-top: 80px; - font-weight: bold; - font-size: 1.1em + + padding-top: 80px; + font-weight: bold; + font-size: 1.1em +} + +// when sidebar is open +.main-sidebar { + + background-color: $sidebar_col !important; + + .sidebar { + padding: 0px; + + //icon color + .fa { + color: $sidebar_pink; + transition: 100ms; + } + + // add background img - synapse logo + &:before { + content: ''; + background-image: url('https://www.synapse.org/images/logo.svg'); + background-repeat: no-repeat; + position: absolute; + height: 260px; + top: 80px; + left: 0; + right: 0; + bottom: 0; + opacity: 0.4; + background-size: contain; + transform: scale(0.8); + } + + li>a { + color: #FFF !important; + border-radius: 8px; + border-left: none !important; + margin: 10px 5px 10px 5px; + filter: grayscale(100%) opacity(0.7); + transition: 100ms; + + &:hover { + background: rgba(104, 103, 103, 0.3) !important; + filter: grayscale(0%) opacity(1); + } + + i { + margin-left: -3px; //move icon to left a bit + } + } + + li.active>a { + background-color: rgba($primary_col, 0.8) !important; + filter: unset; + // box-shadow: 0 0px 20px 0px $htan_col; + + .fa{ + color: #FFF + } + } + } +} + +// when sidebar is collapsed +.sidebar-collapse .sidebar{ + + &:before { + visibility: hidden; + } + + span { + visibility: hidden; + } + + li>a { + margin-right: 5px !important; + } } \ No newline at end of file From a329b3e84661a859fe87181460bd27c27ca2fa10 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 1 Jun 2021 16:58:41 +0000 Subject: [PATCH 055/260] bg color and box change in content --- www/scss/basic/_button.scss | 2 +- www/scss/basic/_variables.scss | 13 +++++++-- www/scss/section/_content.scss | 52 +++++++++++++++++++++++++++++++++- www/scss/section/_header.scss | 24 ++++++++++++++-- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 3d337387..370517e3 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -60,7 +60,7 @@ &:hover, &:focus { transform: scale(1.01); font-size: 1.02em; - box-shadow: $float_shadow; + box-shadow: $primary_shadow; border-radius: 20px; transition: transform 50ms; } diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index bb0db5d8..665a37c3 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -11,14 +11,21 @@ $success_col: #28a745; $notif_process_col: #F7DC6F; $notif_success_col: #82E0AA; +$bg_primary_col: #FFF; $sidebar_col: #191919; $sidebar_pink: #A63FAA; $footer_col: #878787; $footer_bg_col: #202020; // box shadow +$primary_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), + 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), + 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); $simple_shadow:rgba(50, 50, 105, 0.15) 0px 2px 5px 0px, rgba(0, 0, 0, 0.05) 0px 1px 1px 0px; -$float_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), - 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), - 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); +$float_shadow: 0 16px 32px 0 rgba(0,0,0,0.2); + +@mixin header_bg { + background-image: linear-gradient(180deg, $sidebar_col,transparent); + background-color: $primary_col; +} \ No newline at end of file diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 7e862fea..3cdadc8f 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -1,9 +1,59 @@ // specify div +.content-wrapper { + // overflow-y: visible !important; + background-color: $bg_primary_col; + // padding: 10px; +} + .content { - padding-top: 50px; + padding-top: 50px; +} + +.tab-content { + .title h2 { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); // line below title + padding-bottom: 16px; + } } +// TODO: Make it function or use existing function +.box-solid.box-primary { + border-radius: 10px !important; + background-color: $bg_primary_col ; + border: 0px !important; + top: 15px; // move down to lower than header + box-shadow: $primary_shadow; + transition: 200ms; + -webkit-transition-property: box-shadow, transform; + transition-property: box-shadow, transform; + + &:hover { + box-shadow: $float_shadow; + -webkit-transform: scale(1.01); + transform: scale(1.01); + } + /*#show_template_box { + background-color: $dark; + margin: 50px 0px 5px; + } + */ + .box-header { + border-radius: 10px; + // background: $grad_primary_col !important; + // box-shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), + // 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), + // 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); + margin: 0 5px 5px 5px; + top: -7px; + } + + // help msg + .help-block { + margin: 8px 5px 2.5px 5px ; + } + +} #div_download, #div_validate, #div_val_gsheet { font-size: 18px; diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index d6ef4c5a..959681b2 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -1,5 +1,10 @@ +.logo, .navbar { + background-color: transparent !important; +} + .main-header { - + @include header_bg; + .logo { font-size: 1.8em; } @@ -11,9 +16,24 @@ padding: 0 15px; } + // adjust custom dropdown color effect + .navbar .nav { + + a:hover { + background: $primary_col !important; + } + .open>a { + background-color: $primary_col !important; + + &:focus, &:hover { + background-color: $primary_col !important; + } + } + } + .dropdown-menu { left: auto !important; // stick with the button left - box-shadow: $float_shadow; + box-shadow: $primary_shadow; animation: fadeIn 100ms; From c950f1fdae1e4c6b614671b4a8a52c85f43ff448 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 2 Jun 2021 14:04:41 +0000 Subject: [PATCH 056/260] header change x2 --- www/scss/basic/_variables.scss | 16 +++++++++------- www/scss/section/_header.scss | 15 ++++++++------- www/scss/section/_sidebar.scss | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index 665a37c3..c5ec0c01 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -1,22 +1,24 @@ /*** Global Variables ***/ -// colors +// basic color $primary_col: #605ca8; - $htan_col: rgb(95,0,140); $light: #f8f9fa; $dark: #343a40; -$error_col: #E53935; -$success_col: #28a745; -$notif_process_col: #F7DC6F; -$notif_success_col: #82E0AA; +$glass_grey: rgba(104, 103, 103, 0.3); +// section color $bg_primary_col: #FFF; $sidebar_col: #191919; $sidebar_pink: #A63FAA; $footer_col: #878787; $footer_bg_col: #202020; +// msg color +$error_col: #E53935; +$success_col: #28a745; +$notif_process_col: #F7DC6F; +$notif_success_col: #82E0AA; // box shadow $primary_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), @@ -26,6 +28,6 @@ $simple_shadow:rgba(50, 50, 105, 0.15) 0px 2px 5px 0px, $float_shadow: 0 16px 32px 0 rgba(0,0,0,0.2); @mixin header_bg { - background-image: linear-gradient(180deg, $sidebar_col,transparent); + background-image: linear-gradient(450deg, $sidebar_col, $htan_col, transparent); background-color: $primary_col; } \ No newline at end of file diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index 959681b2..848b9ae6 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -7,6 +7,7 @@ .logo { font-size: 1.8em; + font-weight: 600; } #HTAN_logo a { @@ -17,16 +18,16 @@ } // adjust custom dropdown color effect - .navbar .nav { - + .navbar { a:hover { - background: $primary_col !important; + background-color: $glass_grey !important; } - .open>a { - background-color: $primary_col !important; + // custom dropdown - leftUI + .open>a { // when the box open + background-color: $glass_grey !important; &:focus, &:hover { - background-color: $primary_col !important; + background-color: $glass_grey !important; } } } @@ -77,7 +78,7 @@ ul.menu { &>div, .row { flex-wrap: wrap; - justify-content: center + // justify-content: center } } } \ No newline at end of file diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss index 8ff537ef..46e29e02 100644 --- a/www/scss/section/_sidebar.scss +++ b/www/scss/section/_sidebar.scss @@ -46,7 +46,7 @@ transition: 100ms; &:hover { - background: rgba(104, 103, 103, 0.3) !important; + background: $glass_grey !important; filter: grayscale(0%) opacity(1); } From 47e6d218444cb71d73ab6b804b65d8386b4e3e2c Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 2 Jun 2021 16:29:32 +0000 Subject: [PATCH 057/260] content change x2 --- modules/switch_tabs.R | 42 -------------------- server.R | 7 ++-- ui.R | 7 ++-- www/scss/basic/_button.scss | 71 ---------------------------------- www/scss/basic/_variables.scss | 1 + www/scss/section/_content.scss | 44 +++++++++++---------- 6 files changed, 33 insertions(+), 139 deletions(-) delete mode 100644 modules/switch_tabs.R delete mode 100644 www/scss/basic/_button.scss diff --git a/modules/switch_tabs.R b/modules/switch_tabs.R deleted file mode 100644 index 03a77794..00000000 --- a/modules/switch_tabs.R +++ /dev/null @@ -1,42 +0,0 @@ -# This is the module to create one/two buttons to switch to previous/next tab -# TODO: Add more descriptions - -tagID <- c("Next", "Prev") # Do not change order, to ensure server works properly - -switchTabUI <- function(id, direction = c("left", "right", "both")) { - - # namespace - ns <- NS(id) - # if we put buttons in server, buttons will change after observing tabs' change delay - # which cause some add-remove tranisition in delay - # now, put buttons in UI - btn_prev <- actionButton(ns(tagID[2]), HTML("
"), style = "margin-top: 20px;") - btn_next <- actionButton(ns(tagID[1]), HTML("
"), style = "margin-top: 20px;") - fluidRow( - if (direction == "right") { - column(1, offset = 10, btn_next) - } else if (direction == "left") { - column(1, offset = 1, btn_prev) - } else { - div(column(1, offset = 1, btn_prev), column(1, offset = 8, btn_next)) - } - ) -} - - -switchTabServer <- function(id, tabId, tab, tabList, parent) { - moduleServer( - id, - function(input, output, session) { - lapply(c(-1, 1), function(i) { - tagName <- tagID[i] - observeEvent(input[[tagName]], { - current_tab <- which(tabList == tab) - # need to use parent session to update tab - # TODO: figure out how to call parent inputs in module to minimize args - updateTabItems(parent, tabId, selected = tabList[current_tab + i]) - }) - }) - } - ) -} diff --git a/server.R b/server.R index 87c8adc7..261eb7aa 100644 --- a/server.R +++ b/server.R @@ -62,9 +62,9 @@ shinyServer(function(input, output, session) { syn_login(sessionToken = input$cookie, rememberMe = FALSE) # welcome message - output$title <- renderUI({ - titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) - }) + # output$title <- renderUI({ + # titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) + # }) # updating global vars with values for projects synStore_obj <<- synapse_driver(token = input$cookie) @@ -443,3 +443,4 @@ shinyServer(function(input, output, session) { } }) }) + diff --git a/ui.R b/ui.R index b10d9164..f58bc211 100644 --- a/ui.R +++ b/ui.R @@ -53,6 +53,7 @@ ui <- shinydashboardPlus::dashboardPage( width = 250, sidebarMenu( id = "tabs", + # uiOutput("title"), menuItem( "Instructions", tabName = "tab_instructions", @@ -86,8 +87,7 @@ ui <- shinydashboardPlus::dashboardPage( dashboardBody( tags$head( tags$style(sass(sass_file("www/scss/main.scss"))), - singleton(includeScript("www/js/readCookie.js")), - singleton(includeScript("www/js/onclick.js")) + singleton(includeScript("www/js/readCookie.js")) ), use_notiflix_report(), use_waiter(), @@ -95,7 +95,6 @@ ui <- shinydashboardPlus::dashboardPage( # First tab content tabItem( tabName = "tab_instructions", - uiOutput("title"), h2("Instructions for the Data Curator App:"), h3( "1. Go to", @@ -191,6 +190,7 @@ ui <- shinydashboardPlus::dashboardPage( box( title = "Metadata Preview", solidHeader = TRUE, + collapsible = TRUE, status = "primary", width = 12, DTableUI("tbl_preview") @@ -199,6 +199,7 @@ ui <- shinydashboardPlus::dashboardPage( title = "Validate Filled Metadata", status = "primary", solidHeader = TRUE, + collapsible = TRUE, width = 12, actionButton("btn_validate", "Validate Metadata"), hidden( diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss deleted file mode 100644 index 370517e3..00000000 --- a/www/scss/basic/_button.scss +++ /dev/null @@ -1,71 +0,0 @@ -// styles of button are collected in here - -// https://paigen11.medium.com/ -#btn_header_update -{ - position: relative; - background: #27022d; - color: #fff; - text-decoration: none; - letter-spacing: 1px; - border-radius: 5px; - box-shadow: $simple_shadow; - transition: 500ms; - overflow: hidden; - // for background color shift - background-image: (linear-gradient(270deg, #8e9ac2, #42579a)); - background-size: 400% 400%; - animation: TransitioningBackground 10s ease infinite; - - &:hover { - background-image: (linear-gradient(to left, #2d8fe5, #d155b8)); - transform: scale(1.05); - cursor: pointer; - } - // shine animation left side - &::before { - content: ''; - display: block; - position: absolute; - background: rgba(255, 255, 255, 0.5); - width: 60px; - height: 100%; - top: 0; - filter: blur(30px); - transform: translateX(-100px) skewX(-15deg); - } - // shine animation right side - &::after { - content: ''; - display: block; - position: absolute; - background: rgba(255, 255, 255, 0.2); - width: 30px; - height: 100%; - top: 0; - filter: blur(5px); - transform: translateX(-100px) skewX(-15deg); - } - - &::before, - &::after { - transform: translateX(300px) skewX(-15deg); - transition: 0.7s; - } -} - - -// dropdown hover effect -.option { - &:hover, &:focus { - transform: scale(1.01); - font-size: 1.02em; - box-shadow: $primary_shadow; - border-radius: 20px; - transition: transform 50ms; - } -} - - - - diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index c5ec0c01..812dec96 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -4,6 +4,7 @@ $primary_col: #605ca8; $htan_col: rgb(95,0,140); $light: #f8f9fa; +$light2: #f4f4f4; $dark: #343a40; $glass_grey: rgba(104, 103, 103, 0.3); diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 3cdadc8f..d26f6786 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -8,20 +8,19 @@ .content { padding-top: 50px; -} -.tab-content { - .title h2 { - border-bottom: 1px solid rgba(0, 0, 0, 0.12); // line below title + .tab-content h2 { + border-bottom: 1px solid $light2; // line below title padding-bottom: 16px; } } +// box effect // TODO: Make it function or use existing function -.box-solid.box-primary { +.box-primary { border-radius: 10px !important; background-color: $bg_primary_col ; - border: 0px !important; + border-color: rgba($primary_col, 0.8) !important; top: 15px; // move down to lower than header box-shadow: $primary_shadow; transition: 200ms; @@ -32,27 +31,32 @@ box-shadow: $float_shadow; -webkit-transform: scale(1.01); transform: scale(1.01); - } - /*#show_template_box { - background-color: $dark; - margin: 50px 0px 5px; - } - */ - .box-header { - border-radius: 10px; - // background: $grad_primary_col !important; - // box-shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), - // 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), - // 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); - margin: 0 5px 5px 5px; - top: -7px; + z-index: 100; } // help msg .help-block { margin: 8px 5px 2.5px 5px ; } +} +// if use solidHeader box +.box-solid { + @extend .box-primary; + border: 0px !important; + .box-header { + border-radius: 10px; + background: rgba($primary_col, 0.8) !important; + // box-shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), + // 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), + // 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); + margin: 0 5px 5px 5px; + top: -7px; + + .box-tools .btn{ + background: rgba($primary_col, 0.8); + } + } } #div_download, #div_validate, #div_val_gsheet { From 3a2df3b87772d8b215ad8db6b2f89b49f9a53fab Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 2 Jun 2021 17:41:35 +0000 Subject: [PATCH 058/260] remove solid header, increase title size --- ui.R | 7 ------- www/scss/basic/_variables.scss | 6 ++++-- www/scss/section/_content.scss | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/ui.R b/ui.R index f58bc211..dd398160 100644 --- a/ui.R +++ b/ui.R @@ -120,7 +120,6 @@ ui <- shinydashboardPlus::dashboardPage( fluidRow( box( status = "primary", - solidHeader = TRUE, width = 6, title = "Choose a Project and Folder: ", selectInput( @@ -139,7 +138,6 @@ ui <- shinydashboardPlus::dashboardPage( ), box( status = "primary", - solidHeader = TRUE, width = 6, title = "Choose a Metadata Template Type: ", selectInput( @@ -160,7 +158,6 @@ ui <- shinydashboardPlus::dashboardPage( box( title = "Get Link, Annotate, and Download Template as CSV", status = "primary", - solidHeader = TRUE, width = 12, actionButton("btn_download", "Click to Generate Google Sheets Template"), hidden( @@ -182,14 +179,12 @@ ui <- shinydashboardPlus::dashboardPage( fluidRow( box( title = "Upload Filled Metadata as a CSV", - solidHeader = TRUE, status = "primary", width = 12, csvInfileUI("inputFile") ), box( title = "Metadata Preview", - solidHeader = TRUE, collapsible = TRUE, status = "primary", width = 12, @@ -198,7 +193,6 @@ ui <- shinydashboardPlus::dashboardPage( box( title = "Validate Filled Metadata", status = "primary", - solidHeader = TRUE, collapsible = TRUE, width = 12, actionButton("btn_validate", "Validate Metadata"), @@ -219,7 +213,6 @@ ui <- shinydashboardPlus::dashboardPage( box( title = "Submit Validated Metadata to Synapse", status = "primary", - solidHeader = TRUE, width = 12, uiOutput("btn_submit") ) diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index 812dec96..e961d1f9 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -9,7 +9,7 @@ $dark: #343a40; $glass_grey: rgba(104, 103, 103, 0.3); // section color -$bg_primary_col: #FFF; +$bg_primary_col: $light; $sidebar_col: #191919; $sidebar_pink: #A63FAA; $footer_col: #878787; @@ -26,7 +26,9 @@ $primary_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); $simple_shadow:rgba(50, 50, 105, 0.15) 0px 2px 5px 0px, rgba(0, 0, 0, 0.05) 0px 1px 1px 0px; -$float_shadow: 0 16px 32px 0 rgba(0,0,0,0.2); +$float_shadow: 0 16px 32px 0 rgba(0, 0, 0, 0.2); +$float_shadow2: 0 5px 11px 0 rgba(0, 0,0, 0.18), + 0 4px 15px 0 rgba(0, 0, 0, 0.15); @mixin header_bg { background-image: linear-gradient(450deg, $sidebar_col, $htan_col, transparent); diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index d26f6786..73d476f4 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -19,7 +19,7 @@ // TODO: Make it function or use existing function .box-primary { border-radius: 10px !important; - background-color: $bg_primary_col ; + background-color: #FFF ; border-color: rgba($primary_col, 0.8) !important; top: 15px; // move down to lower than header box-shadow: $primary_shadow; @@ -28,15 +28,19 @@ transition-property: box-shadow, transform; &:hover { - box-shadow: $float_shadow; - -webkit-transform: scale(1.01); - transform: scale(1.01); - z-index: 100; + box-shadow: $float_shadow; + -webkit-transform: scale(1.001); + transform: scale(1.001); + z-index: 100; } + .box-title { + font-size: 1.6em; + } + // help msg .help-block { - margin: 8px 5px 2.5px 5px ; + margin: 8px 5px 2.5px 5px ; } } @@ -47,9 +51,6 @@ .box-header { border-radius: 10px; background: rgba($primary_col, 0.8) !important; - // box-shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), - // 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), - // 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); margin: 0 5px 5px 5px; top: -7px; From 5358baa4165caed30a881070efd2b757c66002dc Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 2 Jun 2021 17:42:18 +0000 Subject: [PATCH 059/260] buttons change --- modules/switch_tabs.R | 42 +++++++++ www/scss/basic/_button.scss | 165 ++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 modules/switch_tabs.R create mode 100644 www/scss/basic/_button.scss diff --git a/modules/switch_tabs.R b/modules/switch_tabs.R new file mode 100644 index 00000000..97e2e675 --- /dev/null +++ b/modules/switch_tabs.R @@ -0,0 +1,42 @@ +# This is the module to create one/two buttons to switch to previous/next tab +# TODO: Add more descriptions + +tagID <- c("Next", "Prev") # Do not change order, to ensure server works properly + +switchTabUI <- function(id, direction = c("left", "right", "both")) { + + # namespace + ns <- NS(id) + # if we put buttons in server, buttons will change after observing tabs' change delay + # which cause some add-remove tranisition in delay + # now, put buttons in UI + btn_prev <- actionButton(ns(tagID[2]), lapply(1:3, function(i) tags$i(class="fa fa-angle-left")), style = "margin-top: 20px;") + btn_next <- actionButton(ns(tagID[1]), lapply(1:3, function(i) tags$i(class="fa fa-angle-right")), style = "margin-top: 20px;") + fluidRow( + if (direction == "right") { + column(1, offset = 10, btn_next) + } else if (direction == "left") { + column(1, offset = 1, btn_prev) + } else { + div(column(1, offset = 1, btn_prev), column(1, offset = 8, btn_next)) + } + ) +} + + +switchTabServer <- function(id, tabId, tab, tabList, parent) { + moduleServer( + id, + function(input, output, session) { + lapply(c(-1, 1), function(i) { + tagName <- tagID[i] + observeEvent(input[[tagName]], { + current_tab <- which(tabList == tab) + # need to use parent session to update tab + # TODO: figure out how to call parent inputs in module to minimize args + updateTabItems(parent, tabId, selected = tabList[current_tab + i]) + }) + }) + } + ) +} diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss new file mode 100644 index 00000000..1ee04a21 --- /dev/null +++ b/www/scss/basic/_button.scss @@ -0,0 +1,165 @@ +// styles of button are collected in here + +// https://paigen11.medium.com/ +#btn_header_update { + position: relative; + background: #27022d; + color: #fff; + text-decoration: none; + letter-spacing: 1px; + border-radius: 5px; + box-shadow: $simple_shadow; + transition: 500ms; + overflow: hidden; + // for background color shift + background-image: (linear-gradient(270deg, #8e9ac2, #42579a)); + background-size: 400% 400%; + animation: TransitioningBackground 10s ease infinite; + + &:hover { + background-image: (linear-gradient(to left, #2d8fe5, #d155b8)); + transform: scale(1.05); + cursor: pointer; + } + // shine animation left side + &::before { + content: ''; + display: block; + position: absolute; + background: rgba(255, 255, 255, 0.5); + width: 60px; + height: 100%; + top: 0; + filter: blur(30px); + transform: translateX(-100px) skewX(-15deg); + } + // shine animation right side + &::after { + content: ''; + display: block; + position: absolute; + background: rgba(255, 255, 255, 0.2); + width: 30px; + height: 100%; + top: 0; + filter: blur(5px); + transform: translateX(-100px) skewX(-15deg); + } + + &::before, &::after { + transform: translateX(300px) skewX(-15deg); + transition: 0.7s; + } +} + + +// dropdown hover effect +.option { + &:hover, &:focus { + transform: scale(1.01); + font-size: 1.02em; + box-shadow: $primary_shadow; + border-radius: 20px; + transition: transform 50ms; + } +} + +// previous - next button +@for $i from 1 through 3 { + #switchTab#{$i}-Prev, #switchTab#{$i}-Next { + background: $bg_primary_col; + color: #000; + display: flex; + justify-content: center; + align-items: center; + width: 70px; + height: 40px ; + margin-top: 10px; + margin-bottom: 20px; + padding: 5px; + border-radius: 10px; + box-shadow: $simple_shadow; + + .fa { + margin: 1.5px; + font-size: 20px; + } + } +} + +@for $i from 1 through 3 { + #switchTab#{$i}-Prev:hover { + .fa { + animation: move-left 2s infinite; + &:nth-child(2) { + animation-delay: -0.2s; + } + &:nth-child(1) { + animation-delay: -0.4s; + } + } + } +} + +@for $i from 1 through 3 { + #switchTab#{$i}-Next:hover { + .fa { + animation: move-right 2s infinite; + &:nth-child(2) { + animation-delay: -0.2s; + } + &:nth-child(3) { + animation-delay: -0.4s; + } + } + } +} + +@keyframes move-left { + 0% { + opacity: 0; + transform: translateX(10px); + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + transform: translateX(-10px); + } +} + +@keyframes move-right { + 0% { + opacity: 0; + transform: translateX(-10px); + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + transform: translateX(10px); + } +} + +// simple float effect +#btn_download, #btn_validate, #btn_val_gsheet, #btn_submit { + background: $primary_col; + color: #fff; + border-color: transparent; + border-radius: 40px; + cursor: pointer; + + &:hover { + box-shadow: $float_shadow2; + -webkit-transition: box-shadow .4s ease-out; + transition: box-shadow .4s ease-out; + } +} + +// upload button +.shiny-file-input-progress .progress-bar { + background: $primary_col; + border-radius: 40px; +} From 89f49fe76511c1668bffe2aea896eefffc94a23e Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 3 Jun 2021 03:37:06 +0000 Subject: [PATCH 060/260] format .R and .scss --- modules/switch_tabs.R | 5 +- modules/validation.R | 2 +- server.R | 7 +- ui.R | 13 +++- www/scss/basic/_animation.scss | 60 ++++++++++++++- www/scss/basic/_button.scss | 130 ++++++++++++++------------------- www/scss/basic/_message.scss | 32 ++++---- www/scss/basic/_variables.scss | 4 +- www/scss/section/_content.scss | 9 ++- www/scss/section/_footer.scss | 2 + www/scss/section/_header.scss | 16 +++- www/scss/section/_sidebar.scss | 2 - 12 files changed, 170 insertions(+), 112 deletions(-) diff --git a/modules/switch_tabs.R b/modules/switch_tabs.R index 97e2e675..7705cdd4 100644 --- a/modules/switch_tabs.R +++ b/modules/switch_tabs.R @@ -7,11 +7,12 @@ switchTabUI <- function(id, direction = c("left", "right", "both")) { # namespace ns <- NS(id) + tags$head() # if we put buttons in server, buttons will change after observing tabs' change delay # which cause some add-remove tranisition in delay # now, put buttons in UI - btn_prev <- actionButton(ns(tagID[2]), lapply(1:3, function(i) tags$i(class="fa fa-angle-left")), style = "margin-top: 20px;") - btn_next <- actionButton(ns(tagID[1]), lapply(1:3, function(i) tags$i(class="fa fa-angle-right")), style = "margin-top: 20px;") + btn_prev <- actionButton(ns(tagID[2]), class = "switch-tab-prev", lapply(1:3, function(i) tags$i(class = "fa fa-angle-left"))) + btn_next <- actionButton(ns(tagID[1]), class = "switch-tab-next", lapply(1:3, function(i) tags$i(class = "fa fa-angle-right"))) fluidRow( if (direction == "right") { column(1, offset = 10, btn_next) diff --git a/modules/validation.R b/modules/validation.R index 7fc81c0c..fc34fd46 100644 --- a/modules/validation.R +++ b/modules/validation.R @@ -24,7 +24,7 @@ ValidationMsgServer <- function(id, valRes, template, inFile) { if (is.null(inFile)) { span(class = text_class, HTML("Please upload a filled template !")) }, - if (length(inFile) == 0) { + if (!is.null(inFile) & length(inFile) == 0) { span(class = text_class, HTML("File is empty. Please upload a filled template !")) }, span(class = text_class, HTML(valRes$outMsg)) diff --git a/server.R b/server.R index 261eb7aa..a5d7fc5a 100644 --- a/server.R +++ b/server.R @@ -295,14 +295,16 @@ shinyServer(function(input, output, session) { if (valRes$validationRes == "valid") { # show submit button output$submit <- renderUI({ - actionButton("btn_submit", "Submit to Synapse") + actionButton("btn_submit", "Submit to Synapse", class = "btn-primary-color") }) output$val_gsheet <- renderUI(NULL) dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) } else { # render gsheet button output$val_gsheet <- renderUI({ - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", + class = "btn-primary-color", icon = icon("table") + ) }) dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) } @@ -443,4 +445,3 @@ shinyServer(function(input, output, session) { } }) }) - diff --git a/ui.R b/ui.R index dd398160..f4a2c071 100644 --- a/ui.R +++ b/ui.R @@ -33,7 +33,10 @@ ui <- shinydashboardPlus::dashboardPage( ) ) }), - actionButton(inputId = "btn_header_update", label = NULL, icon = icon("sync-alt")) + actionButton( + inputId = "btn_header_update", class = "btn-shiny-effect", + label = NULL, icon = icon("sync-alt") + ) ) ) ), @@ -159,7 +162,9 @@ ui <- shinydashboardPlus::dashboardPage( title = "Get Link, Annotate, and Download Template as CSV", status = "primary", width = 12, - actionButton("btn_download", "Click to Generate Google Sheets Template"), + actionButton("btn_download", "Click to Generate Google Sheets Template", + class = "btn-primary-color" + ), hidden( div( id = "div_download", @@ -195,7 +200,9 @@ ui <- shinydashboardPlus::dashboardPage( status = "primary", collapsible = TRUE, width = 12, - actionButton("btn_validate", "Validate Metadata"), + actionButton("btn_validate", "Validate Metadata", + class = "btn-primary-color" + ), hidden( div( id = "div_validate", diff --git a/www/scss/basic/_animation.scss b/www/scss/basic/_animation.scss index 83e6c4b4..28a77cc4 100644 --- a/www/scss/basic/_animation.scss +++ b/www/scss/basic/_animation.scss @@ -1,18 +1,70 @@ +/*** Animation ***/ + @keyframes fadeIn { - 0% {transform:scale(0); opacity: 0} - 30% {transform: scale(0.3)} - 70% {transform: scale(0.7)} - 100% {transform: scale(1); opacity: 1} + + 0% { + transform:scale(0); opacity: 0 + } + + 30% { + transform: scale(0.3) + } + + 70% { + transform: scale(0.7) + } + 100% { + transform: scale(1); opacity: 1 + } } +// update button animation @keyframes TransitioningBackground { + 0% { background-position: 1% 0%; } + 50% { background-position: 99% 100%; } + 100% { background-position: 1% 0%; } +} + +// switch tab animation +@keyframes move-left { + + 0% { + opacity: 0; + transform: translateX(10px); + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateX(-10px); + } +} + +@keyframes move-right { + + 0% { + opacity: 0; + transform: translateX(-10px); + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateX(10px); + } } \ No newline at end of file diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 1ee04a21..7bf7372f 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -1,7 +1,8 @@ -// styles of button are collected in here +/*** Buttons ***/ -// https://paigen11.medium.com/ -#btn_header_update { +// update button +// refer to https://paigen11.medium.com/ +.btn-shiny-effect { position: relative; background: #27022d; color: #fff; @@ -12,15 +13,17 @@ transition: 500ms; overflow: hidden; // for background color shift - background-image: (linear-gradient(270deg, #8e9ac2, #42579a)); + background-image: linear-gradient(270deg, #8e9ac2, #42579a); background-size: 400% 400%; animation: TransitioningBackground 10s ease infinite; &:hover { - background-image: (linear-gradient(to left, #2d8fe5, #d155b8)); + color: #fff; + background-image: linear-gradient(to left, #2d8fe5, #d155b8); transform: scale(1.05); cursor: pointer; } + // shine animation left side &::before { content: ''; @@ -33,6 +36,7 @@ filter: blur(30px); transform: translateX(-100px) skewX(-15deg); } + // shine animation right side &::after { content: ''; @@ -52,9 +56,9 @@ } } - // dropdown hover effect .option { + &:hover, &:focus { transform: scale(1.01); font-size: 1.02em; @@ -65,86 +69,60 @@ } // previous - next button -@for $i from 1 through 3 { - #switchTab#{$i}-Prev, #switchTab#{$i}-Next { - background: $bg_primary_col; - color: #000; - display: flex; - justify-content: center; - align-items: center; - width: 70px; - height: 40px ; - margin-top: 10px; - margin-bottom: 20px; - padding: 5px; - border-radius: 10px; - box-shadow: $simple_shadow; - - .fa { - margin: 1.5px; - font-size: 20px; - } +.switch-tab-prev, .switch-tab-next { + background: #fff; + color: #000; + display: flex; + justify-content: center; + align-items: center; + width: 70px; + height: 40px; + margin: 40px 15px; + padding: 5px; + border-radius: 10px; + box-shadow: $simple_shadow; + + &:hover { + background: #fff; + } + + .fa { + margin: 1.5px; + font-size: 20px; } } -@for $i from 1 through 3 { - #switchTab#{$i}-Prev:hover { - .fa { - animation: move-left 2s infinite; - &:nth-child(2) { - animation-delay: -0.2s; - } - &:nth-child(1) { - animation-delay: -0.4s; - } +.switch-tab-prev:hover { + .fa { + animation: move-left 2s infinite; + &:nth-child(2) { + animation-delay: -0.2s; + } + &:nth-child(1) { + animation-delay: -0.4s; } } } -@for $i from 1 through 3 { - #switchTab#{$i}-Next:hover { - .fa { - animation: move-right 2s infinite; - &:nth-child(2) { - animation-delay: -0.2s; - } - &:nth-child(3) { - animation-delay: -0.4s; - } - } - } -} +.switch-tab-next:hover { -@keyframes move-left { - 0% { - opacity: 0; - transform: translateX(10px); - } - 50% { - opacity: 1; - } - 100% { - opacity: 0; - transform: translateX(-10px); - } -} + .fa { + animation: move-right 2s infinite; + + &:nth-child(2) { + animation-delay: -0.2s; + } -@keyframes move-right { - 0% { - opacity: 0; - transform: translateX(-10px); - } - 50% { - opacity: 1; - } - 100% { - opacity: 0; - transform: translateX(10px); - } + &:nth-child(3) { + animation-delay: -0.4s; + } + } } + // simple float effect -#btn_download, #btn_validate, #btn_val_gsheet, #btn_submit { +// #btn_download, #btn_validate, #btn_val_gsheet, #btn_submit +.btn-primary-color { background: $primary_col; color: #fff; border-color: transparent; @@ -152,13 +130,15 @@ cursor: pointer; &:hover { + background: $primary_col; + color: #fff; box-shadow: $float_shadow2; -webkit-transition: box-shadow .4s ease-out; transition: box-shadow .4s ease-out; } } -// upload button +// upload progress button .shiny-file-input-progress .progress-bar { background: $primary_col; border-radius: 40px; diff --git a/www/scss/basic/_message.scss b/www/scss/basic/_message.scss index 3e209e8b..8740a429 100644 --- a/www/scss/basic/_message.scss +++ b/www/scss/basic/_message.scss @@ -1,32 +1,36 @@ -// styles of messages are collected in here -// (e.g pop-up messages/notification messages et.al) +/*** message ***/ // message .message-menu { - padding-top: 5px + padding-top: 5px } // validation message .error_msg { - color: $error_col; + color: $error_col; } .success_msg { - color: $success_col; + color: $success_col; } // notification .shiny-notification { - position:fixed; - bottom: 0; - right: 0; - width: 100%; + position:fixed; + bottom: 0; + right: 0; + width: 100%; } #shiny-notification-error { - height: 500px; - padding :20px; - display: table-cell + height: 500px; + padding :20px; + display: table-cell } -#shiny-notification-processing {background-color: $notif_process_col} -#shiny-notification-success {background-color: $notif_success_col} \ No newline at end of file +#shiny-notification-processing { + background-color: $notif_process_col +} + +#shiny-notification-success { + background-color: $notif_success_col +} \ No newline at end of file diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index e961d1f9..76a46442 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -15,11 +15,12 @@ $sidebar_pink: #A63FAA; $footer_col: #878787; $footer_bg_col: #202020; -// msg color +// message color $error_col: #E53935; $success_col: #28a745; $notif_process_col: #F7DC6F; $notif_success_col: #82E0AA; + // box shadow $primary_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), @@ -30,6 +31,7 @@ $float_shadow: 0 16px 32px 0 rgba(0, 0, 0, 0.2); $float_shadow2: 0 5px 11px 0 rgba(0, 0,0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); +// mixin @mixin header_bg { background-image: linear-gradient(450deg, $sidebar_col, $htan_col, transparent); background-color: $primary_col; diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 73d476f4..60cb203c 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -1,4 +1,4 @@ -// specify div +/*** Content ***/ .content-wrapper { // overflow-y: visible !important; @@ -19,9 +19,9 @@ // TODO: Make it function or use existing function .box-primary { border-radius: 10px !important; - background-color: #FFF ; + background-color: #FFF; border-color: rgba($primary_col, 0.8) !important; - top: 15px; // move down to lower than header + top: 15px; box-shadow: $primary_shadow; transition: 200ms; -webkit-transition-property: box-shadow, transform; @@ -46,14 +46,17 @@ // if use solidHeader box .box-solid { + @extend .box-primary; border: 0px !important; + .box-header { border-radius: 10px; background: rgba($primary_col, 0.8) !important; margin: 0 5px 5px 5px; top: -7px; + // collapse button .box-tools .btn{ background: rgba($primary_col, 0.8); } diff --git a/www/scss/section/_footer.scss b/www/scss/section/_footer.scss index 2bb0e8b7..74a70700 100644 --- a/www/scss/section/_footer.scss +++ b/www/scss/section/_footer.scss @@ -32,6 +32,7 @@ // sidebar footer when sidebar collapsed .sidebar-collapse #sidebar_footer { + div>.fa{ color: transparent; padding: 2px; @@ -41,6 +42,7 @@ visibility: visible !important; transition: 100ms ease-in-out; } + footer { visibility: hidden; } diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index 848b9ae6..e940b4d6 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -1,8 +1,11 @@ +/*** Header ***/ + .logo, .navbar { background-color: transparent !important; } .main-header { + @include header_bg; .logo { @@ -19,11 +22,14 @@ // adjust custom dropdown color effect .navbar { + a:hover { background-color: $glass_grey !important; } + // custom dropdown - leftUI - .open>a { // when the box open + // when the box open + .open>a { background-color: $glass_grey !important; &:focus, &:hover { @@ -36,11 +42,11 @@ left: auto !important; // stick with the button left box-shadow: $primary_shadow; animation: fadeIn 100ms; - ul.menu { padding: 0 5px !important; + // reset all margin & * { margin: 0px; @@ -67,18 +73,20 @@ } } - +// responsive - cycle back for proper breakpoints if needed @media (max-width:1146px){ + .shiny-input-container{ width: 200px !important; } } @media (max-width:973px){ + ul.menu { + &>div, .row { flex-wrap: wrap; - // justify-content: center } } } \ No newline at end of file diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss index 46e29e02..7fb05d24 100644 --- a/www/scss/section/_sidebar.scss +++ b/www/scss/section/_sidebar.scss @@ -1,7 +1,6 @@ /*** Sidebar ***/ .left-side, .main-sidebar { - padding-top: 80px; font-weight: bold; font-size: 1.1em @@ -9,7 +8,6 @@ // when sidebar is open .main-sidebar { - background-color: $sidebar_col !important; .sidebar { From cbf951a108dc57578c6ce38ed0b414799c13387f Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 4 Jun 2021 16:07:40 +0000 Subject: [PATCH 061/260] clean up codes --- functions/boxEffect.R | 5 ++++ functions/{dc_waiter.R => dcWaiter.R} | 2 +- ...te_validation_msg.R => validationResult.R} | 0 modules/{render_table.R => DTable.R} | 0 modules/{validation.R => ValidationMsg.R} | 0 modules/{read_csvFile.R => csvInfile.R} | 0 modules/{switch_tabs.R => switchTab.R} | 0 server.R | 29 ++++++++++--------- ui.R | 2 +- www/js/onclick.js | 17 ----------- www/scss/basic/_box.scss | 19 ++++++++++++ www/scss/basic/_button.scss | 7 +++-- www/scss/main.scss | 1 + www/scss/section/_content.scss | 11 ------- www/scss/section/_footer.scss | 2 +- 15 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 functions/boxEffect.R rename functions/{dc_waiter.R => dcWaiter.R} (97%) rename functions/{create_validation_msg.R => validationResult.R} (100%) rename modules/{render_table.R => DTable.R} (100%) rename modules/{validation.R => ValidationMsg.R} (100%) rename modules/{read_csvFile.R => csvInfile.R} (100%) rename modules/{switch_tabs.R => switchTab.R} (100%) delete mode 100644 www/js/onclick.js create mode 100644 www/scss/basic/_box.scss diff --git a/functions/boxEffect.R b/functions/boxEffect.R new file mode 100644 index 00000000..bac6a224 --- /dev/null +++ b/functions/boxEffect.R @@ -0,0 +1,5 @@ +boxEffect <- function(zoom = FALSE, float = FALSE) { + # this is cleaner way, one caveat: need to change zoom scale in scss file + toggleClass(selector = ".box", class = "box-zoom", condition = zoom) + toggleClass(selector = ".box", class = "box-float", condition = float) +} diff --git a/functions/dc_waiter.R b/functions/dcWaiter.R similarity index 97% rename from functions/dc_waiter.R rename to functions/dcWaiter.R index cc186ec8..f0cb3fc4 100644 --- a/functions/dc_waiter.R +++ b/functions/dcWaiter.R @@ -1,7 +1,7 @@ # This is script to wrap up the waiter screen for data curator app # TODO: maybe we could split into UI and server if we need -dc_waiter <- function(stage = c("show", "update", "hide"), +dcWaiter <- function(stage = c("show", "update", "hide"), isLogin = FALSE, isPass = TRUE, usrName = NULL, sleep = 2, msg = NULL, spin = NULL) { # validate arguments diff --git a/functions/create_validation_msg.R b/functions/validationResult.R similarity index 100% rename from functions/create_validation_msg.R rename to functions/validationResult.R diff --git a/modules/render_table.R b/modules/DTable.R similarity index 100% rename from modules/render_table.R rename to modules/DTable.R diff --git a/modules/validation.R b/modules/ValidationMsg.R similarity index 100% rename from modules/validation.R rename to modules/ValidationMsg.R diff --git a/modules/read_csvFile.R b/modules/csvInfile.R similarity index 100% rename from modules/read_csvFile.R rename to modules/csvInfile.R diff --git a/modules/switch_tabs.R b/modules/switchTab.R similarity index 100% rename from modules/switch_tabs.R rename to modules/switchTab.R diff --git a/server.R b/server.R index a5d7fc5a..bc3589d3 100644 --- a/server.R +++ b/server.R @@ -49,6 +49,9 @@ shinyServer(function(input, output, session) { tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") clean_tags <- c("div_download", "div_validate", "btn_submit") + + # add box effects + boxEffect(zoom = TRUE, float = TRUE) ######## Initiate Login Process ######## # synapse cookies @@ -83,11 +86,11 @@ shinyServer(function(input, output, session) { }) # update waiter loading screen once login successful - dc_waiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) + dcWaiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) }, error = function(err) { message(err) # write log error - dc_waiter("update", isLogin = TRUE, isPass = FALSE) + dcWaiter("update", isLogin = TRUE, isPass = FALSE) } ) }) @@ -188,7 +191,7 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_download, { # loading screen for template link generation - dc_waiter("show", msg = "Generating link...") + dcWaiter("show", msg = "Generating link...") # update selected folder ID folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] @@ -234,7 +237,7 @@ shinyServer(function(input, output, session) { }) } - dc_waiter("hide", sleep = 1) + dcWaiter("hide", sleep = 1) # display link show("div_download") # TODO: add progress bar on (loading) screen }) @@ -254,7 +257,7 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_validate, { # loading screen for validating metadata - dc_waiter("show", msg = "Validating...") + dcWaiter("show", msg = "Validating...") try( silent = TRUE, @@ -298,7 +301,7 @@ shinyServer(function(input, output, session) { actionButton("btn_submit", "Submit to Synapse", class = "btn-primary-color") }) output$val_gsheet <- renderUI(NULL) - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) + dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) } else { # render gsheet button output$val_gsheet <- renderUI({ @@ -306,10 +309,10 @@ shinyServer(function(input, output, session) { class = "btn-primary-color", icon = icon("table") ) }) - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) + dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) } } else { - dc_waiter("hide") + dcWaiter("hide") } show("div_validate") @@ -318,7 +321,7 @@ shinyServer(function(input, output, session) { # if user click gsheet_btn, generating gsheet observeEvent(input$btn_val_gsheet, { # loading screen for Google link generation - dc_waiter("show", msg = "Generating link...") + dcWaiter("show", msg = "Generating link...") filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, @@ -330,14 +333,14 @@ shinyServer(function(input, output, session) { HTML(paste0("Edit on the Google Sheet.")) }) - dc_waiter("hide") + dcWaiter("hide") }) ######## Submission Section ######## observeEvent(input$btn_submit, { # loading screen for submitting data - dc_waiter("show", msg = "Submitting...") + dcWaiter("show", msg = "Submitting...") # reads file csv again inFile <- csvInfileServer("inputFile") @@ -393,7 +396,7 @@ shinyServer(function(input, output, session) { # TODO: input file not reset yet # reset(c(clean_tags, "inputFile", "tbl_preview")) if reset works } else { - dc_waiter("update", msg = HTML(paste0( + dcWaiter("update", msg = HTML(paste0( "Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" @@ -436,7 +439,7 @@ shinyServer(function(input, output, session) { nrow = 0 )))) } else { - dc_waiter("update", msg = HTML(paste0( + dcWaiter("update", msg = HTML(paste0( "Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) diff --git a/ui.R b/ui.R index f4a2c071..248ff2ab 100644 --- a/ui.R +++ b/ui.R @@ -227,7 +227,7 @@ ui <- shinydashboardPlus::dashboardPage( ) ), # waiter loading screen - dc_waiter("show", isLogin = TRUE) + dcWaiter("show", isLogin = TRUE) ) ) diff --git a/www/js/onclick.js b/www/js/onclick.js deleted file mode 100644 index 0d3a3890..00000000 --- a/www/js/onclick.js +++ /dev/null @@ -1,17 +0,0 @@ -// this script is to adjust the distance btw #header_selection_dropdown and content - -// $(document).on('shiny:connected', function () { -// $('#header_selection_dropdown').on('click', function () { -// if ($('#header_selection_dropdown')[0].className != 'dropdown open') { -// $('.content').css('padding-top', '50px') -// } else { -// $('.content').css('padding-top', '15px') -// } -// }) -// }); - -// $(document).on('click', function (e) { -// if (e.target.id != '#header_selection_dropdown') { -// $('.content').css('padding-top', '15px'); -// } -// }) \ No newline at end of file diff --git a/www/scss/basic/_box.scss b/www/scss/basic/_box.scss new file mode 100644 index 00000000..23106cd9 --- /dev/null +++ b/www/scss/basic/_box.scss @@ -0,0 +1,19 @@ +.box-zoom { + transition: 300ms; + transition-property: transform; + + &:hover { + transform: scale(1.005); // change scale here + z-index: 100; + } +} + +.box-float { + transition: 300ms; + transition-property: box-shadow; + + &:hover { + box-shadow: $float-shadow; + z-index: 100; + } +} \ No newline at end of file diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 7bf7372f..31b83af6 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -17,7 +17,7 @@ background-size: 400% 400%; animation: TransitioningBackground 10s ease infinite; - &:hover { + &:hover, &:focus { color: #fff; background-image: linear-gradient(to left, #2d8fe5, #d155b8); transform: scale(1.05); @@ -82,8 +82,9 @@ border-radius: 10px; box-shadow: $simple_shadow; - &:hover { + &:hover, &:focus { background: #fff; + outline: none !important; } .fa { @@ -129,7 +130,7 @@ border-radius: 40px; cursor: pointer; - &:hover { + &:hover, &:focus { background: $primary_col; color: #fff; box-shadow: $float_shadow2; diff --git a/www/scss/main.scss b/www/scss/main.scss index d9991cca..1a3faf4a 100644 --- a/www/scss/main.scss +++ b/www/scss/main.scss @@ -10,4 +10,5 @@ // feature styles @import 'basic/animation'; @import 'basic/button'; +@import 'basic/box'; @import 'basic/message'; diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 60cb203c..746c823f 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -22,17 +22,6 @@ background-color: #FFF; border-color: rgba($primary_col, 0.8) !important; top: 15px; - box-shadow: $primary_shadow; - transition: 200ms; - -webkit-transition-property: box-shadow, transform; - transition-property: box-shadow, transform; - - &:hover { - box-shadow: $float_shadow; - -webkit-transform: scale(1.001); - transform: scale(1.001); - z-index: 100; - } .box-title { font-size: 1.6em; diff --git a/www/scss/section/_footer.scss b/www/scss/section/_footer.scss index 74a70700..f4211fa6 100644 --- a/www/scss/section/_footer.scss +++ b/www/scss/section/_footer.scss @@ -38,7 +38,7 @@ padding: 2px; transform: scale(2.2); background: linear-gradient(45deg, purple, #7590d6); - -webkit-background-clip: text; + -webkit-background-clip: text; // clip to heart shape visibility: visible !important; transition: 100ms ease-in-out; } From 5fa1048d4607b634246d05db0618415218d79ddb Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 4 Jun 2021 21:32:30 +0000 Subject: [PATCH 062/260] fix submitting bugs from refactoring --- modules/read_csvFile.R | 2 +- server.R | 35 ++++++++++++++++++----------------- ui.R | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/modules/read_csvFile.R b/modules/read_csvFile.R index 1cc12b24..481c2341 100644 --- a/modules/read_csvFile.R +++ b/modules/read_csvFile.R @@ -24,7 +24,7 @@ csvInfileServer <- function(id, na = c("", "NA"), colsAsCharacters = FALSE, keep if (colsAsCharacters) { infile <- read_csv(input$file$datapath, na = na, col_types = cols(.default = "c")) } else { - infile <- read_csv(input$file$datapath, na = na) + infile <- read_csv(input$file$datapath, na = na, col_types = cols()) } if (keepBlank) { diff --git a/server.R b/server.R index eeb02ae1..96a7ebf7 100644 --- a/server.R +++ b/server.R @@ -38,7 +38,7 @@ shinyServer(function(input, output, session) { folder_synID <- NULL # selected foler synapse ID template_schema_name <- NULL # selected template schema name - file_namedlist <- NULL + file_namedList <- NULL ### mapping from display name to schema name schema_name <- config$manifest_schemas$schema_name @@ -162,12 +162,12 @@ shinyServer(function(input, output, session) { synStore_obj, folder_synID ) - file_namedlist <<- list2Vector(file_list) + file_namedList <<- list2Vector(file_list) manifest_url <- metadata_model$getModelManifest(paste0( config$community, " ", input$dropdown_template - ), template_schema_name, filenames = as.list(names(file_namedlist))) + ), template_schema_name, filenames = as.list(names(file_namedList))) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { @@ -288,7 +288,7 @@ shinyServer(function(input, output, session) { dc_waiter("show", msg = "Submitting...") # reads file csv again - inFile <- csvInfileServer("inputFile") + submit_data <- csvInfileServer("inputFile")$data() # IF an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice @@ -299,22 +299,22 @@ shinyServer(function(input, output, session) { # with synapse files if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId - if ("entityId" %in% colnames(infile)) { - write.csv(infile, + if ("entityId" %in% colnames(submit_data)) { + write.csv(submit_data, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } else { - if (is.null(file_namedlist)) { # if user do not generate gsheet of template before - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - file_namedlist <<- list2Vector(file_list) - } - files_df <- stack(file_namedList) + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + file_namedList <<- list2Vector(file_list) + + # better filename checking is needed + files_df <- stack(file_namedList) # crash if no file existing colnames(files_df) <- c("entityId", "Filename") - files_entity <- inner_join(infile, files_df, by = "Filename") + files_entity <- inner_join(submit_data, files_df, by = "Filename") write.csv(files_entity, file = "./files/synapse_storage_manifest.csv", @@ -330,8 +330,9 @@ shinyServer(function(input, output, session) { manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) rm("./files/synapse_storage_manifest.csv") + dc_waiter("hide") + nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) # clean up inputfile sapply(clean_tags, FUN = hide) @@ -348,7 +349,7 @@ shinyServer(function(input, output, session) { } } else { # if not assay type tempalte - write.csv(infile, + write.csv(submit_data, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) diff --git a/ui.R b/ui.R index 613b30aa..2a6e6ecf 100644 --- a/ui.R +++ b/ui.R @@ -189,7 +189,7 @@ ui <- dashboardPage( status = "primary", solidHeader = TRUE, width = 12, - uiOutput("btn_submit") + uiOutput("submit") ) ) ) From dbd19831302e3e4cd37df5b550e8c22dc8abb738 Mon Sep 17 00:00:00 2001 From: rrchai Date: Sat, 5 Jun 2021 01:04:16 +0000 Subject: [PATCH 063/260] adjust valid layout --- server.R | 24 +++++++++++------------- ui.R | 8 ++++---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/server.R b/server.R index 96a7ebf7..4f1508d1 100644 --- a/server.R +++ b/server.R @@ -46,7 +46,7 @@ shinyServer(function(input, output, session) { schema_to_display_lookup <- data.frame(schema_name, display_name) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_download", "div_validate", "btn_submit") + clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") ######## Initiate Login Process ######## # synapse cookies @@ -223,14 +223,16 @@ shinyServer(function(input, output, session) { # output error messages as data table if it is invalid value type # render empty if error is not "invaid value" type - ifelse() will not work - show_df <- if (valRes$errorType == "Invalid Value") valRes$errorDT else data.frame(NULL) - DTableServer("tbl_validate", show_df, - options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE + if (valRes$errorType == "Invalid Value") { + DTableServer("tbl_validate", valRes$errorDT, + options = list( + pageLength = 50, scrollX = TRUE, + scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + info = FALSE, searching = FALSE + ) ) - ) + show(NS("tbl_validate", "table")) + } # highlight invalue cells in preview table if (valRes$errorType == "Wrong Schema") { @@ -247,13 +249,9 @@ shinyServer(function(input, output, session) { output$submit <- renderUI({ actionButton("btn_submit", "Submit to Synapse") }) - output$val_gsheet <- renderUI(NULL) dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) } else { - # render gsheet button - output$val_gsheet <- renderUI({ - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) - }) + show("btn_val_gsheet") dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) } } else { diff --git a/ui.R b/ui.R index 2a6e6ecf..a44bd050 100644 --- a/ui.R +++ b/ui.R @@ -174,10 +174,10 @@ ui <- dashboardPage( div( id = "div_validate", height = "100%", - ValidationMsgUI("text_validate"), - DTableUI("tbl_validate"), - uiOutput("val_gsheet") - ) + ValidationMsgUI("text_validate") + ), + DTableUI("tbl_validate"), + actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) ), helpText( HTML("If you have an error, please try editing locally or on google sheet.
From 9a120b04dbddb8127a978d310fbf337f361fe3c6 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Thu, 10 Jun 2021 09:13:16 -0700 Subject: [PATCH 064/260] Add dataset_id to support use of use_annotations --- server.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server.R b/server.R index 4f1508d1..416cf00c 100644 --- a/server.R +++ b/server.R @@ -164,10 +164,10 @@ shinyServer(function(input, output, session) { ) file_namedList <<- list2Vector(file_list) - manifest_url <- metadata_model$getModelManifest(paste0( - config$community, - " ", input$dropdown_template - ), template_schema_name, filenames = as.list(names(file_namedList))) + manifest_url <- metadata_model$getModelManifest(paste0(config$community," ", input$template_type), + template_type, + filenames = as.list(filename_list), + datasetId = folder_synID) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { From 6f009a2706ca2d7dab03dd0d537830ff01564ebc Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Thu, 10 Jun 2021 10:40:06 -0700 Subject: [PATCH 065/260] Update server.R Incorporate changes from code review. --- server.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server.R b/server.R index 416cf00c..8e860ceb 100644 --- a/server.R +++ b/server.R @@ -164,10 +164,11 @@ shinyServer(function(input, output, session) { ) file_namedList <<- list2Vector(file_list) - manifest_url <- metadata_model$getModelManifest(paste0(config$community," ", input$template_type), - template_type, - filenames = as.list(filename_list), - datasetId = folder_synID) + metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), + template_schema_name, + filenames = as.list(names(file_namedList)), + datasetId = folder_synID +) # make sure not scalar if length of list is 1 in R # add in the step to convert names later } else { From d6db128bc7b3040feeb1a5fd12f95a72a4f377d0 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 15 Jun 2021 18:16:50 +0000 Subject: [PATCH 066/260] add dca; fix bugs --- files/synapse_storage_manifest.csv | 2 +- functions/dcWaiter.R | 4 +- server.R | 89 +++++++++++++----------------- ui.R | 24 ++++---- 4 files changed, 51 insertions(+), 68 deletions(-) diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv index becd43b4..5bba5bde 100644 --- a/files/synapse_storage_manifest.csv +++ b/files/synapse_storage_manifest.csv @@ -1 +1 @@ -CancerType,LibraryConstructionMethod,HTANParticipantID,Filename,HTANSampleID,entityId +Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R index f0cb3fc4..00f90a61 100644 --- a/functions/dcWaiter.R +++ b/functions/dcWaiter.R @@ -2,8 +2,8 @@ # TODO: maybe we could split into UI and server if we need dcWaiter <- function(stage = c("show", "update", "hide"), - isLogin = FALSE, isPass = TRUE, usrName = NULL, - sleep = 2, msg = NULL, spin = NULL) { + isLogin = FALSE, isPass = TRUE, usrName = NULL, + sleep = 2, msg = NULL, spin = NULL) { # validate arguments if (!is.logical(isLogin)) stop("isLogin must be a boolean") if (!is.logical(isPass)) stop("isPass must be a boolean") diff --git a/server.R b/server.R index 9315c8b3..798034b2 100644 --- a/server.R +++ b/server.R @@ -31,25 +31,19 @@ shinyServer(function(input, output, session) { config <- fromJSON("www/config.json") # mapping from display name to schema name - schema_name <- config$manifest_schemas$schema_name - display_name <- config$manifest_schemas$display_name - template_namedList <- schema_name - names(template_namedList) <- display_name + template_namedList <- config$manifest_schemas$schema_name + names(template_namedList) <- config$manifest_schemas$display_name synStore_obj <- NULL # gets list of projects they have access to + project_synID <- NULL # selected project synapse ID folder_synID <- NULL # selected foler synapse ID template_schema_name <- NULL # selected template schema name - datatype_list <- list( - projects_namedList = NULL, - folders_namedList = NULL, - display_name = template_namedList - ) - file_namedlist <- NULL + datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") - + # add box effects boxEffect(zoom = TRUE, float = TRUE) @@ -74,7 +68,7 @@ shinyServer(function(input, output, session) { # get_projects_list(synStore_obj) projects_list <- synapse_driver$getStorageProjects(synStore_obj) - datatype_list[["projects_namedList"]] <<- list2Vector(projects_list) + datatype_list$projects <<- list2Vector(projects_list) # updates project dropdown lapply(c("header_dropdown_", "dropdown_"), function(x) { @@ -105,19 +99,18 @@ shinyServer(function(input, output, session) { lapply(c("header_dropdown_", "dropdown_"), function(x) { observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { # get synID of selected project - project_synID <- datatype_list[["projects_namedList"]][[input[[paste0(x, "project")]]]] + projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] # gets folders per project - folder_list <- synapse_driver$getStorageDatasetsInProject( - synStore_obj, - project_synID - ) - datatype_list[["folders_namedList"]] <<- list2Vector(folder_list) - folders <- sort(names(datatype_list[["folders_namedList"]])) + folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() + + if (x == "dropdown_") { + project_synID <<- projectID + datatype_list$folders <<- folder_list + } + # updates foldernames - updateSelectInput(session, paste0(x, "folder"), - choices = folders - ) + updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) }) }) @@ -194,7 +187,7 @@ shinyServer(function(input, output, session) { dcWaiter("show", msg = "Generating link...") # update selected folder ID - folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] + folder_synID <<- datatype_list$folders[[input$dropdown_folder]] if (is.null(input$dropdown_template)) { output$text_download <- renderUI({ @@ -215,14 +208,14 @@ shinyServer(function(input, output, session) { synStore_obj, folder_synID ) - file_namedList <<- list2Vector(file_list) - - manifest_url <- + datatype_list$files <<- list2Vector(file_list) + + manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), - template_schema_name, - filenames = as.list(names(file_namedList)), - datasetId = folder_synID - ) + template_schema_name, + filenames = as.list(names(datatype_list$files)), + datasetId = folder_synID + ) # make sure not scalar if length of list is 1 in R # add in the step to convert names later @@ -302,15 +295,13 @@ shinyServer(function(input, output, session) { if (valRes$validationRes == "valid") { # show submit button - output$submit <- renderUI({ - actionButton("btn_submit", "Submit to Synapse", class = "btn-primary-color") - }) - - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) - + output$submit <- renderUI(actionButton("btn_submit", "Submit to Synapse", class = "btn-primary-color")) + dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) } else { - show("btn_val_gsheet") - dc_waiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) + output$val_gsheet <- renderUI( + actionButton("btn_val_gsheet", " Generate Google Sheet Link", icon = icon("table"), class = "btn-primary-color") + ) + dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) } } else { dcWaiter("hide") @@ -345,14 +336,11 @@ shinyServer(function(input, output, session) { # reads file csv again submit_data <- csvInfileServer("inputFile")$data() - # IF an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice - assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == - "assay"] - # folder_ID has not been updated yet - if (is.null(folder_synID)) folder_synID <<- datatype_list[["folders_namedList"]][[input$dropdown_folder]] - + assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] + # iffolder_ID has not been updated yet + if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] # and adds entityID, saves it as synapse_storage_manifest.csv, then associates # with synapse files if (input$dropdown_template %in% assay_schemas) { @@ -363,14 +351,11 @@ shinyServer(function(input, output, session) { quote = TRUE, row.names = FALSE, na = "" ) } else { - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - file_namedList <<- list2Vector(file_list) + file_list <- synapse_driver$getFilesInStorageDataset(synStore_obj, folder_synID) + datatype_list$files <<- list2Vector(file_list) # better filename checking is needed - files_df <- stack(file_namedList) # crash if no file existing + files_df <- stack(datatype_list$files) # crash if no file existing colnames(files_df) <- c("entityId", "Filename") files_entity <- inner_join(submit_data, files_df, by = "Filename") @@ -381,15 +366,17 @@ shinyServer(function(input, output, session) { } # associates metadata with data and returns manifest id + logjs("haha6") manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID ) + logjs("haha7") manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { rm("./files/synapse_storage_manifest.csv") - dc_waiter("hide") + dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) # clean up inputfile diff --git a/ui.R b/ui.R index 382d31ba..7d786c0a 100644 --- a/ui.R +++ b/ui.R @@ -98,7 +98,7 @@ ui <- shinydashboardPlus::dashboardPage( # First tab content tabItem( tabName = "tab_instructions", - h2("Instructions for the Data Curator App:"), + h2("Instructions for the Data Curator App (DCA):"), h3( "1. Go to", strong("Select your Dataset"), @@ -200,21 +200,17 @@ ui <- shinydashboardPlus::dashboardPage( status = "primary", collapsible = TRUE, width = 12, - actionButton("btn_validate", "Validate Metadata", - class = "btn-primary-color" - ), - hidden( - div( - id = "div_validate", - height = "100%", - ValidationMsgUI("text_validate") - ), - DTableUI("tbl_validate"), - actionButton("btn_val_gsheet", " Click to Generate Google Sheet Link", icon = icon("table")) + actionButton("btn_validate", "Validate Metadata", class = "btn-primary-color"), + div( + id = "div_validate", + height = "100%", + ValidationMsgUI("text_validate") ), + DTableUI("tbl_validate"), + uiOutput("val_gsheet"), helpText( - HTML("If you have an error, please try editing locally or on google sheet.
- Reupload your CSV and press the validate button as needed.") + HTML("If you have an error, please try editing locally or on google sheet. + Reupload your CSV and press the validate button as needed.") ) ), box( From 25614d02c77feece157866cea85cd28ffea4ddbd Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 15 Jun 2021 22:29:56 +0000 Subject: [PATCH 067/260] add title of browser tab --- ui.R | 1 + 1 file changed, 1 insertion(+) diff --git a/ui.R b/ui.R index 7d786c0a..406053a1 100644 --- a/ui.R +++ b/ui.R @@ -9,6 +9,7 @@ # https://www.synapse.org ui <- shinydashboardPlus::dashboardPage( + title = "Data Curator", skin = "purple", dashboardHeader( titleWidth = 250, From 317050ca126a260cc00c62eba820b88c0d05c738 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 27 Aug 2021 15:25:47 +0000 Subject: [PATCH 068/260] modify setup to use poetry install --- README.md | 49 ++++++++++++++++++++++++------------- environment.yml | 3 --- example_config.yaml | 7 +++--- functions/metadata_model.py | 2 +- global.R | 9 ++++--- 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index eb28829e..8cfd328d 100644 --- a/README.md +++ b/README.md @@ -10,27 +10,48 @@ The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the sc ### Data Curator App Setup Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main): -Navigate to the location where you want to setup the application (i.e., the _Shiny Server_). Clone the code on this github branch (_shiny-server-main_): +1. Clone this repo with one single branch (i.e., *shiny-server-main*): - git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git + git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -Create a conda environment in the cloned directory from the `environment.yml` file which has all the required package dependencies: +2. Create and edit the configuration file. Please make sure `OAuth Credential` ([how to obtain OAuth](###-Authentication)), `App_URL` and `CONDA_ENV_NAME` are correct in `config.yaml`: + + cp example_config.yaml config.yaml + + chmod 400 config.yaml - conda env create -f environment.yml -Here, our conda environment name `data_curator_env` is set from the `environment.yml` file . +3. Create a conda environment in the cloned directory from the `environment.yml` file which has all the required package dependencies: -Activate the `data_curator_env` environment: + grep 'CONDA_ENV_NAME:' config.yaml | cut -f2 -d':' | xargs conda env create -f environment.yml -n - conda activate data_curator_env +4. Activate the `data_curator_env` environment. Here, our conda environment name `data_curator_env` is set by default in the `example_config.yaml`. + conda activate data_curator_env + +5. Install R packages: + + R -e "renv::consent(provided=TRUE)" + R -e "renv::restore(lockfile='renv.lock')" ### Schematic Setup -The next step is to install the latest release of the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main) (backend) as a folder `schematic` inside the `data_curator` folder and tie it together with this frontend. +1. Clone the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/develop) (backend) as a folder `schematic` inside the `data_curator` folder: + + git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git -To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites). +2. Install the latest release of the `schematic`: + python -m pip install schematicpy + + + - For [development](https://github.com/Sage-Bionetworks/schematic/blob/develop/CONTRIBUTION.md#development-environment-setup), install the package via `poetry`: + + cd schematic + poetry build + pip install dist/schematicpy-*-py3-none-any.whl + +2. Set up the schematic configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) ### App Configuration File @@ -45,12 +66,6 @@ Use the app configuration file `www/config.json` to adapt this app to your DCC. * `community` : the abbreviated name of the community or project. (e.g. _HTAN_) -### Authentication (OAuth) - -This utilizes a Synapse OAuth client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration file. +### Authentication -``` -cp example_config.yaml config.yaml -# Edit config.yaml -chmod 400 config.yaml -``` \ No newline at end of file +This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration yaml file. \ No newline at end of file diff --git a/environment.yml b/environment.yml index 325783c6..1dbe832b 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,3 @@ -name: data_curator_env_oauth channels: - defaults dependencies: @@ -92,5 +91,3 @@ dependencies: - wrapt==1.12.1 - zipp==3.1.0 - pyyaml==5.3.1 -prefix: /home/xdoan/bin/home/xdoan/bin/miniconda3/envs/data_curator_env - diff --git a/example_config.yaml b/example_config.yaml index 3908931e..224496d2 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -1,6 +1,7 @@ # This file contains the oauth client id and secret required for # the application. This file needs to have chmod 400 permissions # client_id and APP_URL has to be a string -client_id: -client_secret: -APP_URL: +CLIENT_ID: +CLIENT_SECRET: +APP_URL: "https://shinypro.synapse.org/users/rchai/dc/" +CONDA_ENV_NAME: "data_curator_env" diff --git a/functions/metadata_model.py b/functions/metadata_model.py index 378fad67..1a4a9176 100644 --- a/functions/metadata_model.py +++ b/functions/metadata_model.py @@ -2,7 +2,7 @@ from schematic import CONFIG -config = CONFIG.load_config("config.yml") +config = CONFIG.load_config("schematic/config.yml") inputMModelLocation = CONFIG["model"]["input"]["location"] inputMModelLocationType = CONFIG["model"]["input"]["file_type"] diff --git a/global.R b/global.R index 88bfb1eb..4ab86fe6 100644 --- a/global.R +++ b/global.R @@ -33,9 +33,10 @@ has_auth_code <- function(params) { oauth_client <- yaml.load_file("config.yaml") -client_id <- toString(oauth_client$client_id) -client_secret <- oauth_client$client_secret -APP_URL <- oauth_client$APP_URL +client_id <- toString(oauth_client$CLIENT_ID) +client_secret <- toString(oauth_client$CLIENT_SECRET) +APP_URL <- toString(oauth_client$APP_URL) + if (is.null(client_id)) stop("config.yaml is missing client_id") if (is.null(client_secret)) stop("config.yaml is missing client_secret") if (is.null(APP_URL)) stop("config.yaml is missing client_secret") @@ -77,7 +78,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") +reticulate::use_condaenv("data_curator_dev_env") # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) From c806ac5ed467bc437fc217736761fef7a57b6253 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 27 Aug 2021 15:41:46 +0000 Subject: [PATCH 069/260] correct oauth setup --- global.R | 16 ++++++++-------- server.R | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/global.R b/global.R index 4ab86fe6..0252cc34 100644 --- a/global.R +++ b/global.R @@ -21,8 +21,6 @@ suppressPackageStartupMessages({ library(shinydashboardPlus) }) -# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" - has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if # based on these parameters, it looks like auth code is present that we can @@ -35,16 +33,18 @@ oauth_client <- yaml.load_file("config.yaml") client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) -APP_URL <- toString(oauth_client$APP_URL) +app_url <- toString(oauth_client$APP_URL) +conda_name <- toString(oauth_client$CONDA_ENV_NAME) -if (is.null(client_id)) stop("config.yaml is missing client_id") -if (is.null(client_secret)) stop("config.yaml is missing client_secret") -if (is.null(APP_URL)) stop("config.yaml is missing client_secret") +if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") +if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") +if (is.null(app_url)) stop("config.yaml is missing APP_URL") +if (is.null(conda_name)) stop("config.yaml is missing CONDA_ENV_NAME") app <- oauth_app("shinysynapse", key = client_id, secret = client_secret, - redirect_uri = APP_URL + redirect_uri = app_url ) # These are the user info details ('claims') requested from Synapse: @@ -78,7 +78,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_dev_env") +reticulate::use_condaenv(conda_name) # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) diff --git a/server.R b/server.R index 798034b2..2beb6a3e 100644 --- a/server.R +++ b/server.R @@ -10,7 +10,7 @@ shinyServer(function(input, output, session) { return() } redirect_url <- paste0( - api$access, "?", "redirect_uri=", APP_URL, "&grant_type=", + api$access, "?", "redirect_uri=", app_url, "&grant_type=", "authorization_code", "&code=", params$code ) # get the access_token and userinfo token From fb9f4f88d417bc07e0d4193f10226193624a3bf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 08:47:52 -0400 Subject: [PATCH 070/260] Bump httplib2 from 0.18.1 to 0.19.0 (#177) * Getting develop and main branches in sync (#176) * fix highlight on preview table in val * fix help message & remove rownames on preview table * improve error handling on 'missing required columns' * improve error handling on NOT upload a file/select template * update: highlight entire preview table if it is wrong schema errors * update: improve help message * update: improve error message * update: change 'Valid' to lower case * change error message to red * change NA to can simply fix the issue * save the original comments * add error when click on generate gsheet without selected template * collect styles to a scss file * Revert "change error message to red" This reverts commit 4d26a50bf00a97dcdd233bc6655fc122c9b17afb. * remove css * Revert "Improve error handling on 'missing required columns'" * use getDatasetManifest() to check for existence of manifest * improve error msg for wrong schema * load scss library * fix typo scss to sass * update wording * scss structure * updated config.json to be compatible with latest HTAN.jsonld * add missed codes * remove local test code * rm helper msg * rm msg * moved necessary python files to python directory * package management with renv for Data Curator App * add .Rprofile * update README * add general .Rproj file * example config file for OAuth credentials * don't track config.yaml file * file to store global variables * getting setup with reticulate * add requirements.txt file * move code from app.R to ui.R and server.R * remove app.R * bump up schematicpy version * config.yml file in root of repo by default * remove call to getModelManifest() in metadata_model.py * change environment name to data_curator_env * add readr package to renv.lock * load readr package using library() * improve config environment * set projects, folders, templates to server global variables * organize code/comments * format 355fad5 * rename selectors to more descriptive names * format .Rprofile * create module for next/previous button * wrap up waiter screens * add modules; create modules for reading csv file * create modules for validation and renderTable & collect validation contents in one div * improve gsheet button * improve codes and fix some errors * add utils * feature - show users' datatypes selections and be able to modify * improve waiter, catch the errors on detecting no file in val * move folder_synID to download_btn and submit_btn, it seems like the folder_synID observation has high priority than updating folders, which will crash app * fix 159 - app crash when empty manifest loaded * change selectiveInput to selectInput * change selectizeInput to selectInput * enhance sidebar UI * bg color and box change in content * header change x2 * content change x2 * remove solid header, increase title size * buttons change * format .R and .scss * clean up codes * fix submitting bugs from refactoring * adjust valid layout * Add dataset_id to support use of use_annotations * Update server.R Incorporate changes from code review. * add dca; fix bugs * add title of browser tab Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway * Bump httplib2 from 0.18.1 to 0.19.0 Bumps [httplib2](https://github.com/httplib2/httplib2) from 0.18.1 to 0.19.0. - [Release notes](https://github.com/httplib2/httplib2/releases) - [Changelog](https://github.com/httplib2/httplib2/blob/master/CHANGELOG) - [Commits](https://github.com/httplib2/httplib2/compare/v0.18.1...v0.19.0) --- updated-dependencies: - dependency-name: httplib2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fa846e13..b5aca445 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ google-auth-httplib2==0.0.4 google-auth-oauthlib==0.4.4 googleapis-common-protos==1.53.0 graphviz==0.16 -httplib2==0.18.1 +httplib2==0.19.0 idna==2.10 importlib-metadata==1.7.0 inflection==0.5.1 From 78117938388e85990673ce39092191ae5e24a143 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 08:48:27 -0400 Subject: [PATCH 071/260] Bump rsa from 4.6 to 4.7 (#178) * Getting develop and main branches in sync (#176) * fix highlight on preview table in val * fix help message & remove rownames on preview table * improve error handling on 'missing required columns' * improve error handling on NOT upload a file/select template * update: highlight entire preview table if it is wrong schema errors * update: improve help message * update: improve error message * update: change 'Valid' to lower case * change error message to red * change NA to can simply fix the issue * save the original comments * add error when click on generate gsheet without selected template * collect styles to a scss file * Revert "change error message to red" This reverts commit 4d26a50bf00a97dcdd233bc6655fc122c9b17afb. * remove css * Revert "Improve error handling on 'missing required columns'" * use getDatasetManifest() to check for existence of manifest * improve error msg for wrong schema * load scss library * fix typo scss to sass * update wording * scss structure * updated config.json to be compatible with latest HTAN.jsonld * add missed codes * remove local test code * rm helper msg * rm msg * moved necessary python files to python directory * package management with renv for Data Curator App * add .Rprofile * update README * add general .Rproj file * example config file for OAuth credentials * don't track config.yaml file * file to store global variables * getting setup with reticulate * add requirements.txt file * move code from app.R to ui.R and server.R * remove app.R * bump up schematicpy version * config.yml file in root of repo by default * remove call to getModelManifest() in metadata_model.py * change environment name to data_curator_env * add readr package to renv.lock * load readr package using library() * improve config environment * set projects, folders, templates to server global variables * organize code/comments * format 355fad5 * rename selectors to more descriptive names * format .Rprofile * create module for next/previous button * wrap up waiter screens * add modules; create modules for reading csv file * create modules for validation and renderTable & collect validation contents in one div * improve gsheet button * improve codes and fix some errors * add utils * feature - show users' datatypes selections and be able to modify * improve waiter, catch the errors on detecting no file in val * move folder_synID to download_btn and submit_btn, it seems like the folder_synID observation has high priority than updating folders, which will crash app * fix 159 - app crash when empty manifest loaded * change selectiveInput to selectInput * change selectizeInput to selectInput * enhance sidebar UI * bg color and box change in content * header change x2 * content change x2 * remove solid header, increase title size * buttons change * format .R and .scss * clean up codes * fix submitting bugs from refactoring * adjust valid layout * Add dataset_id to support use of use_annotations * Update server.R Incorporate changes from code review. * add dca; fix bugs * add title of browser tab Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway * Bump rsa from 4.6 to 4.7 Bumps [rsa](https://github.com/sybrenstuvel/python-rsa) from 4.6 to 4.7. - [Release notes](https://github.com/sybrenstuvel/python-rsa/releases) - [Changelog](https://github.com/sybrenstuvel/python-rsa/blob/main/CHANGELOG.md) - [Commits](https://github.com/sybrenstuvel/python-rsa/compare/version-4.6...version-4.7) --- updated-dependencies: - dependency-name: rsa dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b5aca445..e803940a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -46,7 +46,7 @@ PyYAML==5.4.1 rdflib==5.0.0 requests==2.24.0 requests-oauthlib==1.3.0 -rsa==4.6 +rsa==4.7 schematicpy==0.1.13 SecretStorage==2.3.1 setuptools==52.0.0 From e2b49d0fe94cedd3df808090713754d51d397f3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 08:49:14 -0400 Subject: [PATCH 072/260] Bump cryptography from 2.9.2 to 3.3.2 (#179) * Getting develop and main branches in sync (#176) * fix highlight on preview table in val * fix help message & remove rownames on preview table * improve error handling on 'missing required columns' * improve error handling on NOT upload a file/select template * update: highlight entire preview table if it is wrong schema errors * update: improve help message * update: improve error message * update: change 'Valid' to lower case * change error message to red * change NA to can simply fix the issue * save the original comments * add error when click on generate gsheet without selected template * collect styles to a scss file * Revert "change error message to red" This reverts commit 4d26a50bf00a97dcdd233bc6655fc122c9b17afb. * remove css * Revert "Improve error handling on 'missing required columns'" * use getDatasetManifest() to check for existence of manifest * improve error msg for wrong schema * load scss library * fix typo scss to sass * update wording * scss structure * updated config.json to be compatible with latest HTAN.jsonld * add missed codes * remove local test code * rm helper msg * rm msg * moved necessary python files to python directory * package management with renv for Data Curator App * add .Rprofile * update README * add general .Rproj file * example config file for OAuth credentials * don't track config.yaml file * file to store global variables * getting setup with reticulate * add requirements.txt file * move code from app.R to ui.R and server.R * remove app.R * bump up schematicpy version * config.yml file in root of repo by default * remove call to getModelManifest() in metadata_model.py * change environment name to data_curator_env * add readr package to renv.lock * load readr package using library() * improve config environment * set projects, folders, templates to server global variables * organize code/comments * format 355fad5 * rename selectors to more descriptive names * format .Rprofile * create module for next/previous button * wrap up waiter screens * add modules; create modules for reading csv file * create modules for validation and renderTable & collect validation contents in one div * improve gsheet button * improve codes and fix some errors * add utils * feature - show users' datatypes selections and be able to modify * improve waiter, catch the errors on detecting no file in val * move folder_synID to download_btn and submit_btn, it seems like the folder_synID observation has high priority than updating folders, which will crash app * fix 159 - app crash when empty manifest loaded * change selectiveInput to selectInput * change selectizeInput to selectInput * enhance sidebar UI * bg color and box change in content * header change x2 * content change x2 * remove solid header, increase title size * buttons change * format .R and .scss * clean up codes * fix submitting bugs from refactoring * adjust valid layout * Add dataset_id to support use of use_annotations * Update server.R Incorporate changes from code review. * add dca; fix bugs * add title of browser tab Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway * Bump cryptography from 2.9.2 to 3.3.2 Bumps [cryptography](https://github.com/pyca/cryptography) from 2.9.2 to 3.3.2. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/2.9.2...3.3.2) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e803940a..1cff2342 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ cffi==1.14.0 chardet==3.0.4 click==7.1.2 click-log==0.3.2 -cryptography==2.9.2 +cryptography==3.3.2 decorator==4.4.2 Deprecated==1.2.4 entrypoints==0.3 From de52b4c0c53ae025be1bedfe66444269710cdd91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 08:49:25 -0400 Subject: [PATCH 073/260] Bump urllib3 from 1.25.9 to 1.26.5 (#180) * Getting develop and main branches in sync (#176) * fix highlight on preview table in val * fix help message & remove rownames on preview table * improve error handling on 'missing required columns' * improve error handling on NOT upload a file/select template * update: highlight entire preview table if it is wrong schema errors * update: improve help message * update: improve error message * update: change 'Valid' to lower case * change error message to red * change NA to can simply fix the issue * save the original comments * add error when click on generate gsheet without selected template * collect styles to a scss file * Revert "change error message to red" This reverts commit 4d26a50bf00a97dcdd233bc6655fc122c9b17afb. * remove css * Revert "Improve error handling on 'missing required columns'" * use getDatasetManifest() to check for existence of manifest * improve error msg for wrong schema * load scss library * fix typo scss to sass * update wording * scss structure * updated config.json to be compatible with latest HTAN.jsonld * add missed codes * remove local test code * rm helper msg * rm msg * moved necessary python files to python directory * package management with renv for Data Curator App * add .Rprofile * update README * add general .Rproj file * example config file for OAuth credentials * don't track config.yaml file * file to store global variables * getting setup with reticulate * add requirements.txt file * move code from app.R to ui.R and server.R * remove app.R * bump up schematicpy version * config.yml file in root of repo by default * remove call to getModelManifest() in metadata_model.py * change environment name to data_curator_env * add readr package to renv.lock * load readr package using library() * improve config environment * set projects, folders, templates to server global variables * organize code/comments * format 355fad5 * rename selectors to more descriptive names * format .Rprofile * create module for next/previous button * wrap up waiter screens * add modules; create modules for reading csv file * create modules for validation and renderTable & collect validation contents in one div * improve gsheet button * improve codes and fix some errors * add utils * feature - show users' datatypes selections and be able to modify * improve waiter, catch the errors on detecting no file in val * move folder_synID to download_btn and submit_btn, it seems like the folder_synID observation has high priority than updating folders, which will crash app * fix 159 - app crash when empty manifest loaded * change selectiveInput to selectInput * change selectizeInput to selectInput * enhance sidebar UI * bg color and box change in content * header change x2 * content change x2 * remove solid header, increase title size * buttons change * format .R and .scss * clean up codes * fix submitting bugs from refactoring * adjust valid layout * Add dataset_id to support use of use_annotations * Update server.R Incorporate changes from code review. * add dca; fix bugs * add title of browser tab Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway * Bump urllib3 from 1.25.9 to 1.26.5 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.25.9 to 1.26.5. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.25.9...1.26.5) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Co-authored-by: Sujay Patil Co-authored-by: Rong Chai Co-authored-by: Robert Allaway Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1cff2342..8c66a917 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,7 +55,7 @@ synapseclient==2.3.0 tabletext==0.1 toml==0.10.2 uritemplate==3.0.1 -urllib3==1.25.9 +urllib3==1.26.5 wheel==0.34.2 wrapt==1.12.1 zipp==3.1.0 From 2bbdd215e018dd1076d024a9dd432e084d04034b Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 20 Sep 2021 20:56:18 +0000 Subject: [PATCH 074/260] fix 192 & clean codes --- .gitignore | 1 - files/synapse_storage_manifest.csv | 1 - global.R | 9 +++----- server.R | 36 +++++++++++++++--------------- 4 files changed, 21 insertions(+), 26 deletions(-) delete mode 100644 files/synapse_storage_manifest.csv diff --git a/.gitignore b/.gitignore index 11623cf0..4e78e2e3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ www/bootstrap.css www/bootstrap.min.css www/getdata.js www/message-handler.js -files/synapse_storage_manifest.csv .Rproj.user schematic/schema_explorer/__pycache__/* schematic/__pycache__/* diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv deleted file mode 100644 index 5bba5bde..00000000 --- a/files/synapse_storage_manifest.csv +++ /dev/null @@ -1 +0,0 @@ -Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId diff --git a/global.R b/global.R index 88bfb1eb..d4c8ae95 100644 --- a/global.R +++ b/global.R @@ -1,3 +1,6 @@ +# Activate conda env +reticulate::use_condaenv("data_curator_env_oauth") + suppressPackageStartupMessages({ library(shiny) library(httr) @@ -21,8 +24,6 @@ suppressPackageStartupMessages({ library(shinydashboardPlus) }) -# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" - has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if # based on these parameters, it looks like auth code is present that we can @@ -75,10 +76,6 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" -# Activate conda env -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") - # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) diff --git a/server.R b/server.R index 798034b2..5edcd876 100644 --- a/server.R +++ b/server.R @@ -333,21 +333,23 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_submit, { # loading screen for submitting data dcWaiter("show", msg = "Submitting...") - + dir.create("./tmp", showWarnings = FALSE) # reads file csv again submit_data <- csvInfileServer("inputFile")$data() - # IF an assay component selected (define assay components) note for future + # replace special characters with '_' + colnames(submit_data) <- gsub("[[:punct:]]", "_", colnames(submit_data)) + + # If an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - # iffolder_ID has not been updated yet + # if folder_ID has not been updated yet if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - # and adds entityID, saves it as synapse_storage_manifest.csv, then associates - # with synapse files + if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(submit_data)) { write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } else { @@ -355,27 +357,26 @@ shinyServer(function(input, output, session) { datatype_list$files <<- list2Vector(file_list) # better filename checking is needed - files_df <- stack(datatype_list$files) # crash if no file existing + # TODO: crash if no file existing + files_df <- stack(datatype_list$files) + # adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files colnames(files_df) <- c("entityId", "Filename") files_entity <- inner_join(submit_data, files_df, by = "Filename") write.csv(files_entity, - file = "./files/synapse_storage_manifest.csv", + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } # associates metadata with data and returns manifest id - logjs("haha6") manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID ) - logjs("haha7") manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { - rm("./files/synapse_storage_manifest.csv") dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) @@ -390,27 +391,25 @@ shinyServer(function(input, output, session) { manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") } } else { # if not assay type tempalte write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", quote = TRUE, + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID ) - print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { + dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) - rm("./files/synapse_storage_manifest.csv") # clear inputs sapply(clean_tags, FUN = hide) @@ -432,8 +431,9 @@ shinyServer(function(input, output, session) { "Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") } } + # delete tmp manifest + unlink("./tmp/synapse_storage_manifest.csv") }) }) From db1df89a6ddb4aaf21ddd7389da7684a96091d4d Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Mon, 20 Sep 2021 17:24:06 -0400 Subject: [PATCH 075/260] Revert "Fix disconnection when submit manifests with special characters column names" --- .gitignore | 1 + files/synapse_storage_manifest.csv | 1 + global.R | 9 +++++--- server.R | 36 +++++++++++++++--------------- 4 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 files/synapse_storage_manifest.csv diff --git a/.gitignore b/.gitignore index 4e78e2e3..11623cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ www/bootstrap.css www/bootstrap.min.css www/getdata.js www/message-handler.js +files/synapse_storage_manifest.csv .Rproj.user schematic/schema_explorer/__pycache__/* schematic/__pycache__/* diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv new file mode 100644 index 00000000..5bba5bde --- /dev/null +++ b/files/synapse_storage_manifest.csv @@ -0,0 +1 @@ +Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId diff --git a/global.R b/global.R index d4c8ae95..88bfb1eb 100644 --- a/global.R +++ b/global.R @@ -1,6 +1,3 @@ -# Activate conda env -reticulate::use_condaenv("data_curator_env_oauth") - suppressPackageStartupMessages({ library(shiny) library(httr) @@ -24,6 +21,8 @@ suppressPackageStartupMessages({ library(shinydashboardPlus) }) +# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" + has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if # based on these parameters, it looks like auth code is present that we can @@ -76,6 +75,10 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" +# Activate conda env +# Don't necessarily have to set `RETICULATE_PYTHON` env variable +reticulate::use_condaenv("data_curator_env_oauth") + # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) diff --git a/server.R b/server.R index 5edcd876..798034b2 100644 --- a/server.R +++ b/server.R @@ -333,23 +333,21 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_submit, { # loading screen for submitting data dcWaiter("show", msg = "Submitting...") - dir.create("./tmp", showWarnings = FALSE) + # reads file csv again submit_data <- csvInfileServer("inputFile")$data() - # replace special characters with '_' - colnames(submit_data) <- gsub("[[:punct:]]", "_", colnames(submit_data)) - - # If an assay component selected (define assay components) note for future + # IF an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - # if folder_ID has not been updated yet + # iffolder_ID has not been updated yet if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - + # and adds entityID, saves it as synapse_storage_manifest.csv, then associates + # with synapse files if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(submit_data)) { write.csv(submit_data, - file = "./tmp/synapse_storage_manifest.csv", + file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } else { @@ -357,26 +355,27 @@ shinyServer(function(input, output, session) { datatype_list$files <<- list2Vector(file_list) # better filename checking is needed - # TODO: crash if no file existing - files_df <- stack(datatype_list$files) - # adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files + files_df <- stack(datatype_list$files) # crash if no file existing colnames(files_df) <- c("entityId", "Filename") files_entity <- inner_join(submit_data, files_df, by = "Filename") write.csv(files_entity, - file = "./tmp/synapse_storage_manifest.csv", + file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } # associates metadata with data and returns manifest id + logjs("haha6") manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./tmp/synapse_storage_manifest.csv", folder_synID + "./files/synapse_storage_manifest.csv", folder_synID ) + logjs("haha7") manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { + rm("./files/synapse_storage_manifest.csv") dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) @@ -391,25 +390,27 @@ shinyServer(function(input, output, session) { manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) + rm("/tmp/synapse_storage_manifest.csv") } } else { # if not assay type tempalte write.csv(submit_data, - file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, + file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./tmp/synapse_storage_manifest.csv", folder_synID + "./files/synapse_storage_manifest.csv", folder_synID ) + print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { - dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) + rm("./files/synapse_storage_manifest.csv") # clear inputs sapply(clean_tags, FUN = hide) @@ -431,9 +432,8 @@ shinyServer(function(input, output, session) { "Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) + rm("/tmp/synapse_storage_manifest.csv") } } - # delete tmp manifest - unlink("./tmp/synapse_storage_manifest.csv") }) }) From e6a9103c1f16bb66a75be8673e297c6c906b4658 Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Mon, 20 Sep 2021 17:58:44 -0400 Subject: [PATCH 076/260] Revert "Getting develop and main branches in sync (#176)" This reverts commit 4eb5ba33273c7f9c5a940018ba01c057272943cd. --- .Rprofile | 11 - .gitignore | 1 - Shiny_App.Rproj => HTAN_test_shiny.Rproj | 0 README.md | 40 +- app.R | 757 +++++++++++++++++ environment.yml | 2 +- example_config.yaml | 6 - files/synapse_storage_manifest.csv | 2 +- functions/boxEffect.R | 5 - functions/dcWaiter.R | 68 -- functions/metadata_model.py | 13 - functions/utils.R | 8 - functions/validationResult.R | 90 --- global.R | 88 -- init_python_venv.sh | 20 - metadataModelFuns.py | 37 + modules/DTable.R | 45 -- modules/ValidationMsg.R | 35 - modules/csvInfile.R | 47 -- modules/switchTab.R | 43 - renv.lock | 759 ------------------ renv/.gitignore | 3 - renv/activate.R | 157 ---- renv/settings.dcf | 5 - requirements.txt | 61 -- server.R | 439 ---------- .../synapse_func_alias.py => synLoginFun.py | 0 synStoreFuns.py | 30 + synStore_Session.py | 31 + ui.R | 241 ------ www/{img => }/HTAN_text_logo.png | Bin www/config.json | 21 +- www/img/synapse_logo_blk.png | Bin 20190 -> 0 bytes www/{img => }/loading.gif | Bin www/{js => }/readCookie.js | 14 +- www/scss/basic/_animation.scss | 70 -- www/scss/basic/_box.scss | 19 - www/scss/basic/_button.scss | 146 ---- www/scss/basic/_message.scss | 36 - www/scss/basic/_variables.scss | 38 - www/scss/main.scss | 14 - www/scss/section/_content.scss | 60 -- www/scss/section/_footer.scss | 49 -- www/scss/section/_header.scss | 92 --- www/scss/section/_sidebar.scss | 82 -- www/styles.css | 60 ++ www/{img => }/synapse_logo.png | Bin 47 files changed, 942 insertions(+), 2803 deletions(-) delete mode 100644 .Rprofile rename Shiny_App.Rproj => HTAN_test_shiny.Rproj (100%) create mode 100644 app.R delete mode 100644 example_config.yaml delete mode 100644 functions/boxEffect.R delete mode 100644 functions/dcWaiter.R delete mode 100644 functions/metadata_model.py delete mode 100644 functions/utils.R delete mode 100644 functions/validationResult.R delete mode 100644 global.R delete mode 100644 init_python_venv.sh create mode 100644 metadataModelFuns.py delete mode 100644 modules/DTable.R delete mode 100644 modules/ValidationMsg.R delete mode 100644 modules/csvInfile.R delete mode 100644 modules/switchTab.R delete mode 100644 renv.lock delete mode 100644 renv/.gitignore delete mode 100644 renv/activate.R delete mode 100644 renv/settings.dcf delete mode 100644 requirements.txt delete mode 100644 server.R rename functions/synapse_func_alias.py => synLoginFun.py (100%) create mode 100644 synStoreFuns.py create mode 100644 synStore_Session.py delete mode 100644 ui.R rename www/{img => }/HTAN_text_logo.png (100%) delete mode 100644 www/img/synapse_logo_blk.png rename www/{img => }/loading.gif (100%) rename www/{js => }/readCookie.js (72%) delete mode 100644 www/scss/basic/_animation.scss delete mode 100644 www/scss/basic/_box.scss delete mode 100644 www/scss/basic/_button.scss delete mode 100644 www/scss/basic/_message.scss delete mode 100644 www/scss/basic/_variables.scss delete mode 100644 www/scss/main.scss delete mode 100644 www/scss/section/_content.scss delete mode 100644 www/scss/section/_footer.scss delete mode 100644 www/scss/section/_header.scss delete mode 100644 www/scss/section/_sidebar.scss create mode 100644 www/styles.css rename www/{img => }/synapse_logo.png (100%) diff --git a/.Rprofile b/.Rprofile deleted file mode 100644 index 407da0f4..00000000 --- a/.Rprofile +++ /dev/null @@ -1,11 +0,0 @@ -.First <- function() { - options( - repos = c( - CRAN = "https://cran.rstudio.com/", - Sage = "http://ran.synapse.org" - ) - ) -} - -options(stringsAsFactors = FALSE) -source("renv/activate.R") diff --git a/.gitignore b/.gitignore index 11623cf0..38f3f3d0 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,3 @@ schematic/token.pickle credentials.json token.pickle **/__pycache__ -config.yaml \ No newline at end of file diff --git a/Shiny_App.Rproj b/HTAN_test_shiny.Rproj similarity index 100% rename from Shiny_App.Rproj rename to HTAN_test_shiny.Rproj diff --git a/README.md b/README.md index eb28829e..9d1b6f5c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,9 @@ # Data Curator App -## Introduction - -The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the schematic Python package. It allows data contributors to easily annotate, validate and submit their metadata. - - ## Setup -### Data Curator App Setup -Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main): +### Data Curator App Setup (frontend) +Follow the steps below to make sure the _Data Curator App_ (frontend) is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main) (backend): Navigate to the location where you want to setup the application (i.e., the _Shiny Server_). Clone the code on this github branch (_shiny-server-main_): @@ -23,34 +18,29 @@ Here, our conda environment name `data_curator_env` is set from the `environment Activate the `data_curator_env` environment: conda activate data_curator_env + +_Note_: +- You can change the name of your conda environment inside `environment.yml` or even use another environment, but please note that you will need to make changes accordingly in the [`app.R`](https://github.com/Sage-Bionetworks/data_curator/blob/shiny-server-develop/app.R#L17) file. +------- -### Schematic Setup +### Schematic Setup (backend) The next step is to install the latest release of the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main) (backend) as a folder `schematic` inside the `data_curator` folder and tie it together with this frontend. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites). +------- -### App Configuration File +### App Configuration file Use the app configuration file `www/config.json` to adapt this app to your DCC. * `manifest schemas`: defines the list of schemas displayed under the "Choose a Metadata Template Type:" dropdown in the application. - * `display_name` : The display name for the dropdown. (e.g. _scRNA-seq Level 1_) - * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. _ScRNA-seqLevel1_) - * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type _assay_. - -* `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) -* `community` : the abbreviated name of the community or project. (e.g. _HTAN_) - - -### Authentication (OAuth) - -This utilizes a Synapse OAuth client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration file. + * `display_name` : The display name for the dropdown. (e.g. "Genomics Assay") + * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. "GenomicsAssay") + * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type "assay". -``` -cp example_config.yaml config.yaml -# Edit config.yaml -chmod 400 config.yaml -``` \ No newline at end of file +* `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. "syn20446927") +* `community` : the abbreviated name of the community or project. (e.g. "HTAN") +} diff --git a/app.R b/app.R new file mode 100644 index 00000000..c325cf89 --- /dev/null +++ b/app.R @@ -0,0 +1,757 @@ +library(shiny) +library(shinyjs) +library(dplyr) +library(shinythemes) +library(shinydashboard) +library(stringr) +library(DT) +library(jsonlite) +library(reticulate) +library(ggplot2) +library(purrr) +library(plotly) +library(shinypop) +library(waiter) + +#########global +use_condaenv('data_curator_env', required = TRUE) +reticulate::import("sys") + +source_python("synLoginFun.py") +source_python("metadataModelFuns.py") + +######### + +ui <- dashboardPage( + skin = "purple", + dashboardHeader( + titleWidth = 250, + title = "Data Curator", + tags$li(class = "dropdown", + tags$a(href = "https://humantumoratlas.org/", target = "_blank", ##insert links and logos of your choice, this is just an example + tags$img(height = "40px", alt = "HTAN LOGO", + src = "HTAN_text_logo.png"))) + ), + dashboardSidebar( + width = 250, + sidebarMenu( + id = "tabs", + menuItem("Instructions", tabName = "instructions", icon = icon("book-open")), + menuItem("Select your Dataset", tabName = "data", icon = icon("mouse-pointer")), + menuItem("Get Metadata Template", tabName = "template", icon = icon("table")), + menuItem("Submit & Validate Metadata", tabName = "upload", icon = icon("upload")), + HTML('
+ Supported by the Human Tumor Atlas Network
+ (U24-CA233243-01)
+ Powered by Sage Bionetworks +
') + ) + ), + dashboardBody( + tags$head( + tags$link(rel = "stylesheet", type = "text/css", href = "styles.css"), + singleton( + includeScript("www/readCookie.js") + )), + uiOutput("title"), + use_notiflix_report(), + tabItems( + # First tab content + tabItem(tabName = "instructions", + h2("Instructions for the Data Curator App:"), + h3("1. Go to", strong("Select your Dataset"), "tab - select your project; choose your folder and metadata template type matching your metadata."), + h3("2. Go to", strong("Get Metadata Template"), "tab - click on the link to generate the metadata template, then fill out and download the file as a CSV. If you already have an annotated metadata template, you may skip this step."), + h3("3. Go to", strong("Submit and Validate Metadata"), "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata.") + ), +# second tab content + tabItem(tabName = "data", + h2("Set Dataset and Metadata Template for Curation"), + fluidRow( + box( + status = "primary", + solidHeader = TRUE, + width = 6, + title = "Choose a Project and Folder: ", + selectizeInput(inputId = "var", label = "Project:", + choices = "Generating..."), + uiOutput('folders'), + helpText("If your recently updated folder does not appear, please wait for Synapse to sync and refresh") + ), + box( + status = "primary", + solidHeader = TRUE, + width = 6, + title = "Choose a Metadata Template Type: ", + uiOutput("manifest_display_name") + ) + ) + ), +# Third tab item + tabItem(tabName = "template", + useShinyjs(), + h2("Download Template for Selected Folder"), + fluidRow( + box( + title = "Get Link, Annotate, and Download Template as CSV", + status = "primary", + solidHeader = TRUE, + width = 12, + actionButton("download", "Click to Generate Google Sheets Template"), + hidden( + div( + id = 'text_div', + height = "100%", + htmlOutput("text"), + style = "font-size:18px; background-color: white; border: 1px solid #ccc; border-radius: 3px; margin: 10px 0; padding: 10px" + ) + ), + helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") + ) + + ) + ), + +# Fourth tab content + tabItem(tabName = "upload", + h2("Submit & Validate a Filled Metadata Template"), + fluidRow( + box( + title = "Upload Filled Metadata as a CSV", + solidHeader = TRUE, + status = "primary", + width = 12, + uiOutput('fileInput_ui') + ), + box( + title = "Metadata Preview", + solidHeader = TRUE, + status = "primary", + width = 12, + DT::DTOutput("tbl"), + helpText("Google spreadsheet row numbers are incremented from this table by 1") + ), + box( + title = "Validate Filled Metadata", + status = "primary", + solidHeader = TRUE, + width = 12, + actionButton("validate", "Validate Metadata"), + hidden( + div(id = 'text_div2', + height = "100%", + htmlOutput("text2"), + style = "font-size:18px; background-color: white; border: 1px solid #ccc; border-radius: 3px; margin: 10px 0; padding: 10px" + ), + DT::DTOutput("tbl2"), + actionButton("gsheet_btn", " Click to Generate Google Sheet Link", icon = icon("table")), + div(id = 'gsheet_div', + height = "100%", + htmlOutput("gsheet_link"), + style = "font-size:18px; background-color: white; border: 1px solid #ccc; border-radius: 3px; margin: 10px 0; padding: 10px" + ) + ), + helpText( + HTML("If you have an error, please try editing locally or on google sheet.
+ Reupload your CSV and press the validate button as needed.") + ) + ), + box(title = "Submit Validated Metadata to Synapse", + status = "primary", + solidHeader = TRUE, + width = 12, + uiOutput("submit") + ) + ) + ) + ), + uiOutput("Next_Previous"), + + ## waiter loading screen + use_waiter(), + waiter_show_on_load( + html = tagList( + img(src = "loading.gif"), + h4("Retrieving Synapse information...") + ), + color = "#424874" + ) + ) +) + +server <- function(input, output, session) { + + ########### session global variables + reticulate::source_python("synStore_Session.py") + + ### read config in + config <- jsonlite::fromJSON('www/config.json') + + ### logs in and gets list of projects they have access to + synStore_obj <- NULL + # get_projects_list(synStore_obj) + projects_list <- c() + + projects_namedList <- c() + + proj_folder_manifest_cells <- c() + + folder_synID <- NULL + + filename_list <- c() + ############ + + ### synapse cookies + session$sendCustomMessage(type = "readCookie", message = list()) + + ### initial login front page items + observeEvent(input$cookie, { + + ## login and update session; otherwise, notify to login to Synapse first + tryCatch({ + + ### logs in + syn_login(sessionToken = input$cookie, rememberMe = FALSE) + + ### welcome message + output$title <- renderUI({ + titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) + }) + + ### updating global vars with values for projects + # synStore_obj <<- syn_store(config$main_fileview, token = input$cookie) + synStore_obj <<- syn_store(token = input$cookie) + + # get_projects_list(synStore_obj) + projects_list <<- syn_store$getStorageProjects(synStore_obj) + + for (i in seq_along(projects_list)) { + projects_namedList[projects_list[[i]][[2]]] <<- projects_list[[i]][[1]] + } + + ### updates project dropdown + updateSelectizeInput(session, 'var', choices = sort(names(projects_namedList))) + + ### update waiter loading screen once login successful + waiter_update( + html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3(sprintf("Welcome, %s!", syn_getUserProfile()$userName)) + ) + ) + Sys.sleep(2) + waiter_hide() + }, error = function(err) { + Sys.sleep(2) + waiter_update( + html = tagList( + img(src = "synapse_logo.png", height = "120px"), + h3("Looks like you're not logged in!"), + span("Please ", a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), + " to Synapse, then refresh this page.") + ) + ) + }) + }) + + + ###### BUTTONS STUFF !!! remove last arrow + Previous_Button=tags$div(actionButton("Prev_Tab",HTML(' +
+'))) + Next_Button=div(actionButton("Next_Tab",HTML(' +
+'))) + +list_tabs <- c("instructions", "data", "template", "upload") + + output$Next_Previous <- renderUI({ + + tab_list=list_tabs + if ( input[["tabs"]] == "upload" ){ + # column(1,offset=1,Previous_Button) + } else if (input[["tabs"]] == "instructions" ) { + column(1,offset = 10,Next_Button) + } else { + div(column(1,offset=1,Previous_Button),column(1,offset=8,Next_Button)) + } + }) + + observeEvent(input$Prev_Tab, + { + tab_list=list_tabs + current_tab=which(tab_list==input[["tabs"]]) + updateTabItems(session,"tabs",selected=tab_list[current_tab-1]) + }) + + observeEvent(input$Next_Tab, + { + tab_list=list_tabs + current_tab=which(tab_list==input[["tabs"]]) + updateTabItems(session,"tabs",selected=tab_list[current_tab+1]) + }) + + ####### BUTTONS END + + ### lists folder datasets if exists in project + observeEvent(ignoreNULL = TRUE, ignoreInit = TRUE, + input$var, { + output$folders = renderUI({ + selected_project <- input$var + + # if selected_project not empty + if (!is.null(selected_project)) { + project_synID <- projects_namedList[[selected_project]] ### get synID of selected project + + ### gets folders per project + folder_list <- syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folderNames <- names(folders_namedList) + + ### updates foldernames + selectInput(inputId = "dataset", label = "Folder:", choices = folderNames) + } + }) + }) + +### mapping from display name to schema name +schema_name <- config$manifest_schemas$schema_name +display_name <- config$manifest_schemas$display_name + +output$manifest_display_name <- renderUI({ + selectInput(inputId = "template_type", + label = "Template:", + choices = display_name) + +}) + +observeEvent({input$dataset + input$template_type + }, { + sapply(c('text_div', 'text_div2', 'tbl2', 'gsheet_btn', 'gsheet_div', 'submitButton'), FUN=hide) +}) + +schema_to_display_lookup <- data.frame(schema_name, display_name) + + # loading screen for template link generation + manifest_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Generating link...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + ###shows new metadata link when get gsheets template button pressed OR updates old metadata if is exists + observeEvent( + input$download, { + + manifest_w$show() + + selected_folder <- input$dataset + selected_project <- input$var + + ###lookup schema template name + template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F ] + template_type <- as.character(template_type_df$schema_name) + + project_synID <- projects_namedList[[selected_project]] ### get synID of selected project + + folder_list <- syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### checks if a manifest already exists + existing_manifestID <- syn_store$updateDatasetManifestFiles(synStore_obj, folder_synID) + + ### if there isn't an existing manifest make a new one + if (existing_manifestID == '') { + file_list <- syn_store$getFilesInStorageDataset(synStore_obj, folder_synID) + file_namedList <- c() + for (i in seq_along(file_list)) { + file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] + } + filename_list <- names(file_namedList) + + + manifest_url <- metadata_model$getModelManifest(paste0(config$community," ", input$template_type), template_type, filenames = as.list(filename_list)) + ### make sure not scalar if length of list is 1 in R + ## add in the step to convert names later ### + + output$text <- renderUI({ + tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### + }) + } else { + ### if the manifest already exists + manifest_entity <- syn_get(existing_manifestID) + # prepopulatedManifestURL = mm.populateModelManifest("test_update", entity.path, component) + manifest_url <- metadata_model$populateModelManifest(paste0(config$community," ", input$template_type), manifest_entity$path, template_type) + + output$text <- renderUI({ + tags$a(href = manifest_url, manifest_url, target = "_blank") + }) + } + ## links shows in text box + show('text_div') + ### if want a progress bar need more feedback from API to know how to increment progress bar ### + + manifest_w$hide() + } + ) + + ### renders fileInput ui + output$fileInput_ui <- renderUI({ + + fileInput("file1", "Upload CSV File", + accept = c('text/csv', + 'text/comma-separated-values', + '.csv')) + }) + + ### reads csv file and previews + rawData <- eventReactive(input$file1, { + infile <- readr::read_csv(input$file1$datapath, na = c("", "NA")) + ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + infile <- infile[, !grepl('^X', colnames(infile))] + infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + }) + + observeEvent(input$file1, { + sapply(c('text_div2', 'tbl2', 'gsheet_btn', 'gsheet_div', 'submitButton'), FUN=hide) + }) + + ### renders in DT for preview + observeEvent( + rawData(), { + output$tbl <- DT::renderDT({ + datatable(rawData(), options = list(lengthChange = FALSE, scrollX = TRUE) + ) + }) + + } + ) + + ## loading screen for validating metadata + validate_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Validating...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + ### toggles validation status when validate button pressed + observeEvent( + input$validate, { + + validate_w$show() + + ###lookup schema template name + template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F ] + template_type <- as.character(template_type_df$schema_name) + + annotation_status <- metadata_model$validateModelManifest(input$file1$datapath, template_type) + + show('text_div2') + + + if (length(annotation_status) != 0) { + + # mismatched template index + inx_mt <- which(sapply(annotation_status, function(x) grepl("Component value provided is: .*, whereas the Template Type is: .*", x[[3]]))) + + if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template + + # get all mismatched components + error_values <- sapply(annotation_status[inx_mt], function(x) x[[4]][[1]]) %>% unique() + column_names <- "Component" + + # error messages for mismatch + mismatch_c <- error_values %>% sQuote %>% paste(collapse = ", ") + type_error <- paste0("The submitted metadata contains << ", mismatch_c, " >> in the Component column, but requested validation for << ", input$template_type, " >>.") + help_msg <- paste0("Please check that you have selected the correct template in the Select your Dataset tab and + ensure your metadata contains only one template, e.g. ", input$template_type, ".") + + # get wrong columns and values for updating preview table + errorDT <- data.frame(Column=sapply(annotation_status[inx_mt], function(i) i[[2]]), + Value=sapply(annotation_status[inx_mt], function(i) i[[4]][[1]])) + + } else { + + type_error <- paste0("The submitted metadata have ", length(annotation_status), " errors.") + help_msg <- NULL + + errorDT <- data.frame(Column=sapply(annotation_status, function(i) i[[2]]), + Value=sapply(annotation_status, function(i) i[[4]][[1]]), + Error=sapply(annotation_status, function(i) i[[3]])) + # sort rows based on input column names + errorDT <- errorDT[order(match(errorDT$Column, colnames(rawData()))),] + + # output error messages as data table + show("tbl2") + output$tbl2 <- DT::renderDT({ + datatable(errorDT, caption = "The errors are also highlighted in the preview table above.", + rownames = FALSE, options = list(pageLength = 50, scrollX = TRUE, + scrollY = min(50*length(annotation_status), 400), + lengthChange = FALSE, info = FALSE, searching = FALSE) + ) + }) + } + + validate_w$update( + html = h3(sprintf("%d errors found", length(annotation_status))) + ) + + ### format output text + output$text2 <- renderUI({ + tagList( + HTML("Your metadata is invalid according to the data model.

"), + HTML(type_error, "

"), + HTML(help_msg) + ) + }) + + ### update DT view with incorrect values + ### currently only one column, requires backend support of multiple + output$tbl <- DT::renderDT({ + datatable(rawData(), + options = list(lengthChange = FALSE, scrollX = TRUE) + ) %>% formatStyle(errorDT$Column, + backgroundColor = styleEqual(errorDT$Value, rep("yellow", length(errorDT$Value) ) )) ## how to have multiple errors + }) + + show('gsheet_btn') + + } else { + output$text2 <- renderUI({ + HTML("Your metadata is valid!") + }) + + ### show submit button + output$submit <- renderUI({ + actionButton("submitButton", "Submit to Synapse") + }) + + } + Sys.sleep(2) + validate_w$hide() + } + ) + + # if user click gsheet_btn, generating gsheet + observeEvent( + input$gsheet_btn, { + + # loading screen for Google link generation + gsheet_w <- Waiter$new( + html = tagList( + spin_plus(), br(), + h4("Generating link...") + ), + color = "rgba(66, 72, 116, .9)" + ) + + gsheet_w$show() + + ###lookup schema template name + template_type_df <- schema_to_display_lookup[match(input$template_type, schema_to_display_lookup$display_name), 1, drop = F ] + template_type <- as.character(template_type_df$schema_name) + + ## if error not empty aka there is an error + filled_manifest <- metadata_model$populateModelManifest(paste0(config$community," ", input$template_type), input$file1$datapath, template_type) + + show('gsheet_div') + + output$gsheet_link <- renderUI({ + # tags$a(href = filled_manifest, filled_manifest, target = "_blank") + HTML(paste0('Edit on the Google Sheet.')) + }) + + hide('gsheet_btn') # hide btn once link generated + + gsheet_w$hide() + }) + + ## loading screen for submitting data + submit_w <- Waiter$new( + html = tagList( + img(src = "loading.gif"), + h4("Submitting...") + ), + color = "#424874" + ) + + ###submit button + observeEvent( + input$submitButton, { + + submit_w$show() + + ### reads in csv + infile <- readr::read_csv(input$file1$datapath, na = c("", "NA")) + + ### remove empty rows/columns where readr called it "X"[digit] for unnamed col + infile <- infile[, !grepl('^X', colnames(infile))] + infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + + ### IF an assay component selected (define assay components) + ## note for future - the type to filter (eg assay) on could probably also be a config choice + assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type=="assay"] + + ### and adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files + if ( input$template_type %in% assay_schemas ) { + + ### make into a csv or table for assay components + ### already has entityId + if ("entityId" %in% colnames(infile)) { + + write.csv(infile, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "") + + } else { + # if not get ids + selected_folder <- input$dataset + selected_project <- input$var + + project_synID <- projects_namedList[[selected_project]] ### get synID of selected project + folder_list <- syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + + folder_synID <- folders_namedList[[selected_folder]] + + file_list <- syn_store$getFilesInStorageDataset(synStore_obj, folder_synID) + file_namedList <- c() + for (i in seq_along(file_list)) { + file_namedList[file_list[[i]][[2]]] <- file_list[[i]][[1]] + } + + files_df <- stack(file_namedList) + colnames(files_df) <- c("entityId", "Filename") + files_entity <- inner_join(infile, files_df, by = "Filename") + + write.csv(files_entity, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "") + } + selected_project <- input$var + selected_folder <- input$dataset + + project_synID <- projects_namedList[[selected_project]] ### get synID of selected project + + folder_list <- syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### associates metadata with data and returns manifest id + manifest_id <- syn_store$associateMetadataWithFiles(synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID) + print(manifest_id) + manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) + ### if no error + if (startsWith(manifest_id, "syn") == TRUE) { + nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) + rm("./files/synapse_storage_manifest.csv") + + ### clear inputs + output$text2 <- renderUI({ + HTML("") + }) + output$submit <- renderUI({ + }) + + ### rerenders fileinput UI + output$fileInput_ui <- renderUI({ + fileInput("file1", "Upload CSV File", + accept = c('text/csv', + 'text/comma-separated-values', + '.csv')) + }) + ### renders empty df + output$tbl <- DT::renderDT( + datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0))) + ) + + } else { + submit_w$update( + html = tagList( + img(src = "synapse_logo.png", height = "115px"), + h3("Uh oh, looks like something went wrong!"), + span(manifest_id, " is not a valid Synapse ID. Try again?") + ) + ) + rm("/tmp/synapse_storage_manifest.csv") + } + + } else { ## if not assay type tempalte + write.csv(infile, file = "./files/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "") + + selected_project <- input$var + selected_folder <- input$dataset + + project_synID <- projects_namedList[[selected_project]] ### get synID of selected project + # folder_synID <- get_folder_synID(synStore_obj, project_synID, selected_folder) + + folder_list <- syn_store$getStorageDatasetsInProject(synStore_obj, project_synID) + folders_namedList <- c() + for (i in seq_along(folder_list)) { + folders_namedList[folder_list[[i]][[2]]] <- folder_list[[i]][[1]] + } + folder_synID <- folders_namedList[[selected_folder]] + + ### associates metadata with data and returns manifest id + manifest_id <- syn_store$associateMetadataWithFiles(synStore_obj, "./files/synapse_storage_manifest.csv", folder_synID) + print(manifest_id) + manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) + + ### if uploaded provided valid synID message + if (startsWith(manifest_id, "syn") == TRUE) { + nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) + rm("./files/synapse_storage_manifest.csv") + + ### clear inputs + output$text2 <- renderUI({ + HTML("") + }) + output$submit <- renderUI({ + }) + + ### rerenders fileinput UI + output$fileInput_ui <- renderUI({ + fileInput("file1", "Upload CSV File", + accept = c('text/csv', + 'text/comma-separated-values', + '.csv')) + }) + ### renders empty df + output$tbl <- DT::renderDT( + datatable(as.data.frame(matrix(0, ncol = 0, nrow = 0))) + ) + + } else { + submit_w$update( + html = tagList( + img(src = "synapse_logo.png", height = "115px"), + h3("Uh oh, looks like something went wrong!"), + span(manifest_id, " is not a valid Synapse ID. Try again?") + ) + ) + rm("/tmp/synapse_storage_manifest.csv") + } + } + Sys.sleep(3) + submit_w$hide() + + }) + + +} + + +shinyApp(ui, server) diff --git a/environment.yml b/environment.yml index 325783c6..d5e40aa8 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: data_curator_env_oauth +name: data_curator_env channels: - defaults dependencies: diff --git a/example_config.yaml b/example_config.yaml deleted file mode 100644 index 3908931e..00000000 --- a/example_config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# This file contains the oauth client id and secret required for -# the application. This file needs to have chmod 400 permissions -# client_id and APP_URL has to be a string -client_id: -client_secret: -APP_URL: diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv index 5bba5bde..becd43b4 100644 --- a/files/synapse_storage_manifest.csv +++ b/files/synapse_storage_manifest.csv @@ -1 +1 @@ -Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId +CancerType,LibraryConstructionMethod,HTANParticipantID,Filename,HTANSampleID,entityId diff --git a/functions/boxEffect.R b/functions/boxEffect.R deleted file mode 100644 index bac6a224..00000000 --- a/functions/boxEffect.R +++ /dev/null @@ -1,5 +0,0 @@ -boxEffect <- function(zoom = FALSE, float = FALSE) { - # this is cleaner way, one caveat: need to change zoom scale in scss file - toggleClass(selector = ".box", class = "box-zoom", condition = zoom) - toggleClass(selector = ".box", class = "box-float", condition = float) -} diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R deleted file mode 100644 index 00f90a61..00000000 --- a/functions/dcWaiter.R +++ /dev/null @@ -1,68 +0,0 @@ -# This is script to wrap up the waiter screen for data curator app -# TODO: maybe we could split into UI and server if we need - -dcWaiter <- function(stage = c("show", "update", "hide"), - isLogin = FALSE, isPass = TRUE, usrName = NULL, - sleep = 2, msg = NULL, spin = NULL) { - # validate arguments - if (!is.logical(isLogin)) stop("isLogin must be a boolean") - if (!is.logical(isPass)) stop("isPass must be a boolean") - if (!is.numeric(sleep)) stop("sleep must be a numeric") - if (!stage %in% c("show", "update", "hide")) { - stop("Please provide a value for stage: 'show', 'update' or 'hide'.") - } - if (is.null(msg)) msg <- "Loading ..." - if (is.null(spin)) spin <- spin_plus() - - # if "hide", proceed hiding process immediately and exit function - if (stage == "hide") { - Sys.sleep(sleep) - return(waiter_hide()) - } - - # log in screen - if (isLogin) { - # The message on initial loading page are not customizable - if (stage == "show") { - waiter_show_on_load( - html = tagList( - img(src = "img/loading.gif"), - h4("Retrieving Synapse information...") - ), - color = "#424874" - ) - } else if (isPass) { - waiter_update(html = tagList( - img(src = "img/synapse_logo.png", height = "120px"), - h3(sprintf("Welcome, %s!", usrName)) - )) - Sys.sleep(sleep) - waiter_hide() - } else { - # ensure the synapse logo image is stored in www/ - waiter_update(html = tagList( - img(src = "img/synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), span( - "Please ", a("login", - href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" - ), - " to Synapse, then refresh this page." - ) - )) - } - } else { - # other loading screens - - if (stage == "show") { - waiter_show( - html = tagList(spin, br(), h3(msg)), - color = "rgba(66, 72, 116, .9)" - ) - } else { - Sys.sleep(2) # has to put at least 2s before to make update work - waiter_update(html = tagList(spin, br(), h3(msg))) - Sys.sleep(sleep) - waiter_hide() - } - } -} diff --git a/functions/metadata_model.py b/functions/metadata_model.py deleted file mode 100644 index 378fad67..00000000 --- a/functions/metadata_model.py +++ /dev/null @@ -1,13 +0,0 @@ -from schematic.models.metadata import MetadataModel -from schematic import CONFIG - - -config = CONFIG.load_config("config.yml") - -inputMModelLocation = CONFIG["model"]["input"]["location"] -inputMModelLocationType = CONFIG["model"]["input"]["file_type"] - -manifest_title = CONFIG["manifest"]["title"] -manifest_data_type = CONFIG["manifest"]["data_type"] - -metadata_model = MetadataModel(inputMModelLocation, inputMModelLocationType) diff --git a/functions/utils.R b/functions/utils.R deleted file mode 100644 index 76e230fc..00000000 --- a/functions/utils.R +++ /dev/null @@ -1,8 +0,0 @@ - -list2Vector <- function(list) { - vector <- c() - for (i in seq_along(list)) { - vector[list[[i]][[2]]] <- list[[i]][[1]] - } - return(vector) -} diff --git a/functions/validationResult.R b/functions/validationResult.R deleted file mode 100644 index 2d9983f4..00000000 --- a/functions/validationResult.R +++ /dev/null @@ -1,90 +0,0 @@ -validationResult <- function(valRes, template, inFile) { - validation_res <- NULL - error_msg <- NULL - help_msg <- NULL - outMsg <- NULL - errorDT <- NULL - errorType <- NULL - - if (!is.null(inFile) && !is.null(template) && length(inFile) != 0) { - if (length(valRes) != 0) { - validation_res <- "invalid" - # mismatched template index - inx_mt <- which(sapply(valRes, function(x) { - grepl( - "Component value provided is: .*, whereas the Template Type is: .*", - x[[3]] - ) - })) - # missing column index - inx_ws <- which(sapply(valRes, function(x) { - grepl( - "Wrong schema", - x[[2]] - ) - })) - - if (length(inx_mt) > 0) { - # mismatched error(s): selected template mismatched with validating template - errorType <- "Mismatched Template" - # get all mismatched components - error_values <- sapply(valRes[inx_mt], function(x) x[[4]][[1]]) %>% - unique() - - # error messages for mismatch - mismatch_c <- error_values %>% - sQuote() %>% - paste(collapse = ", ") - error_msg <- paste0( - "The submitted metadata contains << ", - mismatch_c, " >> in the Component column, but requested validation for << ", - template, " >>." - ) - help_msg <- paste0( - "Please check that you have selected the correct template in the Select your Dataset tab and - ensure your metadata contains only one template, e.g. ", - template, "." - ) - } else if (length(inx_ws) > 0) { - # wrong schema error(s): validating metadata miss any required columns - errorType <- "Wrong Schema" - error_msg <- "The submitted metadata does not contain all required column(s)." - help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and - ensure your metadata contains all required columns." - } else { - errorType <- "Invalid Value" - error_msg <- paste0( - "The submitted metadata have ", length(valRes), - " errors." - ) - } - - errorDT <- data.frame( - Column = sapply(valRes, function(i) i[[2]]), - Value = sapply(valRes, function(i) i[[4]][[1]]), - Error = sapply(valRes, function(i) i[[3]]) - ) - - # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] - # TODO: to reduce parameter, sort just based on alphabetic - # errorDT <- errorDT[order(errorDT$Column),] - } else { - validation_res <- "valid" - errorType <- "No Error" - } - - # combine all error messages into one, add an extra empty line to bottom - outMsg <- paste0(c( - paste0("Your metadata is ", validation_res, " !!!"), - error_msg, help_msg - ), collapse = "

") - } - - return(list( - validationRes = validation_res, - outMsg = outMsg, - errorDT = errorDT, - errorType = errorType - )) -} diff --git a/global.R b/global.R deleted file mode 100644 index 88bfb1eb..00000000 --- a/global.R +++ /dev/null @@ -1,88 +0,0 @@ -suppressPackageStartupMessages({ - library(shiny) - library(httr) - library(rjson) - library(yaml) - library(shinyjs) - library(dplyr) - library(shinythemes) - library(shinydashboard) - library(stringr) - library(DT) - library(jsonlite) - library(reticulate) - library(ggplot2) - library(purrr) - library(plotly) - library(shinypop) - library(waiter) - library(readr) - library(sass) - library(shinydashboardPlus) -}) - -# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" - -has_auth_code <- function(params) { - # params is a list object containing the parsed URL parameters. Return TRUE if - # based on these parameters, it looks like auth code is present that we can - # use to get an access token. If not, it means we need to go through the OAuth - # flow. - return(!is.null(params$code)) -} - -oauth_client <- yaml.load_file("config.yaml") - -client_id <- toString(oauth_client$client_id) -client_secret <- oauth_client$client_secret -APP_URL <- oauth_client$APP_URL -if (is.null(client_id)) stop("config.yaml is missing client_id") -if (is.null(client_secret)) stop("config.yaml is missing client_secret") -if (is.null(APP_URL)) stop("config.yaml is missing client_secret") - -app <- oauth_app("shinysynapse", - key = client_id, - secret = client_secret, - redirect_uri = APP_URL -) - -# These are the user info details ('claims') requested from Synapse: -claims <- list( - family_name = NULL, - given_name = NULL, - email = NULL, - email_verified = NULL, - userid = NULL, - orcid = NULL, - is_certified = NULL, - is_validated = NULL, - validated_given_name = NULL, - validated_family_name = NULL, - validated_location = NULL, - validated_email = NULL, - validated_company = NULL, - validated_at = NULL, - validated_orcid = NULL, - company = NULL -) - -claimsParam <- toJSON(list(id_token = claims, userinfo = claims)) -api <- oauth_endpoint( - authorize = paste0("https://signin.synapse.org?claims=", claimsParam), - access = "https://repo-prod.prod.sagebase.org/auth/v1/oauth2/token" -) - -# The 'openid' scope is required by the protocol for retrieving user information. -scope <- "openid view download modify" - -# Activate conda env -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") - -# Import functions/modules -source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) -sapply(source_files, FUN = source) - -# Global variables -datatypes <- c("project", "folder", "template") -options(sass.cache = FALSE) diff --git a/init_python_venv.sh b/init_python_venv.sh deleted file mode 100644 index 67250c5f..00000000 --- a/init_python_venv.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# a sample initialization of a virtualenv for use with -# this project. a local virtualenv is created, the python -# dependencies are installed into it, and an environment -# variable is set to hint reticulate to use this virtualenv. - -# this assumes that a python3 command is available on the path -# with a python version >= 3.6 - -# Sample usage: -# $source init_python_venv.sh - -python3 -m venv venv -source venv/bin/activate - -pip install -r requirements.txt - -export RETICULATE_PYTHON=venv/bin/python - diff --git a/metadataModelFuns.py b/metadataModelFuns.py new file mode 100644 index 00000000..830886ea --- /dev/null +++ b/metadataModelFuns.py @@ -0,0 +1,37 @@ +# import json +from schematic.models.metadata import MetadataModel + +from schematic import CONFIG + +config = CONFIG.load_config("./schematic/config.yml") + +#inputMModelLocation = "./schemas/exampleSchemaReq.jsonld" +#inputMModelLocation = "./HTAN-data-pipeline/schemas/scRNASeq.jsonld" +# inputMModelLocation = "./HTAN-data-pipeline/schemas/HTAPP.jsonld" +inputMModelLocation = CONFIG["model"]["input"]["location"] +inputMModelLocationType = CONFIG["model"]["input"]["file_type"] + +manifest_title = CONFIG["manifest"]["title"] +manifest_data_type = CONFIG["manifest"]["data_type"] +# datasetType = "scRNASeq" +# modelType = "TableA" + +metadata_model = MetadataModel(inputMModelLocation, inputMModelLocationType) +metadata_model.getModelManifest(title=manifest_title, + rootNode=manifest_data_type) + +### function for getting model Manifest +# mm.getModelManifest(modelType, additionalMetadata = {"Filename":["MantonCB1_HiSeq_1_S1_L001_R1_001.fastq.gz"]} ) +# getModelManifest = mm.getModelManifest + +# ### function for validating manifest +# # mm.validateModelManifest(manifest_path, datasetType) +# validateModelManifest = mm.validateModelManifest + +# ### populates manifest with path to csv +# populateModelManifest = mm.populateModelManifest + +# ### gets dependencies +# # "Generating dependency graph and ordering dependencies") +# # dependencies = mm.getOrderedModelNodes(component, "requiresDependency") +# getDependencies = mm.getOrderedModelNodes diff --git a/modules/DTable.R b/modules/DTable.R deleted file mode 100644 index 9aca7a4c..00000000 --- a/modules/DTable.R +++ /dev/null @@ -1,45 +0,0 @@ -# This moduel is to peformrender DT table function for preview/highlight - -DTableUI <- function(id) { - ns <- NS(id) - DT::DTOutput(ns("table")) -} - -DTableServer <- function(id, data, - rownames = FALSE, caption = NULL, - options = list(lengthChange = FALSE, scrollX = TRUE), - highlight = NULL, hightlight.col = NULL, hightlight.value = NULL) { - if (!is.null(highlight)) { - if (!highlight %in% c("full", "partial")) { - Stop("Please choose a value for highlight: 'full', 'partial'.") - } - - column <- hightlight.col - value <- hightlight.value - } - - df <- datatable(data, - caption = caption, - rownames = rownames, - options = options - ) - - if (!is.null(highlight)) { - if (highlight == "full") { - df <- df %>% - formatStyle(1, target = "row", backgroundColor = "yellow") - } else if (highlight == "partial") { - df <- df %>% - formatStyle(column, backgroundColor = styleEqual( - value, rep("yellow", length(value)) - )) - } - } - - moduleServer( - id, - function(input, output, session) { - output$table <- renderDT(df) - } - ) -} diff --git a/modules/ValidationMsg.R b/modules/ValidationMsg.R deleted file mode 100644 index fc34fd46..00000000 --- a/modules/ValidationMsg.R +++ /dev/null @@ -1,35 +0,0 @@ - -# format and process validation results from schematic - -ValidationMsgUI <- function(id) { - ns <- NS(id) - htmlOutput(ns("results")) -} - -ValidationMsgServer <- function(id, valRes, template, inFile) { - moduleServer( - id, - function(input, output, session) { - output$results <- renderUI({ - text_class <- - ifelse(!is.null(valRes$validationRes) && valRes$validationRes == "valid" && length(valRes$validationRes) != 0, - "success_msg", "error_msg" - ) - - tagList( - # TODO: remove first two checking once we set dropdown value as 1st selection by default - if (is.null(template)) { - span(class = text_class, HTML("Please select a template from the 'Select your Dataset' tab !

")) - }, - if (is.null(inFile)) { - span(class = text_class, HTML("Please upload a filled template !")) - }, - if (!is.null(inFile) & length(inFile) == 0) { - span(class = text_class, HTML("File is empty. Please upload a filled template !")) - }, - span(class = text_class, HTML(valRes$outMsg)) - ) - }) - } - ) -} diff --git a/modules/csvInfile.R b/modules/csvInfile.R deleted file mode 100644 index 481c2341..00000000 --- a/modules/csvInfile.R +++ /dev/null @@ -1,47 +0,0 @@ -# This module is to read csv file - -csvInfileUI <- function(id) { - ns <- NS(id) - tagList( - # renders fileInput ui - fileInput(ns("file"), "Upload CSV File", accept = c( - "text/csv", "text/comma-separated-values", - ".csv" - )) - ) -} - -csvInfileServer <- function(id, na = c("", "NA"), colsAsCharacters = FALSE, keepBlank = FALSE) { - moduleServer( - id, - function(input, output, session) { - usrFile <- eventReactive(ignoreNULL = FALSE, input$file, { - # if no file uploaded, return null - if (is.null(input$file)) { - return(NULL) - } - - if (colsAsCharacters) { - infile <- read_csv(input$file$datapath, na = na, col_types = cols(.default = "c")) - } else { - infile <- read_csv(input$file$datapath, na = na, col_types = cols()) - } - - if (keepBlank) { - # change NA to blank to match schema output) - infile <- infile %>% replace(., is.na(.), "") - } - - # remove empty rows/columns where readr called it 'X'[digit] for unnamed col - infile <- infile[, !grepl("^X", colnames(infile))] - infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] - }) - return(list( - raw = reactive({ - input$file - }), - data = usrFile - )) - } - ) -} diff --git a/modules/switchTab.R b/modules/switchTab.R deleted file mode 100644 index 7705cdd4..00000000 --- a/modules/switchTab.R +++ /dev/null @@ -1,43 +0,0 @@ -# This is the module to create one/two buttons to switch to previous/next tab -# TODO: Add more descriptions - -tagID <- c("Next", "Prev") # Do not change order, to ensure server works properly - -switchTabUI <- function(id, direction = c("left", "right", "both")) { - - # namespace - ns <- NS(id) - tags$head() - # if we put buttons in server, buttons will change after observing tabs' change delay - # which cause some add-remove tranisition in delay - # now, put buttons in UI - btn_prev <- actionButton(ns(tagID[2]), class = "switch-tab-prev", lapply(1:3, function(i) tags$i(class = "fa fa-angle-left"))) - btn_next <- actionButton(ns(tagID[1]), class = "switch-tab-next", lapply(1:3, function(i) tags$i(class = "fa fa-angle-right"))) - fluidRow( - if (direction == "right") { - column(1, offset = 10, btn_next) - } else if (direction == "left") { - column(1, offset = 1, btn_prev) - } else { - div(column(1, offset = 1, btn_prev), column(1, offset = 8, btn_next)) - } - ) -} - - -switchTabServer <- function(id, tabId, tab, tabList, parent) { - moduleServer( - id, - function(input, output, session) { - lapply(c(-1, 1), function(i) { - tagName <- tagID[i] - observeEvent(input[[tagName]], { - current_tab <- which(tabList == tab) - # need to use parent session to update tab - # TODO: figure out how to call parent inputs in module to minimize args - updateTabItems(parent, tabId, selected = tabList[current_tab + i]) - }) - }) - } - ) -} diff --git a/renv.lock b/renv.lock deleted file mode 100644 index 9804e4f4..00000000 --- a/renv.lock +++ /dev/null @@ -1,759 +0,0 @@ -{ - "R": { - "Version": "3.6.3", - "Repositories": [ - { - "Name": "CRAN", - "URL": "https://cran.rstudio.com" - }, - { - "Name": "Sage", - "URL": "http://ran.synapse.org" - } - ] - }, - "Packages": { - "BH": { - "Package": "BH", - "Version": "1.72.0-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f9ce74c6417d61f0782cbae5fd2b7b0" - }, - "DT": { - "Package": "DT", - "Version": "0.14", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a3580ce0309c94d061c23b0afb4accbd" - }, - "MASS": { - "Package": "MASS", - "Version": "7.3-51.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1dad32ac9dbd8057167b2979fb932ff7" - }, - "Matrix": { - "Package": "Matrix", - "Version": "1.2-18", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08588806cba69f04797dab50627428ed" - }, - "R.cache": { - "Package": "R.cache", - "Version": "0.15.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e92a8ea8388c47c82ed8aa435ed3be50" - }, - "R.methodsS3": { - "Package": "R.methodsS3", - "Version": "1.8.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bf6453323755202d5909697b6f7c109" - }, - "R.oo": { - "Package": "R.oo", - "Version": "1.24.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5709328352717e2f0a9c012be8a97554" - }, - "R.utils": { - "Package": "R.utils", - "Version": "2.10.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a9e316277ff12a43997266f2f6567780" - }, - "R6": { - "Package": "R6", - "Version": "2.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "292b54f8f4b94669b08f94e5acce6be2" - }, - "RColorBrewer": { - "Package": "RColorBrewer", - "Version": "1.1-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e031418365a7f7a766181ab5a41a5716" - }, - "Rcpp": { - "Package": "Rcpp", - "Version": "1.0.5", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "125dc7a0ed375eb68c0ce533b48d291f" - }, - "askpass": { - "Package": "askpass", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e8a22846fff485f0be3770c2da758713" - }, - "assertthat": { - "Package": "assertthat", - "Version": "0.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "50c838a310445e954bc13f26f26a6ecf" - }, - "backports": { - "Package": "backports", - "Version": "1.1.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3ef0eac19317fd03c0c854aed581d473" - }, - "base64enc": { - "Package": "base64enc", - "Version": "0.1-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "543776ae6848fde2f48ff3816d0628bc" - }, - "callr": { - "Package": "callr", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "643163a00cb536454c624883a10ae0bc" - }, - "cli": { - "Package": "cli", - "Version": "2.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ff0becff7bfdfe3f75d29aff8f3172dd" - }, - "clipr": { - "Package": "clipr", - "Version": "0.7.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08cf4045c149a0f0eaf405324c7495bd" - }, - "colorspace": { - "Package": "colorspace", - "Version": "1.4-1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6b436e95723d1f0e861224dd9b094dfb" - }, - "commonmark": { - "Package": "commonmark", - "Version": "1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0f22be39ec1d141fd03683c06f3a6e67" - }, - "cpp11": { - "Package": "cpp11", - "Version": "0.2.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "730eebcc741a5c36761f7d4d0f5e37b8" - }, - "crayon": { - "Package": "crayon", - "Version": "1.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0d57bc8e27b7ba9e45dba825ebc0de6b" - }, - "crosstalk": { - "Package": "crosstalk", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ae55f5d7c02f0ab43c58dd050694f2b4" - }, - "curl": { - "Package": "curl", - "Version": "4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2b7d10581cc730804e9ed178c8374bd6" - }, - "data.table": { - "Package": "data.table", - "Version": "1.12.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "cd711af60c47207a776213a368626369" - }, - "desc": { - "Package": "desc", - "Version": "1.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6c8fe8fa26a23b79949375d372c7b395" - }, - "digest": { - "Package": "digest", - "Version": "0.6.25", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f697db7d92b7028c4b3436e9603fb636" - }, - "dplyr": { - "Package": "dplyr", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4011f62581a34080e44105d4aa05a97f" - }, - "ellipsis": { - "Package": "ellipsis", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" - }, - "evaluate": { - "Package": "evaluate", - "Version": "0.14", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" - }, - "fansi": { - "Package": "fansi", - "Version": "0.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7fce217eaaf8016e72065e85c73027b5" - }, - "farver": { - "Package": "farver", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "dad6793a5a1f73c8e91f1a1e3e834b05" - }, - "fastmap": { - "Package": "fastmap", - "Version": "1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "83ab58a0518afe3d17e41da01af13b60" - }, - "fresh": { - "Package": "fresh", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fa54367040deb4537da49b7ac0ee5770" - }, - "fs": { - "Package": "fs", - "Version": "1.4.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8c04112383ca1988e96f429255f95675" - }, - "generics": { - "Package": "generics", - "Version": "0.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8cff1d1391fd1ad8b65877f4c7f2e53" - }, - "ggplot2": { - "Package": "ggplot2", - "Version": "3.3.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4ded8b439797f7b1693bd3d238d0106b" - }, - "glue": { - "Package": "glue", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f43e0d5e85ccb0a4045670c0607ee504" - }, - "gtable": { - "Package": "gtable", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ac5c6baf7822ce8732b343f14c072c4d" - }, - "hexbin": { - "Package": "hexbin", - "Version": "1.28.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3d59212f2814d65dff517e6899813c58" - }, - "hms": { - "Package": "hms", - "Version": "0.5.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "726671f634529d470545f9fd1a9d1869" - }, - "htmltools": { - "Package": "htmltools", - "Version": "0.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7d651b7131794fe007b1ad6f21aaa401" - }, - "htmlwidgets": { - "Package": "htmlwidgets", - "Version": "1.5.1.9001", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "htmlwidgets", - "RemoteUsername": "ramnathv", - "RemoteRef": "master", - "RemoteSha": "6fcc4b03ed3fc42be76d4e43d863db3d85c8babb", - "Hash": "43198daf611c2422a3969bf1f02213b4" - }, - "httpuv": { - "Package": "httpuv", - "Version": "1.5.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4e6dabb220b006ccdc3b3b5ff993b205" - }, - "httr": { - "Package": "httr", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7146fea4685b4252ebf478978c75f597" - }, - "isoband": { - "Package": "isoband", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" - }, - "jsonlite": { - "Package": "jsonlite", - "Version": "1.7.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2657f20b9a74c996c602e74ebe540b06" - }, - "labeling": { - "Package": "labeling", - "Version": "0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "73832978c1de350df58108c745ed0e3e" - }, - "later": { - "Package": "later", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d0a62b247165aabf397fded504660d8a" - }, - "lattice": { - "Package": "lattice", - "Version": "0.20-41", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fbd9285028b0263d76d18c95ae51a53d" - }, - "lazyeval": { - "Package": "lazyeval", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d908914ae53b04d4c0c0fd72ecc35370" - }, - "lifecycle": { - "Package": "lifecycle", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "361811f31f71f8a617a9a68bf63f1f42" - }, - "magrittr": { - "Package": "magrittr", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "41287f1ac7d28a92f0a286ed507928d3" - }, - "mgcv": { - "Package": "mgcv", - "Version": "1.8-31", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bb7e0c4f3557583e1e8d3c9ffb8ba5c" - }, - "mime": { - "Package": "mime", - "Version": "0.9", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e87a35ec73b157552814869f45a63aa3" - }, - "munsell": { - "Package": "munsell", - "Version": "0.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6dfe8bf774944bd5595785e3229d8771" - }, - "nlme": { - "Package": "nlme", - "Version": "3.1-148", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "662f52871983ff3e3ef042c62de126df" - }, - "openssl": { - "Package": "openssl", - "Version": "1.4.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b3209c62052922b6c629544d94c8fa8a" - }, - "pillar": { - "Package": "pillar", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "bdf26e55ccb7df3e49a490150277f002" - }, - "pkgbuild": { - "Package": "pkgbuild", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "404684bc4e3685007f9720adf13b06c1" - }, - "pkgconfig": { - "Package": "pkgconfig", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "01f28d4278f15c76cddbea05899c5d6f" - }, - "pkgload": { - "Package": "pkgload", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b6b150cd4709e0c0c9b5d51ac4376282" - }, - "plotly": { - "Package": "plotly", - "Version": "4.9.2.9000", - "Source": "GitHub", - "RemoteType": "github", - "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", - "RemoteHost": "api.github.com", - "RemoteRepo": "plotly", - "RemoteUsername": "ropensci", - "RemoteRef": "master", - "RemoteSha": "1d1eddda377685cf900ed4a7b16e7796a24b8fe4", - "Hash": "d2858de9ced9d164806a7aa2eebb8b2c" - }, - "praise": { - "Package": "praise", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a555924add98c99d2f411e37e7d25e9f" - }, - "prettyunits": { - "Package": "prettyunits", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" - }, - "processx": { - "Package": "processx", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f4f13345fcb00c51ace12f65dd18749f" - }, - "promises": { - "Package": "promises", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a8730dcbdd19f9047774909f0ec214a4" - }, - "ps": { - "Package": "ps", - "Version": "1.3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "425d938eb9c02906a8ac98c0c2a306b5" - }, - "purrr": { - "Package": "purrr", - "Version": "0.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "97def703420c8ab10d8f0e6c72101e02" - }, - "rappdirs": { - "Package": "rappdirs", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8c8298583adbbe76f3c2220eef71bebc" - }, - "readr": { - "Package": "readr", - "Version": "1.4.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2639976851f71f330264a9c9c3d43a61" - }, - "rematch2": { - "Package": "rematch2", - "Version": "2.1.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "76c9e04c712a05848ae7a23d2f170a40" - }, - "renv": { - "Package": "renv", - "Version": "0.11.0-3", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "renv", - "RemoteUsername": "rstudio", - "RemoteRef": "master", - "RemoteSha": "caf0b39c883168cdd5ebd55a547f6d8689ab8712", - "Hash": "094b6d0b0fe28b14a6780dad836f6356" - }, - "reticulate": { - "Package": "reticulate", - "Version": "1.16", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5db95d35ae4605b46cea66b6e3bcab3e" - }, - "rjson": { - "Package": "rjson", - "Version": "0.2.20", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7d597f982ee6263716b6a2f28efd29fa" - }, - "rlang": { - "Package": "rlang", - "Version": "0.4.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "c06d2a6887f4b414f8e927afd9ee976a" - }, - "rprojroot": { - "Package": "rprojroot", - "Version": "1.3-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f6a407ae5dd21f6f80a6708bbb6eb3ae" - }, - "rstudioapi": { - "Package": "rstudioapi", - "Version": "0.11", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "33a5b27a03da82ac4b1d43268f80088a" - }, - "sass": { - "Package": "sass", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "441417bbd40d5bbd07561cc40fb182ed" - }, - "scales": { - "Package": "scales", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6f76f71042411426ec8df6c54f34e6dd" - }, - "shiny": { - "Package": "shiny", - "Version": "1.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ee4ed72d7a5047d9e73cf922ad66e9c9" - }, - "shinydashboard": { - "Package": "shinydashboard", - "Version": "0.7.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "133639dc106955eee4ffb8ec73edac37" - }, - "shinydashboardPlus": { - "Package": "shinydashboardPlus", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1abe63cd90fe33d3ca211525a0b39af9" - }, - "shinyjs": { - "Package": "shinyjs", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b40a5207b6624f6e2b8cdb50689cdb69" - }, - "shinypop": { - "Package": "shinypop", - "Version": "0.0.1.920", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "shinypop", - "RemoteUsername": "dreamRs", - "RemoteRef": "master", - "RemoteSha": "e3be83f99e85401c59ec7a1dfafa5c92c4f7367b", - "Hash": "095c2c667d27cd2f5829967a48e14229" - }, - "shinythemes": { - "Package": "shinythemes", - "Version": "1.1.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f047210d7d68ea4860a3c0d8cced272" - }, - "sourcetools": { - "Package": "sourcetools", - "Version": "0.1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "947e4e02a79effa5d512473e10f41797" - }, - "stringi": { - "Package": "stringi", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e99d8d656980d2dd416a962ae55aec90" - }, - "stringr": { - "Package": "stringr", - "Version": "1.4.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0759e6b6c0957edb1311028a49a35e76" - }, - "styler": { - "Package": "styler", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2ec6308547ffe73208cef3ef3766fc33" - }, - "sys": { - "Package": "sys", - "Version": "3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "507f3116a38d37ad330a038b3be07b66" - }, - "testthat": { - "Package": "testthat", - "Version": "2.3.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0829b987b8961fb07f3b1b64a2fbc495" - }, - "tibble": { - "Package": "tibble", - "Version": "3.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08bd36bd34b20d4f7971d49e81deaab0" - }, - "tidyr": { - "Package": "tidyr", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7395a05640bf91502dd475a84008d87e" - }, - "tidyselect": { - "Package": "tidyselect", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6ea435c354e8448819627cf686f66e0a" - }, - "utf8": { - "Package": "utf8", - "Version": "1.1.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" - }, - "vctrs": { - "Package": "vctrs", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1739235995f08583db4095a28c357207" - }, - "viridisLite": { - "Package": "viridisLite", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ce4f6271baa94776db692f1cb2055bee" - }, - "waiter": { - "Package": "waiter", - "Version": "0.1.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7bfebcea9f02aa9b2821fb4f529031e6" - }, - "withr": { - "Package": "withr", - "Version": "2.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ecd17882a0b4419545691e095b74ee89" - }, - "xfun": { - "Package": "xfun", - "Version": "0.15", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ddeca7650052ff9131ac7c41a9a77b3b" - }, - "xtable": { - "Package": "xtable", - "Version": "1.8-4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" - }, - "yaml": { - "Package": "yaml", - "Version": "2.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2826c5d9efb0a88f657c7a679c7106db" - } - } -} diff --git a/renv/.gitignore b/renv/.gitignore deleted file mode 100644 index 82740ba9..00000000 --- a/renv/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -library/ -python/ -staging/ diff --git a/renv/activate.R b/renv/activate.R deleted file mode 100644 index 924c2d38..00000000 --- a/renv/activate.R +++ /dev/null @@ -1,157 +0,0 @@ - -local({ - - # the requested version of renv - version <- "0.8.2" - - # avoid recursion - if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) - return(invisible(TRUE)) - - # signal that we're loading renv during R startup - Sys.setenv("RENV_R_INITIALIZING" = "true") - on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) - - # signal that we've consented to use renv - options(renv.consent = TRUE) - - # load the 'utils' package eagerly -- this ensures that renv shims, which - # mask 'utils' packages, will come first on the search path - library(utils, lib.loc = .Library) - - # check to see if renv has already been loaded - if ("renv" %in% loadedNamespaces()) { - - # if renv has already been loaded, and it's the requested version of renv, - # nothing to do - spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") - if (identical(spec[["version"]], version)) - return(invisible(TRUE)) - - # otherwise, unload and attempt to load the correct version of renv - unloadNamespace("renv") - - } - - # construct path to renv in library - libpath <- local({ - - root <- Sys.getenv("RENV_PATHS_LIBRARY", unset = "renv/library") - prefix <- paste("R", getRversion()[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - file.path(root, prefix, R.version$platform) - - }) - - # try to load renv from the project library - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(renv::load()) - - # failed to find renv locally; we'll try to install from GitHub. - # first, set up download options as appropriate (try to use GITHUB_PAT) - install_renv <- function() { - - message("Failed to find installation of renv -- attempting to bootstrap...") - - # ensure .Rprofile doesn't get executed - rpu <- Sys.getenv("R_PROFILE_USER", unset = NA) - Sys.setenv(R_PROFILE_USER = "") - on.exit({ - if (is.na(rpu)) - Sys.unsetenv("R_PROFILE_USER") - else - Sys.setenv(R_PROFILE_USER = rpu) - }, add = TRUE) - - # prepare download options - pat <- Sys.getenv("GITHUB_PAT") - if (nzchar(Sys.which("curl")) && nzchar(pat)) { - fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "curl", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { - fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "wget", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } - - # fix up repos - repos <- getOption("repos") - on.exit(options(repos = repos), add = TRUE) - repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" - options(repos = repos) - - # check for renv on CRAN matching this version - db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) - if ("renv" %in% rownames(db)) { - entry <- db["renv", ] - if (identical(entry$Version, version)) { - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - utils::install.packages("renv", lib = libpath, quiet = TRUE) - message("Done!") - return(TRUE) - } - } - - # try to download renv - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - prefix <- "https://api.github.com" - url <- file.path(prefix, "repos/rstudio/renv/tarball", version) - destfile <- tempfile("renv-", fileext = ".tar.gz") - on.exit(unlink(destfile), add = TRUE) - utils::download.file(url, destfile = destfile, mode = "wb", quiet = TRUE) - message("Done!") - - # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - - # invoke using system2 so we can capture and report output - bin <- R.home("bin") - exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) - args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(libpath), shQuote(destfile)) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - text <- c("Error installing renv", "=====================", output) - writeLines(text, con = stderr()) - } - - - } - - try(install_renv()) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) - -}) diff --git a/renv/settings.dcf b/renv/settings.dcf deleted file mode 100644 index d04fb5e1..00000000 --- a/renv/settings.dcf +++ /dev/null @@ -1,5 +0,0 @@ -external.libraries: -ignored.packages: -snapshot.type: packrat -use.cache: TRUE -vcs.ignore.library: TRUE diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index fa846e13..00000000 --- a/requirements.txt +++ /dev/null @@ -1,61 +0,0 @@ -attrs==19.3.0 -cachetools==4.1.1 -certifi==2020.6.20 -cffi==1.14.0 -chardet==3.0.4 -click==7.1.2 -click-log==0.3.2 -cryptography==2.9.2 -decorator==4.4.2 -Deprecated==1.2.4 -entrypoints==0.3 -fastjsonschema==2.14.4 -google-api-core==1.26.3 -google-api-python-client==1.12.8 -google-auth==1.19.1 -google-auth-httplib2==0.0.4 -google-auth-oauthlib==0.4.4 -googleapis-common-protos==1.53.0 -graphviz==0.16 -httplib2==0.18.1 -idna==2.10 -importlib-metadata==1.7.0 -inflection==0.5.1 -isodate==0.6.0 -jsonschema==3.2.0 -keyring==12.0.2 -keyrings.alt==3.1 -networkx==2.5.1 -numpy==1.19.0 -oauth2client==3.0.0 -oauthlib==3.1.0 -orderedset==2.0.1 -packaging==20.9 -pandas==1.2.3 -pip==20.1.1 -protobuf==3.15.7 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -pycparser==2.20 -pygsheets==2.0.5 -pyparsing==2.4.7 -pyrsistent==0.16.0 -python-dateutil==2.8.1 -pytz==2020.1 -PyYAML==5.4.1 -rdflib==5.0.0 -requests==2.24.0 -requests-oauthlib==1.3.0 -rsa==4.6 -schematicpy==0.1.13 -SecretStorage==2.3.1 -setuptools==52.0.0 -six==1.15.0 -synapseclient==2.3.0 -tabletext==0.1 -toml==0.10.2 -uritemplate==3.0.1 -urllib3==1.25.9 -wheel==0.34.2 -wrapt==1.12.1 -zipp==3.1.0 diff --git a/server.R b/server.R deleted file mode 100644 index 798034b2..00000000 --- a/server.R +++ /dev/null @@ -1,439 +0,0 @@ -# This is the server logic for a Shiny web application. You can find out more -# about building applications with Shiny here: http://shiny.rstudio.com This -# server has been modified to be used specifically on Sage Bionetworks Synapse -# pages to log into Synapse as the currently logged in user from the web portal -# using the session token. https://www.synapse.org - -shinyServer(function(input, output, session) { - params <- parseQueryString(isolate(session$clientData$url_search)) - if (!has_auth_code(params)) { - return() - } - redirect_url <- paste0( - api$access, "?", "redirect_uri=", APP_URL, "&grant_type=", - "authorization_code", "&code=", params$code - ) - # get the access_token and userinfo token - req <- POST(redirect_url, encode = "form", body = "", authenticate(app$key, app$secret, - type = "basic" - ), config = list()) - # Stop the code if anything other than 2XX status code is returned - stop_for_status(req, task = "get an access token") - token_response <- content(req, type = NULL) - access_token <- token_response$access_token - - ######## session global variables ######## - source_python("functions/synapse_func_alias.py") - source_python("functions/metadata_model.py") - # import module that contains SynapseStorage class - synapse_driver <- import("schematic.store.synapse")$SynapseStorage - # read config in - config <- fromJSON("www/config.json") - - # mapping from display name to schema name - template_namedList <- config$manifest_schemas$schema_name - names(template_namedList) <- config$manifest_schemas$display_name - - synStore_obj <- NULL # gets list of projects they have access to - project_synID <- NULL # selected project synapse ID - folder_synID <- NULL # selected foler synapse ID - template_schema_name <- NULL # selected template schema name - - datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) - - tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") - - # add box effects - boxEffect(zoom = TRUE, float = TRUE) - - ######## Initiate Login Process ######## - # synapse cookies - session$sendCustomMessage(type = "readCookie", message = list()) - - # login page - observeEvent(input$cookie, { - # login and update session; otherwise, notify to login to Synapse first - tryCatch( - { - syn_login(sessionToken = input$cookie, rememberMe = FALSE) - - # welcome message - # output$title <- renderUI({ - # titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) - # }) - - # updating global vars with values for projects - synStore_obj <<- synapse_driver(token = input$cookie) - - # get_projects_list(synStore_obj) - projects_list <- synapse_driver$getStorageProjects(synStore_obj) - datatype_list$projects <<- list2Vector(projects_list) - - # updates project dropdown - lapply(c("header_dropdown_", "dropdown_"), function(x) { - lapply(c(1, 3), function(i) { - updateSelectInput(session, paste0(x, datatypes[i]), - choices = sort(names(datatype_list[[i]])) - ) - }) - }) - - # update waiter loading screen once login successful - dcWaiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) - }, - error = function(err) { - message(err) # write log error - dcWaiter("update", isLogin = TRUE, isPass = FALSE) - } - ) - }) - - - ######## Arrow Button ######## - lapply(1:3, function(i) { - switchTabServer(id = paste0("switchTab", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) - }) - - ######## Update Folder List ######## - lapply(c("header_dropdown_", "dropdown_"), function(x) { - observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { - # get synID of selected project - projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] - - # gets folders per project - folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() - - if (x == "dropdown_") { - project_synID <<- projectID - datatype_list$folders <<- folder_list - } - - # updates foldernames - updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) - }) - }) - - ######## Header Dropdown Button ######## - # Adjust header selection dropdown based on tabs - observe({ - if (input[["tabs"]] %in% c("tab_instructions", "tab_data")) { - hide("header_selection_dropdown") - } else { - show("header_selection_dropdown") - addClass(id = "header_selection_dropdown", class = "open") - } - }) - - lapply(datatypes, function(x) { - selector <- paste0("header_dropdown_", x) - observeEvent(input[[selector]], { - if (nchar(input[[selector]]) > 20) { - short <- paste0(substr(input[[selector]], 1, 20), " ...") - runjs(paste0("$('#header_content_", x, " .item').text('", short, "');")) - } - }) - }) - - lapply(datatypes, function(x) { - observeEvent(input[[paste0("dropdown_", x)]], { - updateSelectInput(session, paste0("header_dropdown_", x), - selected = input[[paste0("dropdown_", x)]] - ) - }) - }) - - observeEvent(input$btn_header_update, { - nx_confirm( - inputId = "update_confirm", - title = "Are you sure to update?", - message = "previous selections will also change", - button_ok = "Sure!", - button_cancel = "Nope!" - ) - }) - - observeEvent(input$update_confirm, { - if (input$update_confirm == TRUE) { - lapply(datatypes, function(x) { - updateSelectInput(session, paste0("dropdown_", x), - selected = input[[paste0("header_dropdown_", x)]] - ) - }) - } - }) - - ######## Update Template ######## - # update selected schema template name - observeEvent(input$dropdown_template, { - template_schema_name <<- template_namedList[match(input$dropdown_template, names(template_namedList))] - }) - - # hide tags when users select new template - observeEvent( - { - input$dropdown_folder - input$dropdown_template - }, - { - sapply(clean_tags, FUN = hide) - } - ) - - ######## Template Google Sheet Link ######## - observeEvent(input$btn_download, { - - # loading screen for template link generation - dcWaiter("show", msg = "Generating link...") - - # update selected folder ID - folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - - if (is.null(input$dropdown_template)) { - output$text_download <- renderUI({ - tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) - }) - } else { - # checks if a manifest already exists - existing_manifestID <- synapse_driver$getDatasetManifest( - synStore_obj, - folder_synID - ) - # if there isn't an existing manifest make a new one - if (existing_manifestID == "") { - # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - datatype_list$files <<- list2Vector(file_list) - - manifest_url <- - metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), - template_schema_name, - filenames = as.list(names(datatype_list$files)), - datasetId = folder_synID - ) - - # make sure not scalar if length of list is 1 in R - # add in the step to convert names later - } else { - # if the manifest already exists - manifest_entity <- syn_get(existing_manifestID) - manifest_url <- metadata_model$populateModelManifest(paste0( - config$community, - " ", input$dropdown_template - ), manifest_entity$path, template_schema_name) - } - - output$text_download <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### - }) - } - - dcWaiter("hide", sleep = 1) - # display link - show("div_download") # TODO: add progress bar on (loading) screen - }) - - - ######## Reads .csv File ######## - inFile <- csvInfileServer("inputFile", colsAsCharacters = TRUE, keepBlank = TRUE) - - observeEvent(inFile$data(), { - # hide the validation section when upload a new file - sapply(clean_tags[-1], FUN = hide) - # renders in DT for preview - DTableServer("tbl_preview", inFile$data()) - }) - - ######## Validation Section ####### - observeEvent(input$btn_validate, { - - # loading screen for validating metadata - dcWaiter("show", msg = "Validating...") - - try( - silent = TRUE, - annotation_status <- metadata_model$validateModelManifest( - inFile$raw()$datapath, - template_schema_name - ) - ) - - # validation messages - valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) - ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) - - # if there is a file uploaded - if (!is.null(valRes$validationRes)) { - - # output error messages as data table if it is invalid value type - # render empty if error is not "invaid value" type - ifelse() will not work - if (valRes$errorType == "Invalid Value") { - DTableServer("tbl_validate", valRes$errorDT, - options = list( - pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, - info = FALSE, searching = FALSE - ) - ) - show(NS("tbl_validate", "table")) - } - - # highlight invalue cells in preview table - if (valRes$errorType == "Wrong Schema") { - DTableServer("tbl_preview", data = inFile$data(), highlight = "full") - } else { - DTableServer("tbl_preview", - data = inFile$data(), - highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value - ) - } - - if (valRes$validationRes == "valid") { - # show submit button - output$submit <- renderUI(actionButton("btn_submit", "Submit to Synapse", class = "btn-primary-color")) - dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_inner_circles(), sleep = 2.5) - } else { - output$val_gsheet <- renderUI( - actionButton("btn_val_gsheet", " Generate Google Sheet Link", icon = icon("table"), class = "btn-primary-color") - ) - dcWaiter("update", msg = paste0(valRes$errorType, " Found !!! "), spin = spin_pulsar(), sleep = 2.5) - } - } else { - dcWaiter("hide") - } - - show("div_validate") - }) - - # if user click gsheet_btn, generating gsheet - observeEvent(input$btn_val_gsheet, { - # loading screen for Google link generation - dcWaiter("show", msg = "Generating link...") - - filled_manifest <- metadata_model$populateModelManifest(paste0( - config$community, - " ", input$dropdown_template - ), inFile$raw()$datapath, template_schema_name) - - # rerender and change button to link - output$val_gsheet <- renderUI({ - HTML(paste0("Edit on the Google Sheet.")) - }) - - dcWaiter("hide") - }) - - - ######## Submission Section ######## - observeEvent(input$btn_submit, { - # loading screen for submitting data - dcWaiter("show", msg = "Submitting...") - - # reads file csv again - submit_data <- csvInfileServer("inputFile")$data() - # IF an assay component selected (define assay components) note for future - # the type to filter (eg assay) on could probably also be a config choice - assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - # iffolder_ID has not been updated yet - if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - # and adds entityID, saves it as synapse_storage_manifest.csv, then associates - # with synapse files - if (input$dropdown_template %in% assay_schemas) { - # make into a csv or table for assay components already has entityId - if ("entityId" %in% colnames(submit_data)) { - write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, row.names = FALSE, na = "" - ) - } else { - file_list <- synapse_driver$getFilesInStorageDataset(synStore_obj, folder_synID) - datatype_list$files <<- list2Vector(file_list) - - # better filename checking is needed - files_df <- stack(datatype_list$files) # crash if no file existing - colnames(files_df) <- c("entityId", "Filename") - files_entity <- inner_join(submit_data, files_df, by = "Filename") - - write.csv(files_entity, - file = "./files/synapse_storage_manifest.csv", - quote = TRUE, row.names = FALSE, na = "" - ) - } - - # associates metadata with data and returns manifest id - logjs("haha6") - manifest_id <- synapse_driver$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID - ) - logjs("haha7") - manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) - # if no error - if (startsWith(manifest_id, "syn") == TRUE) { - rm("./files/synapse_storage_manifest.csv") - dcWaiter("hide") - nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) - - # clean up inputfile - sapply(clean_tags, FUN = hide) - DTableServer("tbl_preview", data.frame(NULL)) - # TODO: input file not reset yet - # reset(c(clean_tags, "inputFile", "tbl_preview")) if reset works - } else { - dcWaiter("update", msg = HTML(paste0( - "Uh oh, looks like something went wrong!", - manifest_id, - " is not a valid Synapse ID. Try again?" - )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") - } - } else { - # if not assay type tempalte - write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", quote = TRUE, - row.names = FALSE, na = "" - ) - - # associates metadata with data and returns manifest id - manifest_id <- synapse_driver$associateMetadataWithFiles( - synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID - ) - print(manifest_id) - manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) - - # if uploaded provided valid synID message - if (startsWith(manifest_id, "syn") == TRUE) { - nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) - rm("./files/synapse_storage_manifest.csv") - - # clear inputs - sapply(clean_tags, FUN = hide) - - # rerenders fileinput UI - output$fileInput_ui <- renderUI({ - fileInput("file1", "Upload CSV File", accept = c( - "text/csv", "text/comma-separated-values", - ".csv" - )) - }) - # renders empty df - output$tbl_preview <- renderDT(datatable(as.data.frame(matrix(0, - ncol = 0, - nrow = 0 - )))) - } else { - dcWaiter("update", msg = HTML(paste0( - "Uh oh, looks like something went wrong!", - manifest_id, " is not a valid Synapse ID. Try again?" - )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") - } - } - }) -}) diff --git a/functions/synapse_func_alias.py b/synLoginFun.py similarity index 100% rename from functions/synapse_func_alias.py rename to synLoginFun.py diff --git a/synStoreFuns.py b/synStoreFuns.py new file mode 100644 index 00000000..47b979f1 --- /dev/null +++ b/synStoreFuns.py @@ -0,0 +1,30 @@ +###!!!! use synStore_Session for server instead +import synapseclient +from SynapseStorage import SynapseStorage + +syn_get = syn.get + +storage_fileview = "syn20446927" + +syn = synapseclient.Synapse() +syn.login() + +syn_store = SynapseStorage(storage_fileview, syn) + +### "Testing retrieval of project list from Synapse +get_projects_list = syn_store.getStorageProjects() + +###print("Testing retrieval of folder list within a given storage project from Synapse") +#"syn19557917" +get_folder_list = syn_store.getStorageDatasetsInProject + +### print("Testing retrieval of file list within a given storage dataset from Synapse") +# "syn19557948" +get_file_list = syn_store.getFilesInStorageDataset + +### print("Testing association of antities with annotation from manifest") +# "./synapse_storage_manifest.csv", "syn20685746" +get_manifest_syn_id = syn_store.associateMetadataWithFiles + + + diff --git a/synStore_Session.py b/synStore_Session.py new file mode 100644 index 00000000..f563b587 --- /dev/null +++ b/synStore_Session.py @@ -0,0 +1,31 @@ +from schematic.store.synapse import SynapseStorage + +syn_store = SynapseStorage + +### "Testing retrieval of project list from Synapse +# get_projects_list = syn_store.getStorageProjects + +###print("Testing retrieval of folder list within a given storage project from Synapse") +# get_folder_list = syn_store.getStorageDatasetsInProject + +### print("Testing retrieval of file list within a given storage dataseyt from Synapse") +# get_file_list = syn_store.getFilesInStorageDataset + +### print("Testing association of antities with annotation from manifest") +# get_associated_manifestId = syn_store.associateMetadataWithFiles + +### getting all manifests associated with a project accessible by user +### returns a list, empty if manifest isn't there +# [('syn20687304', 'HCA immune cells census'), +# ('syn20703799', 'Ischaemic Sensitivity of Human Tissue'), +# []), +# ( ('syn20687304', 'HCA immune cells census'), +# ('syn21682582', 'Test'), +# ('syn21682585', 'synapse_storage_manifest.csv'))] +# get_all_manifests = syn_store.getAllManifests + +### updating fileset in a manifest associated with a dataset +#manifestId = syn_store.update_dataset_manifest_files(dataset_id) +# returns '' if no manifest exists +# depends on fileview so it may take a few min for new files to show +# get_update_manifestId = syn_store.updateDatasetManifestFiles \ No newline at end of file diff --git a/ui.R b/ui.R deleted file mode 100644 index 406053a1..00000000 --- a/ui.R +++ /dev/null @@ -1,241 +0,0 @@ -# This is the user-interface definition of a Shiny web application. -# You can find out more about building applications with Shiny here: -# -# http://shiny.rstudio.com -# -# This interface has been modified to be used specifically on Sage Bionetworks Synapse pages -# to log into Synapse as the currently logged in user from the web portal using the session token. -# -# https://www.synapse.org - -ui <- shinydashboardPlus::dashboardPage( - title = "Data Curator", - skin = "purple", - dashboardHeader( - titleWidth = 250, - title = tagList( - span(class = "logo-lg", "Data Curator"), - span(class = "logo-mini", "DCA") - ), - leftUi = tagList( - dropdownBlock( - id = "header_selection_dropdown", - title = "Selection", - icon = icon("sliders"), - badgeStatus = "info", - fluidRow( - lapply(datatypes, function(x) { - div( - id = paste0("header_content_", x), - selectInput( - inputId = paste0("header_dropdown_", x), - label = NULL, - choices = character(0) - ) - ) - }), - actionButton( - inputId = "btn_header_update", class = "btn-shiny-effect", - label = NULL, icon = icon("sync-alt") - ) - ) - ) - ), - tags$li( - class = "dropdown", id = "HTAN_logo", - tags$a( - href = "https://humantumoratlas.org/", - target = "_blank", - tags$img( - height = "40px", alt = "HTAN LOGO", - src = "img/HTAN_text_logo.png" - ) - ) - ) - ), - dashboardSidebar( - width = 250, - sidebarMenu( - id = "tabs", - # uiOutput("title"), - menuItem( - "Instructions", - tabName = "tab_instructions", - icon = icon("book-open") - ), - menuItem( - "Select your Dataset", - tabName = "tab_data", - icon = icon("mouse-pointer") - ), - menuItem( - "Get Metadata Template", - tabName = "tab_template", - icon = icon("table") - ), - menuItem( - "Submit & Validate Metadata", - tabName = "tab_upload", - icon = icon("upload") - ), - # add sidebar footer here - tags$a( - id = "sidebar_footer", `data-toggle` = "tab", - tags$div(icon("heart")), - tags$footer(HTML('Supported by the Human Tumor Atlas Network
- (U24-CA233243-01)
- Powered by and Sage Bionetworks')) - ) - ) - ), - dashboardBody( - tags$head( - tags$style(sass(sass_file("www/scss/main.scss"))), - singleton(includeScript("www/js/readCookie.js")) - ), - use_notiflix_report(), - use_waiter(), - tabItems( - # First tab content - tabItem( - tabName = "tab_instructions", - h2("Instructions for the Data Curator App (DCA):"), - h3( - "1. Go to", - strong("Select your Dataset"), - "tab - select your project; choose your folder and metadata template type matching your metadata." - ), - h3( - "2. Go to", - strong("Get Metadata Template"), - "tab - click on the link to generate the metadata template, then fill out and download the file as a CSV. If you already have an annotated metadata template, you may skip this step." - ), - h3( - "3. Go to", - strong("Submit and Validate Metadata"), - "tab - upload your filled CSV and validate your metadata. If you receive errors correct them, reupload your CSV, and revalidate until you receive no more errors. When your metadata is valid, you will be able to see a 'Submit' button. Press it to submit your metadata." - ), - switchTabUI("switchTab1", direction = "right") - ), - # second tab content - tabItem( - tabName = "tab_data", - h2("Set Dataset and Metadata Template for Curation"), - fluidRow( - box( - status = "primary", - width = 6, - title = "Choose a Project and Folder: ", - selectInput( - inputId = "dropdown_project", - label = "Project:", - choices = "Generating..." - ), - selectInput( - inputId = "dropdown_folder", - label = "Folder:", - choices = "Generating..." - ), - helpText( - "If your recently updated folder does not appear, please wait for Synapse to sync and refresh" - ) - ), - box( - status = "primary", - width = 6, - title = "Choose a Metadata Template Type: ", - selectInput( - inputId = "dropdown_template", - label = "Template:", - choices = "Generating..." - ) - ) - ), - switchTabUI("switchTab2", direction = "both") - ), - # Third tab item - tabItem( - tabName = "tab_template", - useShinyjs(), - h2("Download Template for Selected Folder"), - fluidRow( - box( - title = "Get Link, Annotate, and Download Template as CSV", - status = "primary", - width = 12, - actionButton("btn_download", "Click to Generate Google Sheets Template", - class = "btn-primary-color" - ), - hidden( - div( - id = "div_download", - height = "100%", - htmlOutput("text_download") - ) - ), - helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") - ) - ), - switchTabUI("switchTab3", direction = "both") - ), - # Fourth tab content - tabItem( - tabName = "tab_upload", - h2("Submit & Validate a Filled Metadata Template"), - fluidRow( - box( - title = "Upload Filled Metadata as a CSV", - status = "primary", - width = 12, - csvInfileUI("inputFile") - ), - box( - title = "Metadata Preview", - collapsible = TRUE, - status = "primary", - width = 12, - DTableUI("tbl_preview") - ), - box( - title = "Validate Filled Metadata", - status = "primary", - collapsible = TRUE, - width = 12, - actionButton("btn_validate", "Validate Metadata", class = "btn-primary-color"), - div( - id = "div_validate", - height = "100%", - ValidationMsgUI("text_validate") - ), - DTableUI("tbl_validate"), - uiOutput("val_gsheet"), - helpText( - HTML("If you have an error, please try editing locally or on google sheet. - Reupload your CSV and press the validate button as needed.") - ) - ), - box( - title = "Submit Validated Metadata to Synapse", - status = "primary", - width = 12, - uiOutput("submit") - ) - ) - ) - ), - # waiter loading screen - dcWaiter("show", isLogin = TRUE) - ) -) - -uiFunc <- function(req) { - if (!has_auth_code(parseQueryString(req$QUERY_STRING))) { - authorization_url <- oauth2.0_authorize_url(api, app, scope = scope) - return(tags$script(HTML(sprintf( - "location.replace(\"%s\");", - authorization_url - )))) - } else { - ui - } -} diff --git a/www/img/HTAN_text_logo.png b/www/HTAN_text_logo.png similarity index 100% rename from www/img/HTAN_text_logo.png rename to www/HTAN_text_logo.png diff --git a/www/config.json b/www/config.json index d3144027..3f264dab 100644 --- a/www/config.json +++ b/www/config.json @@ -1,35 +1,20 @@ { "manifest_schemas": [ {"display_name": "scRNA-seq Level 1", "schema_name": "ScRNA-seqLevel1", "type": "assay"}, - {"display_name": "scRNA-seq Level 2", "schema_name": "ScRNA-seqLevel2", "type": "assay"}, - {"display_name": "scRNA-seq Level 3", "schema_name": "ScRNA-seqLevel3", "type": "assay"}, - {"display_name": "scRNA-seq Level 4", "schema_name": "ScRNA-seqLevel4", "type": "assay"}, {"display_name": "scATAC-seq Level 1", "schema_name": "ScATAC-seqLevel1", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 1", "schema_name": "BulkRNA-seqLevel1", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 2", "schema_name": "BulkRNA-seqLevel2", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 3", "schema_name": "BulkRNA-seqLevel3", "type": "assay"}, - {"display_name": "Bulk WES Level 1", "schema_name": "BulkWESLevel1", "type": "assay"}, - {"display_name": "Bulk WES Level 2", "schema_name": "BulkWESLevel2", "type": "assay"}, - {"display_name": "Bulk WES Level 3", "schema_name": "BulkWESLevel3", "type": "assay"}, + {"display_name": "Bulk DNAseq Level 1", "schema_name": "BulkWESLevel1", "type": "assay"}, + {"display_name": "Bulk DNAseq Level 2", "schema_name": "BulkWESLevel2", "type": "assay"}, + {"display_name": "Bulk DNAseq Level 3", "schema_name": "BulkWESLevel3", "type": "assay"}, {"display_name": "Imaging Level 2", "schema_name": "ImagingLevel2", "type": "assay"}, {"display_name": "Clinical Tier 1: Demographics", "schema_name": "Demographics", "type": "clinical"}, {"display_name": "Clinical Tier 1: Diagnosis", "schema_name": "Diagnosis", "type": "clinical"}, {"display_name": "Clinical Tier 1: FamilyHistory", "schema_name": "FamilyHistory", "type": "clinical"}, {"display_name": "Clinical Tier 1: Exposure", "schema_name": "Exposure", "type": "clinical"}, {"display_name": "Clinical Tier 1: FollowUp", "schema_name": "FollowUp", "type": "clinical"}, - {"display_name": "Clinical Tier 1: Molecular Test", "schema_name": "MolecularTest", "type": "clinical"}, {"display_name": "Clinical Tier 1: Therapy", "schema_name": "Therapy", "type": "clinical"}, - {"display_name": "Clinical Tier 2", "schema_name": "ClinicalDataTier2", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Acute Lymphoblastic Leukemia", "schema_name": "AcuteLymphoblasticLeukemiaTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Breast Precancer and Cancer ", "schema_name": "BreastCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Colorectal Precancer and Cancer", "schema_name": "ColorectalCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Lung Precancer and Cancer", "schema_name": "LungCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Neuroblastoma and Glioma", "schema_name": "BrainCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Melanoma", "schema_name": "MelanomaTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Ovarian Precancer and Cancer ", "schema_name": "OvarianCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Pancreatic Precancer and Cancer", "schema_name": "PancreaticCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Prostate Precancer and Cancer", "schema_name": "ProstateCancerTier3", "type": "clinical"}, - {"display_name": "Clinical Tier 3: Sarcoma", "schema_name": "SarcomaTier3", "type": "clinical"}, {"display_name": "Biospecimen Tier 1 & 2", "schema_name": "Biospecimen", "type": "biospecimen"}, {"display_name": "Other Assay (Minimal Metadata)", "schema_name": "OtherAssay", "type": "assay"} ], diff --git a/www/img/synapse_logo_blk.png b/www/img/synapse_logo_blk.png deleted file mode 100644 index 84e1347f9b14ea1d2c01f43a5f3171186f62ac56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20190 zcmcFK1ydYN(*y|?+}+)RJBMp_Q zcg;+DcZ8CH6cPeH0t5sEl8m&t%IEy}`JTaj{T#JZZNfe$XiE`!5eSHeIK)?Dn9pxg zQ)v}>2ncU#2#8-H5D?FwpkE*e2)FML5GO_u5Pazn5IBz6oyr2AKfapCNr^*z{P*Pd zlqG#aU|nV8C14Mr5z(md^DA~DKS5s{oE6l*Oc#1&LO{s>lMxqD^ISd8@$kg__dEiy zw9xfdgzKTe7MAE~wYfAAv8Cn8ggNd(lulxf{6!i>iclE7+>`24qbU);2`?jkxgzA^ zAHcYI-Sw3#-pqZ_H&^O5At&P@JLfX@9y=j7mzkB7wIYpHlEBEsM8zi^lAE<+M` z=yy6Vbr|?hH?W?xAW3FnXrx1;B%&!I?O%tPH}8>3j5N-m!cnRyheyRy1A3wIh$2i@ z3qvKdbR2Ns`iS(h5=AP-2G8$}T6C`Hk^LEE584_rQ|k<^nb4`h%#sh*Rw@+d>p-R1XZJ;4r;y!U1mbgN=411%goikk_{hGW4STWSrOTVC zEwK1khm}V$_Oi?MKb15SU-62UUmv@f$Rf3R@g6GfHzm4w-nHOF+l!7GBfKhV30Y$2`~~#ur^hf;ik@hZn?|%3;xP0&u~{DW zeLTNH2};g=Tr@?j-+i6R{#LAnh7cYOeNVMHN-_9{V52zRVzyo=djwmp4udE#XlS;c zi3BruusuWd{j{lVlQ;a!L!R8=*<>=&N~jW+tG-DC&!~J?Hq{ma7tq1p_dSpf{9!cO zgaKNkOB-Mc5W}Ib91b$X(3U~zUiF{s7^kasJf;v*o$x~E;8 zurx60ajk)lKSY<-FX=yx9vok zycCxXmy141YwrTFdKS-4BEtU&go*<^a>VH$ld|5BB&T5(EfbX|uws_WFXMUfib>wr zExs9KztG1xZ3YuGDHhfEN8asu45a%82T?nhIrKQ{Vl zvJUY!s9OFOqwVpGd>~Fz{Jqk|3^JtPW6sS3jYvsXc z3`ai>OfHu&Er`Ww-PN*E*f>+)WIV1Gz#@_!@-gh*w}iD$uhQbj{?(m0z-c*KSIP{! zH0Sa7G@HAXIFEo-|F%+-CqF2x1FUi`{sA5Pbqi)Ji;*a68^lVee@ZO+vx;s_C#oo%Sk|H1Suq+XvGqEw zsMvgveX$`r5s94Su6p-#OjHcP;5>!>U37z9xu2A>I~OgzXp3^e5IF0c-^VYE08|=@SDkY{V{QtIybrN z(mN9|%SvEbrp$4z?eUdw77fj8oF_K&&uzwC*evyX)IXMJs^jG?nW)=sW@brJ8LQb? z65k_m{{u|556~aJXA{1Atw*fAup?<))df}C2mHuUXi`X9&#~WC_%%9!_qMkWmV|g% zLZ(A+r5&2el7zS|s~n{DcX##rDM8wQBJyw#<&ePc@WXN1PmCAP5l^7|Qh#VWsD4a6 zfF|PQ$_F57y77}?*z|h2RUrQv3`c{KNPwViK4#KbjLT~B!K=bIfH9U^ za|xxc-J1%mNfT4#bl_23fz>`Pr~E7Z@O;^^oXiwwaf9zg?byi>U~k3JPWuc&g$Ii& zY7`|y8Kvg$(qg_&xL4Z#k@uAJXMPiyB5sJh`Ijv|5!7zhd((Q*lmniE9gpFFNuq zOB7J@0>YEb(zNpium)}7c%i<$hbcagDP1w3c@nto-`R~-`);%!3{T+IfpL~B7Orj8 zCZlF3HPlt+p1Eqzargkj|IFv3Osx|>c(JHTKyYeNInFldFNqGj6~=?nT$jo4Hh~Xk z{23!_L?UMIzh)r2W+4OHWGu1Y2uD_1Zlbxanzb5@&~Q2c{V5HwYA_PA)yfU~ttWqL zdQR@s%eHi&td>Ld~G zW7$kwPIZI9x!#T1i{@%r4JqlnY=4s>ZWjndyv?JXm=e`eQ>)5BM;q6;GYL~f*-F@- zesn!nBZLJETrf%8JS!C|*jB~*syQQzz}o8y z0FHC;go^y{IQwpja`zywD6TdI!2JDnXj#camnUA;PyN#`B+TrqL;3Iwfm<%q5PYRC zp7ljZi8+AXyA$z0;>zWvPJKDzTPp=ky1Mh9)e-x3NR6~BJy=NfQj*Gt(w1dqtXU6|;GM3U=!;aHgW;Vw>-{a6 zQ!DPN-B;o7a;G<1K>naScC5{pZMPzM0Xkzc@Y)68Xvt)^-db}|c_C49TC#Cd`SRQv zSYCk;fW^HVld=Pl_!iax6*hCA7aCqoLN`4o*-$ye`Ln<7iS=w|mCbJRcsLI*?|^T~ zi|pj4iqjiy$CIN#sKJ0%!v|gwVgPD#7_H!8dibfPebL)!PoA~ldf@XLok-qTUgT>B-VQ&@`$w5SzJZ7>{6 z5p-GE);ShmVh9Nr8U)?p}uCC&JA>5dfNHJ&!SMEzB9rTg`gCIRadK; zPdV%M&MldB4+tslTk3g*oJ6VVKe{8OqJ^`yo?OOvp-{Xfv1;}r8bO_Bol8WHOzpCh|7@D zI#?(5b#koKV=|gn-RVeB4DWWIY3R%_Dz$^CrWzMW9nq*;uYV2E#C>qHdLm37nlU|H zBFB%D0;m~ORfdm*krRi0FSZzM^>gwdl-tuZc(?*GFf1JJdJ7l zfxNLNiY8<-ud6fz`bmE7Uf9%I@(5O-gsh+!=R6gcP>~W6Bplp_S0va7soyV=+3Vmr zM9mcg8nw|TcVJZl4RK%`-CxU$c=cwu_(D)LBeU6I*m+dizfl zOofxhIlXKIA3J@>>n)%2MFI^10hRzN-j!t+gONIV%%A9FYPK@+;XP*t&dG~J}6cE9A>}V+zEX< zIT^-xxQEM;dR;YltTj*1CqST`WY%wd3=H;JX{g>!|6k2vM>DJ|QJObc%}REu6{&$L>N(3bdnORtyW`cB1XzZ8&`goWGu8b&YL zi=ZOTOIq^9J9c2uZuk)1zi1XF?yHq|>G#akxHihPN9uE}yEx}gl$<_wLCbBBi=AIO|E*B1CNLlLaM`e2%~O)Yf|xaT(*o4= z+OYFLve>$~L~7tQlLUX5?L+Cee=kYAPmoAfS1Z&aq%?Gb%{y0lyb2$PG{57I({M`{ zvi+_}V{SaQ7Pz)YGhi{Cv=B)miw}Mhf+exfhV8p_xhQen(okV(k4*W!%4U876eCSj zAe4~n_-(eOOfNT{&>8n=VK*koFL>2uOisbH***~TKd!%jU_x8 zERE<|H~qRa-K`Jvs#?$2%cOZ~O`k&O!)Rd8!$ozRt=e4MQviR~`nVl^YPT!V;#-E% z59Ssn<7d!V^WB?xSG%mNGn?|Pw5=1f;X&EW!{Fk_SjYRznSC^Mc8WA1{?8wstIE3Q@UG{qqS3Nn?S!V0j*UdVj>O4M@|rl%jU7+EQR zT@n=Ni=V2p(U>Nb8ZTt&Qx6j_M5yQD&6?~u$K!UHgRk3oxp&!rv%?y*blXkQm(OT> z91{Av(S>5Z97Er0mvv>shXARsoN!FEtap!7s&H)i=@H@AO=pT`?Zzdfl)zOOE34BN zW?rx6{;Br%xss_1a9-B3J$G?@-hiWvul!ThvxqyF%9m5P#r=d-9T`L}EDMiKfIT_h zkmrAp^bq6{qsQqZFv$++EA;sS?+Tvf$Y#YdZfu0`${oVEZ6IQlI)~oz-*$`9{!*ii1@Sb_ z+3%((MlS2c@R<}ST+)Qiw7F0@Z*5(@P-&?N%uV%&FnE!NzuI~Td`}0uM(sHs8@SRb zp^>^3t7*+yrjXfH&g#yT7kGy{fV>a*pHf6L4d>TbQyzAO|2!8eN}NXHYIrMhWS8T{M!_S=Ym*-^-` zU^v+VyGOZvs|}}{_JZTCPd@tYcu?%9*jQuoqIMs5j!1$!FPiFrqzu;<_*{0P$&*sW zu6xWZG^J*+9(tKSWTO}yiwy?edjNPF`ei?s*7A&0wzAs!{TU8k0z{OntRvGSf;-gZK%>^`Vlb%%Hf}`9*F>Nr0_S=b8>MMe%h+{EJ&M2U z{;08(*xp7b`eu}iBTvChlw7J=&EKunVpk?o(fyb!{twalQ0uMA33Ff7Q$$?EphklD zrb5htOWFL})9(m{S?#%zbUN>x&dQ%EQp${Q65!RjD+qyQ8+7?;`(PI8jEOTsTO@*n z14aLP?oVW&`dw;iJgAsX|i~T>jnRLLjzo%6R+n6 z5xotz9OM(B$VRqs`X_#rHrf4M<%b(nYgG#%;WM6L={LNoVdWR;d!mwkBNz>dZL7K5 zX#{*$*ZZ;4QluPS7)4j)RA`(hDsvw4nr21bG^V@*WzY5?MJ^Z>tG5P2GfX!IM_?E^ zwCK~rhtJKwUo$=^xe_lft4%Cr(QH5kac{oGuhzGD?ddQWFS+1e7mYfjsh{brCOrCU zB-8;*8X=e8iEO<%>^zg#N@EVLl>5(D35Fl9Tsm}~!osiX`i_TBAJCKHMI~=)*B5VY z6b3!5vG$upW4OPM>a6bmtaFhx$1fz~!( z#^_uf{2=6}aF)m4+Si#)OepAVmty2{d7iZIM#or`a$TVVZjG~vagtxG7ptkLbjfk= zK_A2$mC~3M1d9d-w+_lkt^gHv)Btp|Cf6yY+*2WRe}8nUktPQoVn>Ve&Um-PcHXk|vu$49EI!1v`E!k*SEB|Nc5 zx(*|dv~sUzVzj+batJ9O#0MEsN;{(ZBTwkYF!xXBTWV8}7l53A111lpsx0I-$RT6- zf(RwiFk&#NR zeSNvcJ#%%+VjO|QWhDAz{?t`Ca{g695b1;~^9L-ABE|$wX?%uJ};y zL%l4?`(K19kKUbZ}^ziV91r2qHhD{=zI=a&Q~{jM>?n+hJP5`p67q*s`cT; zMtY)Igd$`MRE}M*ZqR7X9eM)CYmX<2`%&`1#CtSfVuZ3=E+xU&zm7*4O8xjWbI){EV} zN%geVbIzZT9_|DKF*O^mvV4&>yKtef9xf?&sDKI2U(<0z*Kri?LYuE9N?bX}V$a_W zf0Xl)|l(|0M^cJX28uLrgV|bo}*E0pt=qa3^sP_1)D`iDp5iW`n_CGExom%{V9b~Xeq=^_#!i7nZURF;eR}I{A#RrKEufrNSouT2VQuV@{mmIPpPKaLKUMY?@ICQ+Z#$R=S!{&# z7~#wviNO)IsM8qGcjnkbm1Qff7v*J5KXOtmpS&W(oeZ2m#G|LldTU#TZSke1L{(cAm}BLfA^*>`&fRO&okG_)3qkJ>@!wZRzoZ~u=i(hV)whlx%Iu@XPs!m z5t@E_(`;mV((t_(S7ZDPfvOyi*k){o%0R(ttkvo|oQ`vkQ_sy`5tpp>O15avgkseU z8)_Y&{8d-Pby1_ig6aAC@}aieY|O>|O?#B@jx4)@X@(Iw9-V3rRK%pf2cDkTP7b-!%_8lIYh*15-ARC3OP+Nn!~T|p1JO{F{HL#gM2dm`N}7z$%T0Rk znP2b6t`t}9(0R+Hi%Wak3$48ZzjW28XrVr@XY56Z%>-+0`h1q#$87^>5{sr=DsAoA zc^qa|53P%2X|c{x7AA`#5z+=9_%v<4PimS(4M(R`{4IJHH|yMGDm!7~OX)Y_zh19D zI*WoD8`1Gos?C?OyB@c-*n3wD#!BPf1#VlmC=_qNB^uQ)n#!&}Mh+dfTZdfwoUtA3 znr_A>-qnR(YG1z2Z`%?uu|%3V+_S({U=SpUn=_BDi(4pU=@r?fTzeX&h%B7r>;0Q8 z5w6&A$%Ju%vP|#`o1kbB!S8LybVfuNlbYEn1T`k5{g49 z2&M=dpBs0?vcT}#X84-BmOL&cGy%BTO$WXPoVv)92*pp$Y8QLADtXt3jKVRkv%h+m>;NvM5e`f3pTc^e<$Ch~mwE~sngoaw=<)q!rm3)nGxW!2h2IR6FwYw~F zIWM=~-puk?^->b$eMaoF*Vtznu}#o-AG?}h07S9I!@4xc2fnV4Mmp}1MM@Tpry%1( z)53^rs`$ICJazV;Bc}@LuBd;gSZZ(32+eAkzNJnO!}YOK;LO#^yCCl;H*r(sg@@xN z@@0>MG8oeNUK=pB_FDR`CdD3Z_iMQ-vP&*XKw8vxj2+F=iupI;#J=gXzqq%21CNuA z<~q;hbfn(Gx=7<>Cl!MiYnEM`;kVw!_Htqh)TDF>0dXm)`>f{rtmk+Cen5o@ECfqU zO-db_Z#!P>lrHOd(3VLxHy9vt2di0pDGJ96i5gqr6^{n z2km5TrnV2kcPxWMyMi^A$~5eIZGVnczo7ixnV`pB%2A&bdQ@lA&C}YO6t6$~fTVtl zZj6EUk4=+OSPmH?H>$qMsEeu3r(ICBrTypU_73dxY~9-zMk>6=@klFkx*~^pvD-{< zKvvUg zGDk~Da-(l`<_Lo&g71X8&r*TjY|9tC+8j_MN{#4*|Tp;H*1sD>cJK(O}(SbwI+CfW+AFf`v9R5-ev@ zxQo`M``!KTOp<}2i*$%{scqv}AD|GK+iO#gH-lSK!Q!^roQJ}M&fUh-Pe^FRIplE3 zU@%0E|7tz{x1x96r+du`o4$Bsz}$REGhkdadSIS*2N^b{_0?B9O<&uOG2j*`4EmF{ z03X&H1%Nj4e;8lZBpw-%C;0-*1!qd-5sMx1qpx`1+T7{|ZdkzPiADm6l89>!CU5aY z!jr@e7nt4nC8YA9L>Jzurx%n3J3b0nhgxhURe~|E|Mu+f<0zwH3>TYctpLqo8E}vR z$9|Gbi0wSc0p6(WIFm4~3tqYkFlb<7MCeRh*B|bc-?VNvWB~Jbv;EnA)&iTwzW)5a z5dTcb7SWi<|?XBFOtaHv5hOcPu`@=DC)BCk|O zyeH(5)s}!^ViCx*EUgw!#lE>l3|8>2%V7C!P<;bGOBMMzh$7fr2Ku*?3oA9ZEs*ng zm`J|#MK6@t#Iz`a)}gPLM9#~yq5*~xYNzmzAkhBda`;N$l_Fs77k4T&At~|M9U;+& zv(Rr@4rB|$!Jl!I6;9u#e;9}i?+kYL+7=eLFVc#>+C1pt9~0^a|L}Jr<~8B|86;`% z1v5}MQ`@iodTacJAT>lX2!%|9)$xzo2wfHe>*gOknEprZ+gAxXcr%<- zm3`QdoDhX0ww+LJPy6MurK6o+%v70bP_t%a&dC0i-*AP9#LlXS0SNIF$%ScTxX z3MeJ-vp@3(AEC*=0?k8C7jcLHDzj*^RxzY|VFDAI(;t6IYE)-K#SvuuD}F=yho)`4 z@uNIsx;~@8e^KLbl^{=<;e)M1Zqk?>nWGDK4j>kqj4NcIoQmy z-X`o(fMG6U9!xXx%DUHMlqhA>m-VoA9|0S%kpyz5U@2nH(YQlR%|m$HYhp5XgUcCLWk6EE}-^-Fe8p!2Rqx z;}%FxiMFcjgrcMQxhT;{zo zc`jT!hpP=2mQ4GOkMsdo^R0}e1Ryrw+y|;*cpR{Ve=!{0t8I|o8YBZ4M9&Q4pZhx zf(+ENFz)@d+OJKOv0nX&93EeL-*NJ4bi-!)FY58_WM`zwW{_^zt91iE&_*#OM>sMI zVI>`dq0AK0b`ePEx99tD{s{4_ATa*48e)T%lgIKAz&df)YJ?`nu{|zSB8?{%5eWx- zSG)tBsDv=p`wvpu1&#S6XtqVs6soB75yVb|m(KAC182;6CT9|)LkfSt@p`&fpcKFf z*aNb-ej81-=g(gK1!n|7p9JTT<=RFM^yYV#)V#ntW*^c$)H2D+OHzw zzb?VntvSgcd8!yA<)P^nl83-mnMSW_3B6*&QY zea6Uo<=)}QN}OAM-gYC9FC}InA|$8F3KFH4rc)XKS=9*@L6q+_jbelgOK1j{n+8^a z$g5xVP(gu38Q(Lp7i~U~)I(H&!o2Ml?N-gyN$(tWL;|UyLHS`$#7)m3A$tef10n1c zLOhW$fnjhoij?{&A#Is*;CNx_0fxru?N7Ayj#ZV=_ym%MN-BELkTZh<{~Y~900wmX z&-OjhTvW8twI~K<4mJ3AfrbcTP}@~<(drTqU%d%3Utuei;t|5IZ>v&!BJHgr8$0D6 z^UDK0H^H;qT57^5ON8)u$aGZF^XagaDjGC6CTlYh52{=-m#%T)0 zt#NrnJ~Igpou;IAS;ae21p_QAniZ^$@7~lu;Lm3yA|NV$L2^l10o5!aJ0VpP%E_`l zuTt*Dm8Jwmd;L+t1eq6AQ_$~YFE_X@ALdrtcv>~?uJVbx$EHC1@z;MOb0w!ngM2&U z;d{LMA;|7syg>vpg;1SC7DzqK@+=buQ~OAJPaPl^J#Q-iZh^v?Yg^_r^Skp#C{D)2-iZf7fx1rS6T%%WLd~lptec z!&Yp~Nfbji(BYV}!iYh8BJnE1nQAJlkFDb1S&}FrOJ%7^+;@d-j}88ybgoG< zwy*jvzsTcj+1T1_YpyK)x^1Z#gK3V0LIM9mnTBI1B*2e|iblMvK_!UM1R1X*Rb0#D z(Y(|I?B-ueoM2JMc=uDWOj_tUe$GVKWHESt{KNTnnpXK;Z#$sg`rK6uk%ES$=sW$F zvJv?N#CUh=o_jJpz}ugyD9NP`ebKK7T(rVw;>Bcs?6&tmodqF*#9H)PA)&aIWGsNC zHjTWOzxfgZ0?i~5M?T>89IZWQ@*M~a1HafUA!gIP=T4H@H-CUAY*vlE;YQab(I2Wd zZpx^wE3frOeN-Z>U>5$=F~yMF`VUf9clua%KRv}%S08~EbdbkA2^Iyes`-K;ib86BGoe__Le$@Nrc<>4D>hga+PJiNP4d z*6i?jy#5cs9!Xb<0hFPzoLxvgU2+=#Q|J0v`;t(Ruz>6f~N%rNz&H;AkmX}Q+0n8YDve$<%1ouu`;B*9L{fb>};`#~J(Wqw17{8=X^W^tjl`;kL2tTn_j{ zfcX-vU8Llr17=evH|9=k7&XR+hZ7F&zqcX}nh{)3VX?@340y zZ0_0wR!0RMhU!U+i5?z}4iu`4d7+~He!Z{bb+NtltXg?6OSb#-tH7;U%vJ#C_DBgo zRaJ(JIW4Um1eg8$jFI3)#m>XJ29*o)Blz@!_|N%97kF^fcIH)FlCS{?1)Pc> zyy5nB`2+fa!}erjbH9#A5H^sSjo|nLKl)Wov5oE4L%Ivu)aaBkQ<7;z|GvR$zwVCW z`zU-IGtezCEvtpDP019koi8nn`oYHP2#ZHyn_;Gqzd`B?>xomwFbe&708W>G(w3Xm z1u=VqE9D%QFN;bmzPe{ss^8Z~^HU-G&G1;NBy;-TjA)?9 z`~lqw`zI>)t&G2_!9Okj)>6zCQ}SKk`k|LH`X;!0JgsDWFd(ogNwj{??05jGunZxQ zbw?3@t79QT=^OI0S=QXA;3CV-eic>w9c*0%++LdQHQtCkQaHs!!YHC+b|qKhN!Rt( zdBA6Pp(3wAGdv&vLyc)tNVx4fyHLx1k#dP5C~- zv&fk4;L5#7Ys>@&r1RACb8m3{lFXSZ6ba_I9`}3oCQbT^^AVarw6))ts$Z?^^^-t7 zk}CdQLl)_j&H~NLq|X*Vdp?XJ)ZSOBF(Njabhvh#iQZ(Z4%p;s`sQ7Mt$=h!B*5uT zD8pnDKZ|8{KsanMw$n&_E@RD}{r4L~m7!1X>cb)js)mvRS;Rn*VhrUuBSS*XtL^kN zypK4vyI^W{4e@49*8s@A3hN}a?~Bli014M15z4o+gU}pD37P~=wO>lr9NmwQ&n=!Q zMf?x-PWpFT@*$XkYO1n#N&U$9O~3w@izkC{kq?uL5M`3SjxCQPJiT4&uH3qNI&5c0 zOQ=%2tO<%)d1^4)vHTz_IwR$ev!$tYy79SQK>A|H_tf(qG3+;%zG+ zWA`@Ha;>VAA!6K`Hnc1rYxhr!-LGMGL#=9o;FBL-Y%B+KK${*2b}T(1J$PRGY00J$ zu~ct~hN(JW%NX6wUfMPjb3Z=T)nMEKOJL`hl};qQ5@LZ)lDe&FuNs0Rz4$Rz{W{*F zp|?EW>x-!9bIy?JX^i&#ong}ca~I|O1CaiWc|>|3Es5;eLRMYbTo%B2@} zKxh0!c^=*EVd0a279;(x5yRmfANvr}oz`~1_u{1-%#T<08iGFs()E?#(*np{miBn< zsHMDH?*gJal-j)ZuIJl;K&NpbGr0m3ASN8NG8dwqNp-Xzi0@Fo&Ie~+$!s|BO2FmC zNJm3Yq+1YPUHwZ8(Gy_)UWlYAwcB~%wB*~uOCk+!|JJ)L)NGph%{0YUA!5X#X85A2 z_Uj|PK`z@Yh`C(#WCQbUdb!=5k6=l3D}kl3v{<=7F7j`-?TrpD@D-}je{HZ4CP2s= zB>II+X<={p=!2w9@Ovg=9Y{QaGgVN#L#u`h-Lw##hKZ)EH;{}op*9}y2PE=^rFj;y zY$sA6Y)M7ZNru=wRg}7hU~u-5O77^j4%ik?s#M{a^0D**Jec~T=Wd5+GJSo0wR2al zVxoQyrwKjckIks7+{N5nAiK=hnN9z2kBfNa)ZA6h{=)7&!vSEzFWVDHji3RCoTX7wel@C9vOJMf^=n(HO9t{}KezW7$44V0>_?h>3;$5zGpF<}E zg;J@R5t^?g3abQbk8?F}wn36nYPSB^`_0ljoR}F+#hT&_j2+qQ{~48UE(^`u_0VWm z%4?EG?;*IE$6#+I6Zl3tavh7dQ;%UDQN}1o9$VV9U(#@!vq};WtjGNGT2rTj=xGPE zH0p_y@$~!Z*Z`l)N_r86kD-+LdnYehKOO@Z;CZ%!W3^lX1?z%<);VO~f_na|m6hxH zp*ssFwR`+hg4tCcymTM4;>VE|B+KGY^qMJYqDRO?gg^Ka1}u^-pK+Pd;@ij`b-)8q z+zJbM4_ngwTgBWsp_*?=lWds0vQnU5KWKk5u;of|)n)JXW64uo`gd7WcjEX5@fD?% z(JM}0LcujJwh%5vsr|W|dPs6*<@Qa8!?hSQaQBe!(QOPVC-Z7}Ez8TM<;pnwF5!tG z)p4jZ<~q_OgnYIn2sQAe5FJ%i1TF^7hl5bg{5||6ry>tN9r6Pumxu?$@+XCFWl-s{ z6`z)RV5wXP^DJhdJREwVt++ZSo7;~KGj-miV{S+4V;q}(9~6~im#>6z@zPk;%Sr;X z`~C!zo&V;exi~3VVcu!JdHM5}%tc;=mwr~I1_{fGs1=7UHgHMa^^RL%Ow)F*vxgWA z*6t4y5rALbXhl)0N{v`#EKlOmB(rel%0FA*Fk-mK7ardo2xMaIBz066=S)PFU_{Zx zwV1Z=W}B_0T0fpkW-W5jZgIb-yVONm%3XL!PsWjBGA3v=3nFE(Gjli}{boCa^GBy< z@k$eXQs98^tTk>~4sWd}C&sCz_^sV*);&wTDChl<_v3m+NKd(gXXD_JgGm3mp@Iv) zm}7sbg_#Se4iM$DN%FoNbMF+_!VEz#MG|r z>xz?YLs6%-9jhqb3i1fAV65wYna*NAlc_8gypdP&wnZ zkAD2O`aq!mZzY{(7zV;ICTOEEhQP@je~Lqu-Im17Mzp6CVt>AP#Tz*m%ZUz~mAe~c zu5M-i42e@j6ak@ViyZO@s|$0Rdw@vb&@!dC)3+2Ua$MfGE&IXFcv5H;H0j}WE`-nK zJDUDW*PYLZo3h67a~)8ZhhjVR*(mR*fr=(+v7Hw$-4ErHtO|gcChZF3r$L=o?wKhJ(`Pf= zg37htIWoU(Pf`VsrD{Q_0wo{w8hcV)yHHx{%VD8ry!jh%=E zK$H}4o|}Fk1Vgf(Pg9iTG=#LuuYG?cao-Dhqxi zMWvNBVzNgkEbR*xk)2@z4d~X4Tf}_UGF=jgc>lg{$3o=OxF=$w;ws@yO6whGF?^r! zv8l|{=Fm&$v0+|pl6$-d(Uij#QkZ}>X*t^5O_m20)nEJ%E}Vt);Y@!9|EBm{S-A2S zdEAH8-Q)H-9++!=%L89l?;E^)rmCLKltS75dR8r2j|4_!W9-$U^`Qd_RW7bTCRdu2 zbFnRA?++5?d+9=PLd@Z$tDLB`&D!4fFOdvUBB8W}G4>|QMhF6MnELs05lVNey(79& zP}*W$0$hRA=Q>3a)Q#MGxC!ud%~sh8TeoSnf|h&?xVO{y9mjEgIK!U|$LfJ+$&En5zzSncPH$a!)- z7vid|%rF&o>ORa^v+1n(8bt>to#DhPfaGky*L{)A7v3%Ra&Vq79n`+)uQ^E`gDb6m zjbE?f_j0;dD$4R#IqbPY@X7ut7Jddlam3?Wa-T{cqJSrgEo~mH5h@X;5ZY!Zk^iGN zc;*Y1nd8`f)nIcV3gq|Q6c64+!$5NAHMU4c4y&p0)85@+Ztkm{uocONz7Oz3Jsn4f znyKYg8_230j{G0ooSAOeCg1BV377_sETO!e-dBB7GO%Tl3q%lo>$ntbHwidDAWO z&_ZDkp$`e^ORT!xZxXvLLK<6Uf+2gJ3+!#+*+%o2PMVjo`4^4Qm2=i@5=n>_t<#;b zJ1E85c|)4TJymfd)c%k_#$it)F?dsR_V*FKM|6gi3Q4mTD+6mf3d3fLND~cG;@6t? z4SU6NfqG9{y^o&PCVce$Hbgo;S^E&&< z#(?bLS-}7ABYz~hl3U7cIW?uZ!H>GE+}*dkrf;WE6<-h@CrrWltYsh(Qp^a$d8gB| zi!lw=iL7f5h`~~zWSA5U7i-{~wlED}9q-7;u)@~bcoq=Ynw_3HyF^Jn8YBpq}lYI%#7f`+^S?h_A09CAQH$i7-O z?Q8oTgwv!B+w*}3Z>I}N6?Uw^vETDI0!0;Fqztu*_gB+$dJcIz`9%#H^Ob~Z9YXxw zuSzAcwTQ(Q2m)IFvGc-bQiocx{OWn)SKD&_k>>Uf+0ydj5QH>Y-zxXpyaohiwTV}} zw~wPvMvUd&j$}7EvAXqIaS^z{(yT1oeiH-%+}O{| z1e)coj>$#(2t@kZq2;SviX>C?K> z)D3e&046m%eB}R{dD3_&ysop)*ke>f#@K2I4Ov2#FqUjH!&tJ7kr0I%OoWE9GxjA* z#@I5l^e2i$%80BX5*o=af7zlMJ=61kdOy71-!J#mIp^NrJ^Q)$oDqpEqvJJY(!hjG z@ok2{n`No0yV>e5qJ-o(4IGW5?rKI^_r}LLOe0b|0@dCv$A`-m#TZh4S;z5Mu5><; zCK_Fo-yY~2nE&k{@ZF!frlf8JjU&ISy+F0K=7}2@6iJeSH_;q8>{v=iGU2%fxcN^B z!1^Ri2e7NyL*YxxVAm*~yKgv%9kAYI0IM4&;T4cAA{}a$zxHJ(qVIg48KAO%k2b<4 zhZaiLWFz3iuuWqi!pL7{mBl;iZ`x`O`TW`Bx1TV@n69ItanO5Lxq60V#tl_{%B_L_ zwWQ;hjS=yE06`=YnM{LW(nAXc+YAL{pB#joFT4b~a6<(2*I$?;LCDuIw}yA?#>XkN zXccS?&&!`d;;+OwX~G4SeKEZt0vwQ(Bchl3p|)+9?+RA&$j2Of@xT~Z%2ijtPQ1}D zzoT)A%+k^f04XC8-rrm2C*r1v$v@1LVRYT$t)ZkDBg}xcm06>I4=>G$=FNexDR+99 zVeqtR(|q*(@lg{(Dnl#uF82ruG&qB3;P%|@7f)ZOkuhE?fge(t?IYy%_-pu0yZBWolMr^sdJi z@d~j*oy*uKoTh0(I?=gCGI8#E&dNOc)aqxmptXFTo6tj z5&I;WZl7<K?gYwTz+{lQ0;=2WGoYpnhD5s~ z3>lK2h9)Z03ruzA~f2>wg3R#bF~o4+@}K5`}r?Z34xjrB3z43C~P>-ydCi znDaHqX+#4rbuge1{$C+<2+sqY?^FG3WtajJMVd8)!gaEU~!WGBg zR?m5fpnjqDMk9;$+{d?8$!Q@YN5vmZT|`g!PEK7Fdw9c$1L1gC(P^XXkGK?u|OAFUb3> zmQ0pNbxIw?prqY3T~8%GEYDVbx>*rbY510wt+-~S?JjSEZB3}};vttBx%R5HNPdjL zJ*7N*y(}jSg0ooS5q%(*H*SBmInX$?tVl9p$1m#R;;!F|oG%+*k0Ug8`1)BWLIee8nat&|?v#aWxv znJBq%iJh4eR)(n@psMxJhNxjlS9|`W#5GHt^%=)_$D+SOr~Uv`Rrm9a@6It{G*6i$ z7$O@&BumvOItjSP8fXXcmOGFclxCQn=ZcIQCk4Q4nY;!*?vH*`?-D(Cs(X+XFLu_y}BATK)Z%)7RPh8wd z2!1CSn-q{if1V$T^|%E-6jMQ;Ul}MD@F-K;IkoP1$Hr$1dq z?+Ccp-g|b$Mc0ec^_xRy;Wk$Er3xF7w^FJ;Z?vvXM_#Mbb8+O5F2^ic@2|7@oKko) z`5rL0cQii`8GVLJp>sZWaV6^fcU9ojkCqEPZe|6t1WCA;mF+R^;kzkDtwPpM(2Nfj z?b{8PCTLtKH$2rHQ5k5qN?JG1ePjkeiCh>haHdnesCz1MV_>+O<}`{o&l)T^>iQ}k zoo6xemztW-7E>tqE zjp*+(4ae-gO6MW*m6i9~)m`bEp&}|5OPA|ChDko{CEFc~K-LAg361OJV|*gD!NzB- zdp|P(5KC}WDGvr^jvSkMIn+zn8bIlS;FApLZpN?r*p7DXYG)k?s|(0JG(UVrdtLb_ ze}OYof>$1C*`5r17WLcK&79_f-L2AnxOj*e3)YxJ$a^3BhJXU(bcS(DqB~Ou^c2&u z>b_trVuEnPdGPBuW)0QEEn!i=9xBbg?cPD*)5V&;2F$vME zT|CwW-5#Z>%Z7`AzVFi!Q;FqlDG?3WwI+>rl<)1IEGKn&DSZ|A0E|Rig3%)Z{@T~~`1TsXn?Au568?(g+ren^3u1t{CjM&_K z0pFL+utq#?01}l_Olj+5rVEv?9y(mZ0VDWYses&z5tn*Coqk-PKfH2FO&eI%Wn8Rv zf_#iJJi=8RGUvSU4%Q_LZLvNFk?7=)wowUG0y7OJfxs1B%rojvUse7}h<_MpHrYL{ z_0zNbD%1_#)UnMTw@n!pRq~^M=vGnq;?Y^0h};rL&&o-y*1!(ZkvU{7g2eFU-qLb! z=cx4N;~u)V5Uqcnlq~#(6!Jojw~c-6&o42;t?6_8uHX5&_VoxAqOFtG?^q*1zPDg+ z2incdlN7e#UQ=GJ8BWC(>p6r9&_Sg5b4XuPivE`;K2^;1J0jl*rYAf4BNWgSK%bQ5 zmTsGX_s>sbeKt%ouZKe6F0ScgVt?RZfy={%>@auLw!9O#RQW(t~eY?{X zjZW-)owi?D@4dW*BMM4`#)?@>tIAV*KhReMyLu(8f+u-c0hQkT>_j&B_Mec9r|JIZ z^-rdIP*>SY-S@<2{+%3QO+dOP*VnvMt&#gUa$Zb-4%_zN!^wf;FCIR@?+f2DP$xx5 zt#`kY(W;Zs!eYcq^%^YBD*pCMHPr0Z2QLlPn(6{Oyl8fKszT8J zt99TH+u^XXG;vYMi#6>{9*=OsU-QI!>v-K}W!K)v)Zl8W%5ZgMRaJXcEu9NmI%@E9 oaJUW}&K~ks;eR3A47}!d{qFyba0eEY%R)G2fv_>DH^RpJ2Z|Ik82|tP diff --git a/www/img/loading.gif b/www/loading.gif similarity index 100% rename from www/img/loading.gif rename to www/loading.gif diff --git a/www/js/readCookie.js b/www/readCookie.js similarity index 72% rename from www/js/readCookie.js rename to www/readCookie.js index d5a56c5e..8300f1c7 100644 --- a/www/js/readCookie.js +++ b/www/readCookie.js @@ -17,18 +17,18 @@ // } // read the user login token from a cookie (new protocol) -Shiny.addCustomMessageHandler("readCookie", function (message) { - readCookie(); +Shiny.addCustomMessageHandler("readCookie", function(message) { + readCookie(); }); function readCookie() { const xhr = new XMLHttpRequest(); - const url = 'https://www.synapse.org/Portal/sessioncookie'; + const url='https://www.synapse.org/Portal/sessioncookie'; xhr.withCredentials = true; - xhr.onreadystatechange = function () { - if (xhr.readyState == XMLHttpRequest.DONE) { - Shiny.onInputChange("cookie", xhr.responseText); - } + xhr.onreadystatechange = function() { + if (xhr.readyState == XMLHttpRequest.DONE) { + Shiny.onInputChange("cookie",xhr.responseText); + } } xhr.open("GET", url); xhr.send(); diff --git a/www/scss/basic/_animation.scss b/www/scss/basic/_animation.scss deleted file mode 100644 index 28a77cc4..00000000 --- a/www/scss/basic/_animation.scss +++ /dev/null @@ -1,70 +0,0 @@ -/*** Animation ***/ - -@keyframes fadeIn { - - 0% { - transform:scale(0); opacity: 0 - } - - 30% { - transform: scale(0.3) - } - - 70% { - transform: scale(0.7) - } - 100% { - transform: scale(1); opacity: 1 - } -} - -// update button animation -@keyframes TransitioningBackground { - - 0% { - background-position: 1% 0%; - } - - 50% { - background-position: 99% 100%; - } - - 100% { - background-position: 1% 0%; - } -} - -// switch tab animation -@keyframes move-left { - - 0% { - opacity: 0; - transform: translateX(10px); - } - - 50% { - opacity: 1; - } - - 100% { - opacity: 0; - transform: translateX(-10px); - } -} - -@keyframes move-right { - - 0% { - opacity: 0; - transform: translateX(-10px); - } - - 50% { - opacity: 1; - } - - 100% { - opacity: 0; - transform: translateX(10px); - } -} \ No newline at end of file diff --git a/www/scss/basic/_box.scss b/www/scss/basic/_box.scss deleted file mode 100644 index 23106cd9..00000000 --- a/www/scss/basic/_box.scss +++ /dev/null @@ -1,19 +0,0 @@ -.box-zoom { - transition: 300ms; - transition-property: transform; - - &:hover { - transform: scale(1.005); // change scale here - z-index: 100; - } -} - -.box-float { - transition: 300ms; - transition-property: box-shadow; - - &:hover { - box-shadow: $float-shadow; - z-index: 100; - } -} \ No newline at end of file diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss deleted file mode 100644 index 31b83af6..00000000 --- a/www/scss/basic/_button.scss +++ /dev/null @@ -1,146 +0,0 @@ -/*** Buttons ***/ - -// update button -// refer to https://paigen11.medium.com/ -.btn-shiny-effect { - position: relative; - background: #27022d; - color: #fff; - text-decoration: none; - letter-spacing: 1px; - border-radius: 5px; - box-shadow: $simple_shadow; - transition: 500ms; - overflow: hidden; - // for background color shift - background-image: linear-gradient(270deg, #8e9ac2, #42579a); - background-size: 400% 400%; - animation: TransitioningBackground 10s ease infinite; - - &:hover, &:focus { - color: #fff; - background-image: linear-gradient(to left, #2d8fe5, #d155b8); - transform: scale(1.05); - cursor: pointer; - } - - // shine animation left side - &::before { - content: ''; - display: block; - position: absolute; - background: rgba(255, 255, 255, 0.5); - width: 60px; - height: 100%; - top: 0; - filter: blur(30px); - transform: translateX(-100px) skewX(-15deg); - } - - // shine animation right side - &::after { - content: ''; - display: block; - position: absolute; - background: rgba(255, 255, 255, 0.2); - width: 30px; - height: 100%; - top: 0; - filter: blur(5px); - transform: translateX(-100px) skewX(-15deg); - } - - &::before, &::after { - transform: translateX(300px) skewX(-15deg); - transition: 0.7s; - } -} - -// dropdown hover effect -.option { - - &:hover, &:focus { - transform: scale(1.01); - font-size: 1.02em; - box-shadow: $primary_shadow; - border-radius: 20px; - transition: transform 50ms; - } -} - -// previous - next button -.switch-tab-prev, .switch-tab-next { - background: #fff; - color: #000; - display: flex; - justify-content: center; - align-items: center; - width: 70px; - height: 40px; - margin: 40px 15px; - padding: 5px; - border-radius: 10px; - box-shadow: $simple_shadow; - - &:hover, &:focus { - background: #fff; - outline: none !important; - } - - .fa { - margin: 1.5px; - font-size: 20px; - } -} - -.switch-tab-prev:hover { - .fa { - animation: move-left 2s infinite; - &:nth-child(2) { - animation-delay: -0.2s; - } - &:nth-child(1) { - animation-delay: -0.4s; - } - } -} - -.switch-tab-next:hover { - - .fa { - animation: move-right 2s infinite; - - &:nth-child(2) { - animation-delay: -0.2s; - } - - &:nth-child(3) { - animation-delay: -0.4s; - } - } -} - - -// simple float effect -// #btn_download, #btn_validate, #btn_val_gsheet, #btn_submit -.btn-primary-color { - background: $primary_col; - color: #fff; - border-color: transparent; - border-radius: 40px; - cursor: pointer; - - &:hover, &:focus { - background: $primary_col; - color: #fff; - box-shadow: $float_shadow2; - -webkit-transition: box-shadow .4s ease-out; - transition: box-shadow .4s ease-out; - } -} - -// upload progress button -.shiny-file-input-progress .progress-bar { - background: $primary_col; - border-radius: 40px; -} diff --git a/www/scss/basic/_message.scss b/www/scss/basic/_message.scss deleted file mode 100644 index 8740a429..00000000 --- a/www/scss/basic/_message.scss +++ /dev/null @@ -1,36 +0,0 @@ -/*** message ***/ - -// message -.message-menu { - padding-top: 5px -} - -// validation message -.error_msg { - color: $error_col; -} - -.success_msg { - color: $success_col; -} - -// notification -.shiny-notification { - position:fixed; - bottom: 0; - right: 0; - width: 100%; -} -#shiny-notification-error { - height: 500px; - padding :20px; - display: table-cell -} - -#shiny-notification-processing { - background-color: $notif_process_col -} - -#shiny-notification-success { - background-color: $notif_success_col -} \ No newline at end of file diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss deleted file mode 100644 index 76a46442..00000000 --- a/www/scss/basic/_variables.scss +++ /dev/null @@ -1,38 +0,0 @@ -/*** Global Variables ***/ - -// basic color -$primary_col: #605ca8; -$htan_col: rgb(95,0,140); -$light: #f8f9fa; -$light2: #f4f4f4; -$dark: #343a40; -$glass_grey: rgba(104, 103, 103, 0.3); - -// section color -$bg_primary_col: $light; -$sidebar_col: #191919; -$sidebar_pink: #A63FAA; -$footer_col: #878787; -$footer_bg_col: #202020; - -// message color -$error_col: #E53935; -$success_col: #28a745; -$notif_process_col: #F7DC6F; -$notif_success_col: #82E0AA; - -// box shadow -$primary_shadow: 0px 0.0625em 0.0625em rgba(0, 0, 0, 0.25), - 0px 0.125em 0.5em rgba(0, 0, 0, 0.25), - 0px 0px 0px 1px inset rgba(255, 255, 255, 0.1); -$simple_shadow:rgba(50, 50, 105, 0.15) 0px 2px 5px 0px, - rgba(0, 0, 0, 0.05) 0px 1px 1px 0px; -$float_shadow: 0 16px 32px 0 rgba(0, 0, 0, 0.2); -$float_shadow2: 0 5px 11px 0 rgba(0, 0,0, 0.18), - 0 4px 15px 0 rgba(0, 0, 0, 0.15); - -// mixin -@mixin header_bg { - background-image: linear-gradient(450deg, $sidebar_col, $htan_col, transparent); - background-color: $primary_col; -} \ No newline at end of file diff --git a/www/scss/main.scss b/www/scss/main.scss deleted file mode 100644 index 1a3faf4a..00000000 --- a/www/scss/main.scss +++ /dev/null @@ -1,14 +0,0 @@ -// global variables -@import 'basic/variables'; - -// dashboard sections -@import 'section/header'; -@import 'section/sidebar'; -@import 'section/content'; -@import 'section/footer'; - -// feature styles -@import 'basic/animation'; -@import 'basic/button'; -@import 'basic/box'; -@import 'basic/message'; diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss deleted file mode 100644 index 746c823f..00000000 --- a/www/scss/section/_content.scss +++ /dev/null @@ -1,60 +0,0 @@ -/*** Content ***/ - -.content-wrapper { - // overflow-y: visible !important; - background-color: $bg_primary_col; - // padding: 10px; -} - -.content { - padding-top: 50px; - - .tab-content h2 { - border-bottom: 1px solid $light2; // line below title - padding-bottom: 16px; - } -} - -// box effect -// TODO: Make it function or use existing function -.box-primary { - border-radius: 10px !important; - background-color: #FFF; - border-color: rgba($primary_col, 0.8) !important; - top: 15px; - - .box-title { - font-size: 1.6em; - } - - // help msg - .help-block { - margin: 8px 5px 2.5px 5px ; - } -} - -// if use solidHeader box -.box-solid { - - @extend .box-primary; - border: 0px !important; - - .box-header { - border-radius: 10px; - background: rgba($primary_col, 0.8) !important; - margin: 0 5px 5px 5px; - top: -7px; - - // collapse button - .box-tools .btn{ - background: rgba($primary_col, 0.8); - } - } -} - -#div_download, #div_validate, #div_val_gsheet { - font-size: 18px; - background-color: white; - margin: 10px 0; - padding: 10px 0; -} diff --git a/www/scss/section/_footer.scss b/www/scss/section/_footer.scss deleted file mode 100644 index f4211fa6..00000000 --- a/www/scss/section/_footer.scss +++ /dev/null @@ -1,49 +0,0 @@ -/*** Footer ***/ - -// footer in sidebar -#sidebar_footer { - position: absolute; - padding: 5px 15px 0px 15px; - left: 0; - bottom: 0; - width: 100%; - background-color: $footer_bg_col; - color: $footer_col; - font-size: 0.7em; - text-align: center; - z-index: 1000; - opacity: 0.8; - // white-space: nowrap; - overflow: hidden; - display: flex; - align-items: center; - - // heart color - div>.fa{ - visibility: hidden !important; - } - - footer { - padding: 10px 0; - margin-left: -20px; - line-height: 2; - } -} - -// sidebar footer when sidebar collapsed -.sidebar-collapse #sidebar_footer { - - div>.fa{ - color: transparent; - padding: 2px; - transform: scale(2.2); - background: linear-gradient(45deg, purple, #7590d6); - -webkit-background-clip: text; // clip to heart shape - visibility: visible !important; - transition: 100ms ease-in-out; - } - - footer { - visibility: hidden; - } -} diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss deleted file mode 100644 index e940b4d6..00000000 --- a/www/scss/section/_header.scss +++ /dev/null @@ -1,92 +0,0 @@ -/*** Header ***/ - -.logo, .navbar { - background-color: transparent !important; -} - -.main-header { - - @include header_bg; - - .logo { - font-size: 1.8em; - font-weight: 600; - } - - #HTAN_logo a { - height: 50px; - display: table-cell; - vertical-align: middle; - padding: 0 15px; - } - - // adjust custom dropdown color effect - .navbar { - - a:hover { - background-color: $glass_grey !important; - } - - // custom dropdown - leftUI - // when the box open - .open>a { - background-color: $glass_grey !important; - - &:focus, &:hover { - background-color: $glass_grey !important; - } - } - } - - .dropdown-menu { - left: auto !important; // stick with the button left - box-shadow: $primary_shadow; - animation: fadeIn 100ms; - - ul.menu { - - padding: 0 5px !important; - - // reset all margin - & * { - margin: 0px; - } - - &>div, .row { - display: flex; - align-items: center; - justify-content: flex-start; - width: 100% !important; - } - - .shiny-input-container{ - width: 250px; - margin: 5px; - height: 34px; // remove extra space bottom - } - } - - .selectize-dropdown { - // increase the width of expanded dropdown menu - width: 150% !important; - } - } -} - -// responsive - cycle back for proper breakpoints if needed -@media (max-width:1146px){ - - .shiny-input-container{ - width: 200px !important; - } -} - -@media (max-width:973px){ - - ul.menu { - - &>div, .row { - flex-wrap: wrap; - } - } -} \ No newline at end of file diff --git a/www/scss/section/_sidebar.scss b/www/scss/section/_sidebar.scss deleted file mode 100644 index 7fb05d24..00000000 --- a/www/scss/section/_sidebar.scss +++ /dev/null @@ -1,82 +0,0 @@ -/*** Sidebar ***/ - -.left-side, .main-sidebar { - padding-top: 80px; - font-weight: bold; - font-size: 1.1em -} - -// when sidebar is open -.main-sidebar { - background-color: $sidebar_col !important; - - .sidebar { - padding: 0px; - - //icon color - .fa { - color: $sidebar_pink; - transition: 100ms; - } - - // add background img - synapse logo - &:before { - content: ''; - background-image: url('https://www.synapse.org/images/logo.svg'); - background-repeat: no-repeat; - position: absolute; - height: 260px; - top: 80px; - left: 0; - right: 0; - bottom: 0; - opacity: 0.4; - background-size: contain; - transform: scale(0.8); - } - - li>a { - color: #FFF !important; - border-radius: 8px; - border-left: none !important; - margin: 10px 5px 10px 5px; - filter: grayscale(100%) opacity(0.7); - transition: 100ms; - - &:hover { - background: $glass_grey !important; - filter: grayscale(0%) opacity(1); - } - - i { - margin-left: -3px; //move icon to left a bit - } - } - - li.active>a { - background-color: rgba($primary_col, 0.8) !important; - filter: unset; - // box-shadow: 0 0px 20px 0px $htan_col; - - .fa{ - color: #FFF - } - } - } -} - -// when sidebar is collapsed -.sidebar-collapse .sidebar{ - - &:before { - visibility: hidden; - } - - span { - visibility: hidden; - } - - li>a { - margin-right: 5px !important; - } -} \ No newline at end of file diff --git a/www/styles.css b/www/styles.css new file mode 100644 index 00000000..b3c59c52 --- /dev/null +++ b/www/styles.css @@ -0,0 +1,60 @@ +/*** Top navigation bar ***/ +.main-header { + max-height: 50px +} + +.main-header .logo { + height: 70px; + font-size: 21px; + padding-top: 10px +} + +.sidebar-toggle { + height: 15px; + padding-top: 25px !important +} + +.navbar { + min-height: 50px !important +} + +.message-menu { + padding-top: 5px +} + +/*** Sidebar ***/ +.left-side, .main-sidebar { + padding-top: 80px; + font-weight: bold; + font-size: 1.1em +} + +/*** Notification bar ***/ +.shiny-notification { + position:fixed; + bottom: 0; + right: 0; + width: 100%; +} +#shiny-notification-error { + height: 500px; + padding :20px; + display: table-cell +} +#shiny-notification-processing {background-color: #F7DC6F} +#shiny-notification-success {background-color: #82E0AA} + +/*** Footer ***/ +footer { + position: absolute; + padding: 18px; + left: 0; + bottom: 0; + width: 100%; + background-color: #D0D6DC; + color: #465362; + font-size: 10px; + text-align: center; + z-index: 1000 +} + diff --git a/www/img/synapse_logo.png b/www/synapse_logo.png similarity index 100% rename from www/img/synapse_logo.png rename to www/synapse_logo.png From 2fca040b036800528a2c1fb1e23154e4e3b7d70f Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 20 Sep 2021 23:03:53 +0000 Subject: [PATCH 077/260] replace special symbols with underscore --- .gitignore | 2 +- files/synapse_storage_manifest.csv | 1 - global.R | 9 +++----- server.R | 35 +++++++++++++++--------------- 4 files changed, 22 insertions(+), 25 deletions(-) delete mode 100644 files/synapse_storage_manifest.csv diff --git a/.gitignore b/.gitignore index 11623cf0..2457b636 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ www/bootstrap.css www/bootstrap.min.css www/getdata.js www/message-handler.js -files/synapse_storage_manifest.csv +tmp/synapse_storage_manifest.csv .Rproj.user schematic/schema_explorer/__pycache__/* schematic/__pycache__/* diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv deleted file mode 100644 index 5bba5bde..00000000 --- a/files/synapse_storage_manifest.csv +++ /dev/null @@ -1 +0,0 @@ -Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId diff --git a/global.R b/global.R index 88bfb1eb..d4c8ae95 100644 --- a/global.R +++ b/global.R @@ -1,3 +1,6 @@ +# Activate conda env +reticulate::use_condaenv("data_curator_env_oauth") + suppressPackageStartupMessages({ library(shiny) library(httr) @@ -21,8 +24,6 @@ suppressPackageStartupMessages({ library(shinydashboardPlus) }) -# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" - has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if # based on these parameters, it looks like auth code is present that we can @@ -75,10 +76,6 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" -# Activate conda env -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") - # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) diff --git a/server.R b/server.R index 798034b2..5dafd437 100644 --- a/server.R +++ b/server.R @@ -333,21 +333,24 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_submit, { # loading screen for submitting data dcWaiter("show", msg = "Submitting...") + dir.create("./tmp", showWarnings = FALSE) # reads file csv again submit_data <- csvInfileServer("inputFile")$data() - # IF an assay component selected (define assay components) note for future + # replace special characters with '_' + colnames(submit_data) <- gsub("[[:punct:]]", "_", colnames(submit_data)) + + # If an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] - # iffolder_ID has not been updated yet + # if folder_ID has not been updated yet if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - # and adds entityID, saves it as synapse_storage_manifest.csv, then associates - # with synapse files + if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId if ("entityId" %in% colnames(submit_data)) { write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } else { @@ -355,27 +358,26 @@ shinyServer(function(input, output, session) { datatype_list$files <<- list2Vector(file_list) # better filename checking is needed - files_df <- stack(datatype_list$files) # crash if no file existing + # TODO: crash if no file existing + files_df <- stack(datatype_list$files) + # adds entityID, saves it as synapse_storage_manifest.csv, then associates with synapse files colnames(files_df) <- c("entityId", "Filename") files_entity <- inner_join(submit_data, files_df, by = "Filename") write.csv(files_entity, - file = "./files/synapse_storage_manifest.csv", + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) } # associates metadata with data and returns manifest id - logjs("haha6") manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID ) - logjs("haha7") manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error if (startsWith(manifest_id, "syn") == TRUE) { - rm("./files/synapse_storage_manifest.csv") dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) @@ -390,27 +392,25 @@ shinyServer(function(input, output, session) { manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") } } else { # if not assay type tempalte write.csv(submit_data, - file = "./files/synapse_storage_manifest.csv", quote = TRUE, + file = "./tmp/synapse_storage_manifest.csv", quote = TRUE, row.names = FALSE, na = "" ) # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./files/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID ) - print(manifest_id) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { + dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) - rm("./files/synapse_storage_manifest.csv") # clear inputs sapply(clean_tags, FUN = hide) @@ -432,8 +432,9 @@ shinyServer(function(input, output, session) { "Uh oh, looks like something went wrong!", manifest_id, " is not a valid Synapse ID. Try again?" )), sleep = 3) - rm("/tmp/synapse_storage_manifest.csv") } } + # delete tmp manifest + unlink("./tmp/synapse_storage_manifest.csv") }) }) From 491ac8ab84d97ae918b2f23be004b16cf1c2615d Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 27 Sep 2021 19:13:17 +0000 Subject: [PATCH 078/260] restore changing special characters from old PR --- server.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/server.R b/server.R index 5dafd437..3a40d13a 100644 --- a/server.R +++ b/server.R @@ -337,8 +337,6 @@ shinyServer(function(input, output, session) { # reads file csv again submit_data <- csvInfileServer("inputFile")$data() - # replace special characters with '_' - colnames(submit_data) <- gsub("[[:punct:]]", "_", colnames(submit_data)) # If an assay component selected (define assay components) note for future # the type to filter (eg assay) on could probably also be a config choice From 46851a7669ac5184713a681722cbd5a540b5ef84 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Sep 2021 01:52:54 +0000 Subject: [PATCH 079/260] update REAMDE --- README.md | 45 +++--- files/synapse_storage_manifest.csv | 216 ++++++++++++++++++++++++++++- 2 files changed, 239 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8cfd328d..28179228 100644 --- a/README.md +++ b/README.md @@ -4,56 +4,54 @@ The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the schematic Python package. It allows data contributors to easily annotate, validate and submit their metadata. - +--- ## Setup +Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic]: + ### Data Curator App Setup -Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/main): -1. Clone this repo with one single branch (i.e., *shiny-server-main*): +1. Clone this repo (front-end) with one single branch (i.e., *shiny-server-main*): git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -2. Create and edit the configuration file. Please make sure `OAuth Credential` ([how to obtain OAuth](###-Authentication)), `App_URL` and `CONDA_ENV_NAME` are correct in `config.yaml`: - +2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](###-Authentication)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: + + cp example_config.yaml config.yaml - chmod 400 config.yaml -3. Create a conda environment in the cloned directory from the `environment.yml` file which has all the required package dependencies: +3. Create and activate the conda environment (our conda environment name `data_curator_env` is set by default in the `example_config.yaml`.) grep 'CONDA_ENV_NAME:' config.yaml | cut -f2 -d':' | xargs conda env create -f environment.yml -n + conda activate data_curator_env -4. Activate the `data_curator_env` environment. Here, our conda environment name `data_curator_env` is set by default in the `example_config.yaml`. - - conda activate data_curator_env - -5. Install R packages: +5. Install required R pacakges dependencies: R -e "renv::consent(provided=TRUE)" R -e "renv::restore(lockfile='renv.lock')" ### Schematic Setup -1. Clone the [schematic](https://github.com/Sage-Bionetworks/schematic/tree/develop) (backend) as a folder `schematic` inside the `data_curator` folder: +1. Clone the [schematic] (backend) as a folder `schematic` inside the `data_curator` folder: git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git -2. Install the latest release of the `schematic`: +2. Install the latest release of the `schematic` via `pip`: python -m pip install schematicpy - - For [development](https://github.com/Sage-Bionetworks/schematic/blob/develop/CONTRIBUTION.md#development-environment-setup), install the package via `poetry`: + For development and test with the latest update from `schematic`, install the `schematic` via `poetry`: - cd schematic - poetry build - pip install dist/schematicpy-*-py3-none-any.whl + cd schematic + poetry build + pip install dist/schematicpy-*-py3-none-any.whl -2. Set up the schematic configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) +3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) -### App Configuration File +### Data Model Configuration Use the app configuration file `www/config.json` to adapt this app to your DCC. @@ -65,7 +63,12 @@ Use the app configuration file `www/config.json` to adapt this app to your DCC. * `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) * `community` : the abbreviated name of the community or project. (e.g. _HTAN_) +--- ### Authentication -This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration yaml file. \ No newline at end of file +This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration yaml file. + + + +[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop \ No newline at end of file diff --git a/files/synapse_storage_manifest.csv b/files/synapse_storage_manifest.csv index 5bba5bde..e2337186 100644 --- a/files/synapse_storage_manifest.csv +++ b/files/synapse_storage_manifest.csv @@ -1 +1,215 @@ -Component,Filename,File Format,HTAN Parent Biospecimen ID,HTAN Data File ID,Nucleic Acid Source,Cryopreserved Cells in Sample,Single Cell Isolation Method,Dissociation Method,Library Construction Method,Read1,Read2,End Bias,Reverse Transcription Primer,Spike In,Sequencing Platform,Total Number of Input Cells,Input Cells and Nuclei,Library Preparation Date,Single Cell Dissociation Date,Sequencing Library Construction Date,Nucleic Acid Capture Date,Protocol Link,Technical Replicate Group,Both Spike in Mixes,Cell Barcode Length,Cell Barcode Offset,Empty Well Barcode,Feature Reference Id,Median UMIs per Cell Number,Spike In Concentration,Spike In Mix 1,Spike In Mix 2,UMI Barcode Length,UMI Barcode Offset,Valid Barcodes Cell Number,Well Index,cDNA Length,cDNA Offset,entityId +"Biospecimen description","Component","HTAN Biospecimen ID","HTAN Parent ID","Timepoint Label","Collection Days from Index","Adjacent Biospecimen IDs","Biospecimen Type","Acquisition Method Type","Fixative Type","Site of Resection or Biopsy","Storage Method","Processing Days from Index","Protocol Link","Site Data Source","Collection Media","Mounting Medium","Processing Location","Histology Assessment By","Histology Assessment Medium","Preinvasive Morphology","Tumor Infiltrating Lymphocytes","Degree of Dysplasia","Dysplasia Fraction","Number Proliferating Cells","Percent Eosinophil Infiltration","Percent Granulocyte Infiltration","Percent Inflam Infiltration","Percent Lymphocyte Infiltration","Percent Monocyte Infiltration","Percent Necrosis","Percent Neutrophil Infiltration","Percent Normal Cells","Percent Stromal Cells","Percent Viable cells","Percent Fibrosis","Percent Tumor Cells","Percent Tumor Nuclei","Fiducial Marker","Slicing Method","Lysis Buffer","Method of Nucleic Acid Isolation","Acquisition Method Other Specify","Analyte Type","Fixation Duration","Histologic Morphology Code","Ischemic Temperature","Ischemic Time","Portion Weight","Preservation Method","Section Thickness Value","Sectioning Days from Index","Shipping Condition Type","Slide Charge Type","Specimen Laterality","Total Volume","Tumor Tissue Type","Sectioning Substrate type","Serial section number","Interval of time between removal from the body and tissue is placed in media (minutes)","Interval of time between removal from the body and tissue is frozen (minutes)","Interval of time between removal from the body and tissue is fixed (minutes)" +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_203_332","HTA1_203","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","22747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_203_3321","HTA1_203_332","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","22747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,54,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_203_332101","HTA1_203_332102","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","22747","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_203_332102","HTA1_203_3321","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","22747","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_203_3323","HTA1_203_332","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","22747","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,155, +"tumor WES (from OCT piece)","Biospecimen","HTA1_203_332301","HTA1_203_3323","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","22877","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_203_332302","HTA1_203_3323","Not recorded","22747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","23075","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_203_0001","HTA1_203","Not recorded","22745",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","22745","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_203_00015","HTA1_203_0001","Not recorded","22745",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","22745","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_203_0001501","HTA1_203_00015","Not recorded","22745",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","22877","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_339_1112","HTA1_339","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","30180","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_339_11121","HTA1_339_1112","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","30180","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,20,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_339_1112101","HTA1_339_1112103","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30180","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_339_1112102","HTA1_339_1112103","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30180","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-enrichment-of-epcam-cells-from-single-cell-s-bucfnstn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 3 (from fresh piece)","Biospecimen","HTA1_339_1112103","HTA1_339_11121","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30180","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_339_11123","HTA1_339_1112","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","30180","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,168, +"tumor WES (from OCT piece)","Biospecimen","HTA1_339_1112301","HTA1_339_11123","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30275","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_339_1112302","HTA1_339_11123","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30473","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_339_11126","HTA1_339_1112","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30180","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,170, +"OCT section for Visium QC H&E","Biospecimen","HTA1_339_1112603","HTA1_339_11126","Not recorded","30180",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30793","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,20,50,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30793,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - A","Biospecimen","HTA1_339_1112604","HTA1_339_11126","Not recorded","30180","HTA1_339_1112305","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30808","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30807,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - B","Biospecimen","HTA1_339_1112605","HTA1_339_11126","Not recorded","30180","HTA1_339_1112304, HTA1_339_1112306","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30808","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30807,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"OCT section for Visium/H&E - C","Biospecimen","HTA1_339_1112606","HTA1_339_11126","Not recorded","30180","HTA1_339_1112305, HTA1_339_1112307","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30808","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30807,,,"Right",,"Primary","Visium spatial gene expression slide",3,,, +"OCT section for Visium/H&E - D","Biospecimen","HTA1_339_1112607","HTA1_339_11126","Not recorded","30180","HTA1_339_1112306","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30808","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30807,,,"Right",,"Primary","Visium spatial gene expression slide",4,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_339_0001","HTA1_339","Not recorded","30173",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","30173","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_339_00015","HTA1_339_0001","Not recorded","30173",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","30173","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_339_0001501","HTA1_339_00015","Not recorded","30173",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","30275","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_661_3572","HTA1_661","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","24529","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_661_35721","HTA1_661_3572","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","24529","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,38,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_661_3572101","HTA1_661_3572102","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24529","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_661_3572102","HTA1_661_35721","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24529","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_661_35723","HTA1_661_3572","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","24529","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,166, +"tumor WES (from OCT piece)","Biospecimen","HTA1_661_3572301","HTA1_661_35723","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24735","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_661_3572302","HTA1_661_35723","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24775","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_661_35726","HTA1_661_3572","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","24529","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,166, +"OCT section for Visium QC H&E","Biospecimen","HTA1_661_3572603","HTA1_661_35726","Not recorded","24529",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25095","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,10,60,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,25095,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - C","Biospecimen","HTA1_661_3572604","HTA1_661_35726","Not recorded","24529","HTA1_661_3572305","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25110","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,25109,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - D","Biospecimen","HTA1_661_3572605","HTA1_661_35726","Not recorded","24529","HTA1_661_3572304","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25110","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,25109,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_661_0001","HTA1_661","Not recorded","24585",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","24585","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_661_00015","HTA1_661_0001","Not recorded","24585",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","24585","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_661_0001501","HTA1_661_00015","Not recorded","24585",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","24735","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_663_3631","HTA1_663","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","21608","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Left",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_663_36311","HTA1_663_3631","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","21608","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Left",,"Primary",,,46,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_663_3631101","HTA1_663_36311","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","21608","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Left",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_663_36313","HTA1_663_3631","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","21608","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Left",,"Primary",,,,134, +"tumor WES (from OCT piece)","Biospecimen","HTA1_663_3631301","HTA1_663_36313","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21832","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Left",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_663_3631302","HTA1_663_36313","Not recorded","21608",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","22030","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Left",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_663_0001","HTA1_663","Not recorded","21584",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","21584","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_663_00015","HTA1_663_0001","Not recorded","21584",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","21584","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_663_0001501","HTA1_663_00015","Not recorded","21584",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","21832","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_734_3812","HTA1_734","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","26450","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_734_38121","HTA1_734_3812","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","26450","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,57,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_734_3812101","HTA1_734_3812102","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","26450","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_734_3812102","HTA1_734_38121","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","26450","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_734_38123","HTA1_734_3812","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","26450","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,236, +"tumor WES (from OCT piece)","Biospecimen","HTA1_734_3812301","HTA1_734_38123","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","26629","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_734_3812302","HTA1_734_38123","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","26669","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_734_38126","HTA1_734_3812","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","26450","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,236, +"OCT section for Visium QC H&E","Biospecimen","HTA1_734_3812603","HTA1_734_38126","Not recorded","26450",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","26989","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,5,60,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,26989,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - A","Biospecimen","HTA1_734_3812604","HTA1_734_38126","Not recorded","26450","HTA1_734_3812305","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","27004","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,27003,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - B","Biospecimen","HTA1_734_3812605","HTA1_734_38126","Not recorded","26450","HTA1_734_3812304","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","27004","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,27003,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_734_0001","HTA1_734","Not recorded","26445",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","26445","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_734_00015","HTA1_734_0001","Not recorded","26445",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","26445","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_734_0001501","HTA1_734_00015","Not recorded","26445",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","26629","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_791_4172","HTA1_791","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","29929","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_791_41721","HTA1_791_4172","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","29929","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,48,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_791_4172101","HTA1_791_4172102","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","29929","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_791_4172102","HTA1_791_41721","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","29929","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_791_41722","HTA1_791_4172","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","29929","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,199, +"tumor WES (from OCT piece)","Biospecimen","HTA1_791_4172201","HTA1_791_41722","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30099","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_791_4172202","HTA1_791_41722","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30139","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_791_41726","HTA1_791_4172","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","29929","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,201, +"OCT section for Visium QC H&E","Biospecimen","HTA1_791_4172603","HTA1_791_41726","Not recorded","29929",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30459","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,40,20,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30459,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - A","Biospecimen","HTA1_791_4172604","HTA1_791_41726","Not recorded","29929","HTA1_791_4172305","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30474","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30473,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - B","Biospecimen","HTA1_791_4172605","HTA1_791_41726","Not recorded","29929","HTA1_791_4172304","Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","30474","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,30473,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_791_0001","HTA1_791","Not recorded","29921",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","29921","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_791_00015","HTA1_791_0001","Not recorded","29921",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","29921","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_791_0001501","HTA1_791_00015","Not recorded","29921",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","30099","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_822_6908","HTA1_822","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","Fresh","28998","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_822_69081","HTA1_822_6908","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","Fresh","28998","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,70,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_822_6908101","HTA1_822_6908102","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","28998","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_822_6908102","HTA1_822_69081","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","28998","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_822_69083","HTA1_822_6908","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","Frozen at -80C","28998","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,142, +"tumor WES (from OCT piece)","Biospecimen","HTA1_822_6908301","HTA1_822_69083","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","29435","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_822_69086","HTA1_822_6908","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","Frozen at -80C","28998","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,142, +"OCT section for Visium QC H&E","Biospecimen","HTA1_822_6908603","HTA1_822_69086","Not recorded","28998",,"Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","29505","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,10,,,,90,30,30,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,29505,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - C","Biospecimen","HTA1_822_6908604","HTA1_822_69086","Not recorded","28998","HTA1_822_6908305","Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","29520","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,29519,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - D","Biospecimen","HTA1_822_6908605","HTA1_822_69086","Not recorded","28998","HTA1_822_6908304","Tissue Biospecimen Type","Surgical Resection","None","Middle lobe lung","unknown","29520","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,29519,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_822_0001","HTA1_822","Not recorded","28998",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","28998","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_822_00015","HTA1_822_0001","Not recorded","28998",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","28998","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_822_0001501","HTA1_822_00015","Not recorded","28998",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","29435","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_921_4561","HTA1_921","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","25023","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_921_45611","HTA1_921_4561","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","25023","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,48,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_921_4561101","HTA1_921_45611","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25023","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_921_45613","HTA1_921_4561","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","25023","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,154, +"tumor WES (from OCT piece)","Biospecimen","HTA1_921_4561301","HTA1_921_45613","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25190","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_921_4561302","HTA1_921_45613","Not recorded","25023",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","25388","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_921_0001","HTA1_921","Not recorded","25023",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","25023","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_921_00015","HTA1_921_0001","Not recorded","25023",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","25023","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_921_0001501","HTA1_921_00015","Not recorded","25023",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","25190","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_937_7969","HTA1_937","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","20486","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_937_79691","HTA1_937_7969","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","20486","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,32,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_937_7969101","HTA1_937_7969102","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20486","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_937_7969102","HTA1_937_79691","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20486","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_937_79693","HTA1_937_7969","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","20486","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,118, +"tumor WES (from OCT piece)","Biospecimen","HTA1_937_7969301","HTA1_937_79693","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20595","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_937_79696","HTA1_937_7969","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","20486","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,120, +"OCT section for Visium QC H&E","Biospecimen","HTA1_937_7969603","HTA1_937_79696","Not recorded","20486",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20955","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,5,90,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,20955,,,"Right",,"Primary","Superfrost microscope glass slide",,,, +"OCT section for Visium/H&E - A","Biospecimen","HTA1_937_7969604","HTA1_937_79696","Not recorded","20486","HTA1_937_7969305","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20970","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,20969,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - B","Biospecimen","HTA1_937_7969605","HTA1_937_79696","Not recorded","20486","HTA1_937_7969304","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","20970","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,"8140/3",,,,"OCT",10,20969,,,"Right",,"Primary","Visium spatial gene expression slide",2,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_937_0001","HTA1_937","Not recorded","20524",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","20524","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_937_00015","HTA1_937_0001","Not recorded","20524",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","20524","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_937_0001501","HTA1_937_00015","Not recorded","20524",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","20595","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_962_4711","HTA1_962","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","28954","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_962_47111","HTA1_962_4711","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","28954","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh",,,,,"Right",,"Primary",,,42,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_962_4711101","HTA1_962_4711102","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","28954","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_962_4711102","HTA1_962_47111","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","28954","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_962_47112","HTA1_962_4711","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","28954","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,155, +"tumor WES (from OCT piece)","Biospecimen","HTA1_962_4711201","HTA1_962_47112","Not recorded","28954",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","29357","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8140/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_962_0001","HTA1_962","Not recorded","29267",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","29267","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,,,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_962_00015","HTA1_962_0001","Not recorded","29267",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Frozen at -80C","29267","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_962_0001501","HTA1_962_00015","Not recorded","29267",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","unknown","29357","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Negative 80 Deg C",,,"Dry Ice",,,,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_261_4801","HTA1_261","Not recorded","31231 ",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","31231 ","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8480/3",,,,"Fresh",,,,,"unknown",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_261_48011","HTA1_261_4801","Not recorded","31231 ",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","31231 ","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8480/3",,,,"Fresh",,,,,"unknown","Primary","Primary",,,20,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_261_4801101","HTA1_261_48011","Not recorded","31231 ",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","31231 ","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8480/3",,,,"Fresh dissociated",,,,,"unknown","Primary","Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_261_48013","HTA1_261_4801","Not recorded","31231 ",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","31231 ","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8480/3",,,,"OCT",,,,,"unknown","Primary","Primary",,,,130, +"tumor WES (from OCT piece)","Biospecimen","HTA1_261_4801301","HTA1_261_48013","Not recorded","31231 ",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","32002","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8480/3",,,,"OCT",,,,,"unknown","Primary","Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_261_0001","HTA1_261","Not recorded","31231 ",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","31231 ","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_261_00015","HTA1_261_0001","Not recorded","31231 ",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","31231 ","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_261_0001501","HTA1_261_00015","Not recorded","31231 ",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","32006","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_274_4891","HTA1_274","Not recorded","22879",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","22879","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"unknown",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_274_48911","HTA1_274_4891","Not recorded","22879",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","22879","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"unknown",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_274_4891101","HTA1_274_48911","Not recorded","22879",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","22879","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh dissociated",,,,,"unknown",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_274_48913","HTA1_274_4891","Not recorded","22879",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","22879","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"unknown",,"Primary",,,,120, +"tumor WES (from OCT piece)","Biospecimen","HTA1_274_4891301","HTA1_274_48913","Not recorded","22879",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","23157","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"unknown",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_274_0001","HTA1_274","Not recorded","22879",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","22879","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_274_00015","HTA1_274_0001","Not recorded","22879",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","22879","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_274_0001501","HTA1_274_00015","Not recorded","22879",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","23223","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_293_5041","HTA1_293","Not recorded","26551",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","26551","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_293_50411","HTA1_293_5041","Not recorded","26551",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","26551","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"Right",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_293_5041101","HTA1_293_50411","Not recorded","26551",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","26551","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_293_50413","HTA1_293_5041","Not recorded","26551",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","26551","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"Right",,"Primary",,,,113, +"tumor WES (from OCT piece)","Biospecimen","HTA1_293_5041301","HTA1_293_50413","Not recorded","26551",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","26809","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_293_0001","HTA1_293","Not recorded","26551",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","26551","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_293_00015","HTA1_293_0001","Not recorded","26551",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","26551","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_293_0001501","HTA1_293_00015","Not recorded","26551",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","26834","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_322_5071","HTA1_322","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","21079","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh",,,,,"Left",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_322_50711","HTA1_322_5071","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","21079","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh",,,,,"Left",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_322_5071101","HTA1_322_50711","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21079","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh dissociated",,,,,"Left",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_322_50713","HTA1_322_5071","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","21079","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"Left",,"Primary",,,,90, +"tumor WES (from OCT piece)","Biospecimen","HTA1_322_5071301","HTA1_322_50713","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21330","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"Left",,"Primary",,,,, +"tumor bulk RNA-Seq (from OCT piece)","Biospecimen","HTA1_322_5071302","HTA1_322_50713","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21528","Pending",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"Left",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_322_50716","HTA1_322_5071","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -150C","21079","Pending",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"Left",,"Primary",,,,37, +"OCT section for Visium QC H&E","Biospecimen","HTA1_322_5071603","HTA1_322_50716","Not recorded","21079",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21862","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,10,,,,90,5,20,,,"Cryosectioning",,,,,,"8260/3",,,,"OCT",10,21862,,,"Left",,"Primary","Superfrost microscope slide",,,, +"OCT section for Visium/H&E - C","Biospecimen","HTA1_322_5071604","HTA1_322_50716","Not recorded","21079","HTA1_322_5071305","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21873","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8260/3",,,,"OCT",10,21873,,,"Left",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - D","Biospecimen","HTA1_322_5071605","HTA1_322_50716","Not recorded","21079","HTA1_322_5071304","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","21873","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8260/3",,,,"OCT",10,21873,,,"Left",,"Primary","Visium spatial gene expression slide",5,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_322_0001","HTA1_322","Not recorded","21079",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","21079","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_322_00015","HTA1_322_0001","Not recorded","21079",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","21079","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_322_0001501","HTA1_322_00015","Not recorded","21079",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","21355","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_324_5101","HTA1_324","Not recorded","24747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","24747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_324_51011","HTA1_324_5101","Not recorded","24747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","24747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"Right",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_324_5101101","HTA1_324_51011","Not recorded","24747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24747","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_324_51013","HTA1_324_5101","Not recorded","24747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","24747","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"Right",,"Primary",,,,140, +"tumor WES (from OCT piece)","Biospecimen","HTA1_324_5101301","HTA1_324_51013","Not recorded","24747",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","24983","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"Right",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_324_0001","HTA1_324","Not recorded","24747",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","24747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_324_00015","HTA1_324_0001","Not recorded","24747",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","24747","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_324_0001501","HTA1_324_00015","Not recorded","24747",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","25049","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_331_5161","HTA1_331","Not recorded","27316",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","27316","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh",,,,,"unknown",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_331_51611","HTA1_331_5161","Not recorded","27316",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","27316","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh",,,,,"unknown",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_331_5161101","HTA1_331_51611","Not recorded","27316",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","27316","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"Fresh dissociated",,,,,"unknown",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_331_51613","HTA1_331_5161","Not recorded","27316",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","27316","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"unknown",,"Primary",,,,103, +"tumor WES (from OCT piece)","Biospecimen","HTA1_331_5161301","HTA1_331_51613","Not recorded","27316",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","27540","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8260/3",,,,"OCT",,,,,"unknown",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_331_0001","HTA1_331","Not recorded","27316",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","27316","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_331_00015","HTA1_331_0001","Not recorded","27316",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","27316","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_331_0001501","HTA1_331_00015","Not recorded","27316",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","27565","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_336_5221","HTA1_336","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","30261","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Fresh",,,,,"Right",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_336_52211","HTA1_336_5221","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","30261","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Fresh",,,,,"Right",,"Primary",,,0,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_336_5221101","HTA1_336_52211","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","30261","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"10x channels protocol/condition 2 (from fresh piece)","Biospecimen","HTA1_336_5221102","HTA1_336_5221101","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","30261","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw, https://www.protocols.io/view/htapp-depletion-of-cd45-cells-from-single-cell-sus-bjxjkpkn",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Fresh dissociated",,,,,"Right",,"Primary",,,,, +"snap frozen piece","Biospecimen","HTA1_336_52212","HTA1_336_5221","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -150C","30261","Pending",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Snap Frozen",,,,,"Right",,"Primary",,,,99, +"tumor WES (from frozen piece)","Biospecimen","HTA1_336_5221201","HTA1_336_52212","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","30911","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"Snap Frozen",,,,,"Right",,"Primary",,,,, +"OCT piece for spatial work","Biospecimen","HTA1_336_52213","HTA1_336_5221","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -150C","30261","Pending",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8574/3",,,,"OCT",,,,,"Right",,"Primary",,,,58, +"OCT section for Visium QC H&E","Biospecimen","HTA1_336_5221303","HTA1_336_52213","Not recorded","30261",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","30994","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,"Pathologist",,,,,,,,,,,,0,,,,100,5,30,,,"Cryosectioning",,,,,,"8574/3",,,,"OCT",10,30994,,,"Right",,"Primary","Superfrost microscope slide",,,, +"OCT section for Visium/H&E - A","Biospecimen","HTA1_336_5221304","HTA1_336_52213","Not recorded","30261","HTA1_336_5221305","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","31005","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8574/3",,,,"OCT",10,31005,,,"Right",,"Primary","Visium spatial gene expression slide",1,,, +"OCT section for Visium/H&E - B","Biospecimen","HTA1_336_5221305","HTA1_336_52213","Not recorded","30261","HTA1_336_5221304, HTA1_336_5221306","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","31005","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8574/3",,,,"OCT",10,31005,,,"Right",,"Primary","Visium spatial gene expression slide",3,,, +"OCT section for Visium/H&E - C","Biospecimen","HTA1_336_5221306","HTA1_336_52213","Not recorded","30261","HTA1_336_5221305, HTA1_336_5221307","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","31005","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8574/3",,,,"OCT",10,31005,,,"Right",,"Primary","Visium spatial gene expression slide",5,,, +"OCT section for Visium/H&E - D","Biospecimen","HTA1_336_5221307","HTA1_336_52213","Not recorded","30261","HTA1_336_5221306","Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","31005","https://www.protocols.io/view/htapp-oct-embedded-frozen-tissue-sectioning-and-mo-bqm3mu8n",,,,,,,,,,,,,,,,,,,,,,,,,,"Cryosectioning",,,,,,"8574/3",,,,"OCT",10,31005,,,"Right",,"Primary","Visium spatial gene expression slide",7,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_336_0001","HTA1_336","Not recorded","30261",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","30261","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_336_00015","HTA1_336_0001","Not recorded","30261",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","30261","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_336_0001501","HTA1_336_00015","Not recorded","30261",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","30911","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_337_5251","HTA1_337","Not recorded","23330",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","23330","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8070/3",,,,"Fresh",,,,,"unknown",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_337_52511","HTA1_337_5251","Not recorded","23330",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","23330","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8070/3",,,,"Fresh",,,,,"unknown",,"Primary",,,44,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_337_5251101","HTA1_337_52511","Not recorded","23330",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","23330","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8070/3",,,,"Fresh dissociated",,,,,"unknown",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_337_52513","HTA1_337_5251","Not recorded","23330",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","23330","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8070/3",,,,"OCT",,,,,"unknown",,"Primary",,,,137, +"tumor WES (from OCT piece)","Biospecimen","HTA1_337_5251301","HTA1_337_52513","Not recorded","23330",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","23522","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8070/3",,,,"OCT",,,,,"unknown",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_337_0001","HTA1_337","Not recorded","23330",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","23330","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_337_00015","HTA1_337_0001","Not recorded","23330",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","23330","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_337_0001501","HTA1_337_00015","Not recorded","23330",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","23547","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_345_5281","HTA1_345","Not recorded","28821",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","28821","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8230/3",,,,"Fresh",,,,,"Left",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_345_52811","HTA1_345_5281","Not recorded","28821",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Fresh","28821","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8230/3",,,,"Fresh",,,,,"Left",,"Primary",,,36,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_345_5281101","HTA1_345_52811","Not recorded","28821",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","28821","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8230/3",,,,"Fresh dissociated",,,,,"Left",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_345_52813","HTA1_345_5281","Not recorded","28821",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","Frozen at -80C","28821","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8230/3",,,,"OCT",,,,,"Left",,"Primary",,,,121, +"tumor WES (from OCT piece)","Biospecimen","HTA1_345_5281301","HTA1_345_52813","Not recorded","28821",,"Tissue Biospecimen Type","Surgical Resection","None","Upper lobe lung","unknown","29001","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8230/3",,,,"OCT",,,,,"Left",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_345_0001","HTA1_345","Not recorded","28821",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","28821","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_345_00015","HTA1_345_0001","Not recorded","28821",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","28821","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_345_0001501","HTA1_345_00015","Not recorded","28821",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","29026","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"original tumor (tissue removed by procedure)","Biospecimen","HTA1_415_5401","HTA1_415","Not recorded","21536",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","21536","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"unknown",,"Primary",,,,, +"fresh piece","Biospecimen","HTA1_415_54011","HTA1_415_5401","Not recorded","21536",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Fresh","21536","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh",,,,,"unknown",,"Primary",,,21,, +"10x channels protocol/condition 1 (from fresh piece)","Biospecimen","HTA1_415_5401101","HTA1_415_54011","Not recorded","21536",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","21536","https://www.protocols.io/view/htapp-dissociation-of-human-primary-lung-cancer-re-bhbgj2jw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"Fresh dissociated",,,,,"unknown",,"Primary",,,,, +"OCT piece for bulk-seq","Biospecimen","HTA1_415_54013","HTA1_415_5401","Not recorded","21536",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","Frozen at -80C","21536","https://www.protocols.io/view/htapp-fresh-tissue-embedding-in-oct-bswgnfbw",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"unknown",,"Primary",,,,101, +"tumor WES (from OCT piece)","Biospecimen","HTA1_415_5401301","HTA1_415_54013","Not recorded","21536",,"Tissue Biospecimen Type","Surgical Resection","None","Lower lobe lung","unknown","21696","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"8550/3",,,,"OCT",,,,,"unknown",,"Primary",,,,, +"germline source (tissue/blood removed by procedure)","Biospecimen","HTA1_415_0001","HTA1_415","Not recorded","21536",,"Blood Biospecimen Type","Other Acquisition Method","None","Blood","Fresh","21536","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Fresh",,,"Not Shipped",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline source (preserved source)","Biospecimen","HTA1_415_00015","HTA1_415_0001","Not recorded","21536",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","Frozen at -150C","21536","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, +"germline WES (from preserved source)","Biospecimen","HTA1_415_0001501","HTA1_415_00015","Not recorded","21536",,"Blood Biospecimen Type","Other Acquisition Method","Cryo-store","Blood","unknown","21721","Not available",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Blood draw",,,"Not Applicable",,,,"Cryopreserved",,,"Dry Ice",,"Not Applicable",,"Not Otherwise Specified",,,,, From 2677475f93b149fd5c0fae6a09967dff6792ca4d Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Sep 2021 02:12:59 +0000 Subject: [PATCH 080/260] add contributors --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 28179228..c6bbfcf5 100644 --- a/README.md +++ b/README.md @@ -71,4 +71,14 @@ This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyO -[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop \ No newline at end of file +[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop + +## Contributors + +Main contributors and developers: + +- [Xengie Doan](https://github.com/xdoan) +- [Milen Nikolov](https://github.com/milen-sage) +- [Rongrong Chai](https://github.com/rrchai) +- [Sujay Patil](https://github.com/sujaypatil96) +- [Robert Allaway](https://github.com/allaway) \ No newline at end of file From fd3238bb75852eb4f9504311b4edcb1c57c25b6e Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Sep 2021 02:14:35 +0000 Subject: [PATCH 081/260] update layout on README --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c6bbfcf5..97c4d436 100644 --- a/README.md +++ b/README.md @@ -65,13 +65,11 @@ Use the app configuration file `www/config.json` to adapt this app to your DCC. --- -### Authentication +## Authentication This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration yaml file. - - -[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop +--- ## Contributors @@ -81,4 +79,9 @@ Main contributors and developers: - [Milen Nikolov](https://github.com/milen-sage) - [Rongrong Chai](https://github.com/rrchai) - [Sujay Patil](https://github.com/sujaypatil96) -- [Robert Allaway](https://github.com/allaway) \ No newline at end of file +- [Robert Allaway](https://github.com/allaway) + + + + +[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop \ No newline at end of file From 1fa893d113812e0a1a3333a8db471f569b966139 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Sep 2021 02:15:58 +0000 Subject: [PATCH 082/260] change setup title --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 97c4d436..e0448d69 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the schematic Python package. It allows data contributors to easily annotate, validate and submit their metadata. --- -## Setup +## Get Started and Installation Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic]: @@ -59,7 +59,6 @@ Use the app configuration file `www/config.json` to adapt this app to your DCC. * `display_name` : The display name for the dropdown. (e.g. _scRNA-seq Level 1_) * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. _ScRNA-seqLevel1_) * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type _assay_. - * `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) * `community` : the abbreviated name of the community or project. (e.g. _HTAN_) From 52e71189ae306e9417330fd62b33e0cd4679e7bc Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Sep 2021 18:08:24 +0000 Subject: [PATCH 083/260] update README --- README.md | 12 +++++------- global.R | 1 + server.R | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e0448d69..9fcb8a16 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ The _Data Curator App_ is an R Shiny app that serves as the _frontend_ to the schematic Python package. It allows data contributors to easily annotate, validate and submit their metadata. --- + ## Get Started and Installation Follow the steps below to make sure the _Data Curator App_ is fully setup to work with the [schematic]: @@ -15,13 +16,11 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](###-Authentication)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: - +2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](##-Authentication)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: cp example_config.yaml config.yaml chmod 400 config.yaml - 3. Create and activate the conda environment (our conda environment name `data_curator_env` is set by default in the `example_config.yaml`.) grep 'CONDA_ENV_NAME:' config.yaml | cut -f2 -d':' | xargs conda env create -f environment.yml -n @@ -41,8 +40,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 2. Install the latest release of the `schematic` via `pip`: python -m pip install schematicpy - - + For development and test with the latest update from `schematic`, install the `schematic` via `poetry`: cd schematic @@ -74,12 +72,12 @@ This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyO Main contributors and developers: +- [Rongrong Chai](https://github.com/rrchai) - [Xengie Doan](https://github.com/xdoan) - [Milen Nikolov](https://github.com/milen-sage) -- [Rongrong Chai](https://github.com/rrchai) - [Sujay Patil](https://github.com/sujaypatil96) - [Robert Allaway](https://github.com/allaway) - +- [Bruno Grande](https://github.com/BrunoGrandePhD) diff --git a/global.R b/global.R index 0113d7d4..0252cc34 100644 --- a/global.R +++ b/global.R @@ -79,6 +79,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable reticulate::use_condaenv(conda_name) + # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) diff --git a/server.R b/server.R index 350b289d..4f825354 100644 --- a/server.R +++ b/server.R @@ -333,6 +333,7 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_submit, { # loading screen for submitting data dcWaiter("show", msg = "Submitting...") + dir.create("./tmp", showWarnings = FALSE) # reads file csv again From 375735a3a3c19a1b25a056d63dfd58e229bb418c Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Tue, 28 Sep 2021 14:16:06 -0400 Subject: [PATCH 084/260] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9fcb8a16..efe0d3b9 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](##-Authentication)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: +2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](https://github.com/Sage-Bionetworks/data_curator#authentication-oauth)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: cp example_config.yaml config.yaml chmod 400 config.yaml @@ -81,4 +81,4 @@ Main contributors and developers: -[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop \ No newline at end of file +[schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop From 77cf7a9d365999eda6ffdf08d378e60e9d8ea56d Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Tue, 28 Sep 2021 14:20:26 -0400 Subject: [PATCH 085/260] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index efe0d3b9..c35c0452 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor cp example_config.yaml config.yaml chmod 400 config.yaml -3. Create and activate the conda environment (our conda environment name `data_curator_env` is set by default in the `example_config.yaml`.) +3. Create and activate the conda environment (our conda environment name `data_curator_env` is set by default in the `example_config.yaml`): grep 'CONDA_ENV_NAME:' config.yaml | cut -f2 -d':' | xargs conda env create -f environment.yml -n conda activate data_curator_env From 9752a68431462ee400f7cda67afd1a0603e7a36b Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 29 Sep 2021 13:19:14 +0000 Subject: [PATCH 086/260] alter code to sync with updated getModelManifest() --- server.R | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/server.R b/server.R index 4f825354..6111beeb 100644 --- a/server.R +++ b/server.R @@ -199,37 +199,26 @@ shinyServer(function(input, output, session) { synStore_obj, folder_synID ) - # if there isn't an existing manifest make a new one - if (existing_manifestID == "") { - # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - datatype_list$files <<- list2Vector(file_list) - - manifest_url <- - metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), - template_schema_name, - filenames = as.list(names(datatype_list$files)), - datasetId = folder_synID - ) + + # get file list in selected folder + # don't put in the observation of folder dropdown + # it will crash if users switch folders too often + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + datatype_list$files <<- list2Vector(file_list) - # make sure not scalar if length of list is 1 in R - # add in the step to convert names later - } else { - # if the manifest already exists - manifest_entity <- syn_get(existing_manifestID) - manifest_url <- metadata_model$populateModelManifest(paste0( - config$community, - " ", input$dropdown_template - ), manifest_entity$path, template_schema_name) - } + manifest_url <- + metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), + template_schema_name, + filenames = as.list(names(datatype_list$files)), + datasetId = folder_synID + ) + # generate link output$text_download <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") ### add link to data dictionary when we have it ### + tags$a(href = manifest_url, manifest_url, target = "_blank") }) } From 3de8f0c2e072f8d41fbc4836786758e556412a52 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 29 Sep 2021 13:42:37 +0000 Subject: [PATCH 087/260] clean url and enable refresh app --- server.R | 2 +- ui.R | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index 4f825354..362beeee 100644 --- a/server.R +++ b/server.R @@ -333,7 +333,7 @@ shinyServer(function(input, output, session) { observeEvent(input$btn_submit, { # loading screen for submitting data dcWaiter("show", msg = "Submitting...") - + dir.create("./tmp", showWarnings = FALSE) # reads file csv again diff --git a/ui.R b/ui.R index 406053a1..533ff1a5 100644 --- a/ui.R +++ b/ui.R @@ -91,7 +91,8 @@ ui <- shinydashboardPlus::dashboardPage( dashboardBody( tags$head( tags$style(sass(sass_file("www/scss/main.scss"))), - singleton(includeScript("www/js/readCookie.js")) + singleton(includeScript("www/js/readCookie.js")), + tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Page Title', window.location.pathname);},2000);")) ), use_notiflix_report(), use_waiter(), From c28f4db9173459d681efc9636d7f7d28f5cb90f0 Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Wed, 29 Sep 2021 12:06:34 -0400 Subject: [PATCH 088/260] Update page title Co-authored-by: Bruno Grande --- ui.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui.R b/ui.R index 533ff1a5..4ef5b418 100644 --- a/ui.R +++ b/ui.R @@ -92,7 +92,7 @@ ui <- shinydashboardPlus::dashboardPage( tags$head( tags$style(sass(sass_file("www/scss/main.scss"))), singleton(includeScript("www/js/readCookie.js")), - tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Page Title', window.location.pathname);},2000);")) + tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Data Curator', window.location.pathname);},2000);")) ), use_notiflix_report(), use_waiter(), From 2874d1b6f543d566f682a4f7c886f65393540488 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 4 Oct 2021 18:35:01 +0000 Subject: [PATCH 089/260] add row index to DT table --- modules/DTable.R | 2 +- modules/csvInfile.R | 5 +++++ server.R | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/DTable.R b/modules/DTable.R index 9aca7a4c..0494e16b 100644 --- a/modules/DTable.R +++ b/modules/DTable.R @@ -6,7 +6,7 @@ DTableUI <- function(id) { } DTableServer <- function(id, data, - rownames = FALSE, caption = NULL, + rownames = TRUE, caption = NULL, options = list(lengthChange = FALSE, scrollX = TRUE), highlight = NULL, hightlight.col = NULL, hightlight.value = NULL) { if (!is.null(highlight)) { diff --git a/modules/csvInfile.R b/modules/csvInfile.R index 481c2341..9c959e91 100644 --- a/modules/csvInfile.R +++ b/modules/csvInfile.R @@ -35,7 +35,12 @@ csvInfileServer <- function(id, na = c("", "NA"), colsAsCharacters = FALSE, keep # remove empty rows/columns where readr called it 'X'[digit] for unnamed col infile <- infile[, !grepl("^X", colnames(infile))] infile <- infile[rowSums(is.na(infile)) != ncol(infile), ] + # add 1 to row index to match spreadsheet's row index + rownames(infile) <- as.numeric(rownames(infile)) + 1 + + return(infile) }) + return(list( raw = reactive({ input$file diff --git a/server.R b/server.R index 446dae06..e9c72598 100644 --- a/server.R +++ b/server.R @@ -262,7 +262,7 @@ shinyServer(function(input, output, session) { # output error messages as data table if it is invalid value type # render empty if error is not "invaid value" type - ifelse() will not work if (valRes$errorType == "Invalid Value") { - DTableServer("tbl_validate", valRes$errorDT, + DTableServer("tbl_validate", valRes$errorDT, rownames = FALSE, options = list( pageLength = 50, scrollX = TRUE, scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, From d9ece07a94205d45ea9f216addd35a54af9e88c9 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 4 Oct 2021 20:41:11 +0000 Subject: [PATCH 090/260] add filter on each column --- modules/DTable.R | 3 ++- server.R | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/DTable.R b/modules/DTable.R index 0494e16b..eeb416a3 100644 --- a/modules/DTable.R +++ b/modules/DTable.R @@ -6,7 +6,7 @@ DTableUI <- function(id) { } DTableServer <- function(id, data, - rownames = TRUE, caption = NULL, + rownames = TRUE, caption = NULL, filter = "top", options = list(lengthChange = FALSE, scrollX = TRUE), highlight = NULL, hightlight.col = NULL, hightlight.value = NULL) { if (!is.null(highlight)) { @@ -21,6 +21,7 @@ DTableServer <- function(id, data, df <- datatable(data, caption = caption, rownames = rownames, + filter = filter, options = options ) diff --git a/server.R b/server.R index e9c72598..93f4396e 100644 --- a/server.R +++ b/server.R @@ -262,7 +262,7 @@ shinyServer(function(input, output, session) { # output error messages as data table if it is invalid value type # render empty if error is not "invaid value" type - ifelse() will not work if (valRes$errorType == "Invalid Value") { - DTableServer("tbl_validate", valRes$errorDT, rownames = FALSE, + DTableServer("tbl_validate", valRes$errorDT, rownames = FALSE, filter = "none", options = list( pageLength = 50, scrollX = TRUE, scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, From 8d7f1c1ddf65d62c6274aba4097b923776ca311d Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 5 Oct 2021 01:59:45 +0000 Subject: [PATCH 091/260] compress duplicated errors --- functions/validationResult.R | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/functions/validationResult.R b/functions/validationResult.R index 2d9983f4..a16fa8fc 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -60,15 +60,33 @@ validationResult <- function(valRes, template, inFile) { } errorDT <- data.frame( + Row = sapply(valRes, function(i) i[[1]]), Column = sapply(valRes, function(i) i[[2]]), Value = sapply(valRes, function(i) i[[4]][[1]]), Error = sapply(valRes, function(i) i[[3]]) ) + # collapse similiar errors with one row + errorDT <- errorDT %>% + mutate(Options = gsub("^'.*?'(.*)", "\\1", Error)) %>% + group_by(Column, Options) %>% + summarise( + n = n_distinct(Value), + Row=str_c(unique(Row), collapse=", "), + Value=str_c(unique(Value), collapse=", "), + .groups = 'drop') %>% + mutate( + Options=ifelse(n > 1, str_replace(Options, "^ is", " are"), Options), + Error=str_c(sQuote(Value), Options) + ) %>% + ungroup() %>% + dplyr::select(Row, Column, Value, Error) + # sort rows based on input column names errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] # TODO: to reduce parameter, sort just based on alphabetic # errorDT <- errorDT[order(errorDT$Column),] + } else { validation_res <- "valid" errorType <- "No Error" From c33f03fdb2bf9265126a55afc392c1e1081ddb4b Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 5 Oct 2021 02:04:27 +0000 Subject: [PATCH 092/260] clean up --- functions/validationResult.R | 18 +++++++++--------- server.R | 9 +++++---- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index a16fa8fc..0664f3de 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -67,18 +67,19 @@ validationResult <- function(valRes, template, inFile) { ) # collapse similiar errors with one row - errorDT <- errorDT %>% - mutate(Options = gsub("^'.*?'(.*)", "\\1", Error)) %>% + errorDT <- errorDT %>% + mutate(Options = gsub("^'.*?'(.*)", "\\1", Error)) %>% group_by(Column, Options) %>% summarise( n = n_distinct(Value), - Row=str_c(unique(Row), collapse=", "), - Value=str_c(unique(Value), collapse=", "), - .groups = 'drop') %>% + Row = str_c(unique(Row), collapse = ", "), + Value = str_c(unique(Value), collapse = ", "), + .groups = "drop" + ) %>% mutate( - Options=ifelse(n > 1, str_replace(Options, "^ is", " are"), Options), - Error=str_c(sQuote(Value), Options) - ) %>% + Options = ifelse(n > 1, str_replace(Options, "^ is", " are"), Options), + Error = str_c(sQuote(Value), Options) + ) %>% ungroup() %>% dplyr::select(Row, Column, Value, Error) @@ -86,7 +87,6 @@ validationResult <- function(valRes, template, inFile) { errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] # TODO: to reduce parameter, sort just based on alphabetic # errorDT <- errorDT[order(errorDT$Column),] - } else { validation_res <- "valid" errorType <- "No Error" diff --git a/server.R b/server.R index 93f4396e..418bc295 100644 --- a/server.R +++ b/server.R @@ -199,7 +199,7 @@ shinyServer(function(input, output, session) { synStore_obj, folder_synID ) - + # get file list in selected folder # don't put in the observation of folder dropdown # it will crash if users switch folders too often @@ -218,7 +218,7 @@ shinyServer(function(input, output, session) { # generate link output$text_download <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") + tags$a(href = manifest_url, manifest_url, target = "_blank") }) } @@ -262,10 +262,11 @@ shinyServer(function(input, output, session) { # output error messages as data table if it is invalid value type # render empty if error is not "invaid value" type - ifelse() will not work if (valRes$errorType == "Invalid Value") { - DTableServer("tbl_validate", valRes$errorDT, rownames = FALSE, filter = "none", + DTableServer("tbl_validate", valRes$errorDT, + rownames = FALSE, filter = "none", options = list( pageLength = 50, scrollX = TRUE, - scrollY = min(50 * length(annotation_status), 400), lengthChange = FALSE, + scrollY = min(50 * nrow(valRes$errorDT), 400), lengthChange = FALSE, info = FALSE, searching = FALSE ) ) From 1e76a794f4de66cef1d970fda18545e866b2ad56 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 13:42:45 +0000 Subject: [PATCH 093/260] limit number of row index and invalid error to 10 with ellipsis --- functions/utils.R | 18 ++++++++++++++++++ functions/validationResult.R | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/functions/utils.R b/functions/utils.R index 76e230fc..edc46aa8 100644 --- a/functions/utils.R +++ b/functions/utils.R @@ -6,3 +6,21 @@ list2Vector <- function(list) { } return(vector) } + +# convert long string from "x1, x2, x3, x4, x5" into "x1, x2 ... x5" +TruncateEllipsis <- function(string, max, split_pattern = NULL) { + + if (!is.null(split_pattern)) { + string <- str_split(string, split_pattern) + } + + sapply(string,function(i) { + n <- length(i) + if (n > max) { + firstMaX <- str_c(i[1:(max-1)], collapse = ", ") + str_c(c(firstMaX, "...", i[n]), collapse = " ") + } else { + str_c(i, collapse = ", ") + } + }) +} diff --git a/functions/validationResult.R b/functions/validationResult.R index 0664f3de..23a68679 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -66,14 +66,14 @@ validationResult <- function(valRes, template, inFile) { Error = sapply(valRes, function(i) i[[3]]) ) - # collapse similiar errors with one row + # collapse similiar errors into one row errorDT <- errorDT %>% mutate(Options = gsub("^'.*?'(.*)", "\\1", Error)) %>% group_by(Column, Options) %>% summarise( n = n_distinct(Value), - Row = str_c(unique(Row), collapse = ", "), - Value = str_c(unique(Value), collapse = ", "), + Row = str_c(unique(Row), collapse = ", ") %>% TruncateEllipsis(10, ", "), + Value = str_c(unique(Value), collapse = ", ") %>% TruncateEllipsis(10, ", "), .groups = "drop" ) %>% mutate( From ce4eb2eb7f550075e2972254b8873936d0d5bc5c Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 13:52:16 +0000 Subject: [PATCH 094/260] add caption on error table --- server.R | 1 + 1 file changed, 1 insertion(+) diff --git a/server.R b/server.R index 418bc295..09d09904 100644 --- a/server.R +++ b/server.R @@ -264,6 +264,7 @@ shinyServer(function(input, output, session) { if (valRes$errorType == "Invalid Value") { DTableServer("tbl_validate", valRes$errorDT, rownames = FALSE, filter = "none", + caption = "View all the error(s) highlighted in the preview table above", options = list( pageLength = 50, scrollX = TRUE, scrollY = min(50 * nrow(valRes$errorDT), 400), lengthChange = FALSE, From 2804bad9c23b06f83b64f5f7514fbc3dc7b1febd Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 15:46:39 +0000 Subject: [PATCH 095/260] add warning message for empty folder --- server.R | 84 ++++++++++++++++++++++------------ ui.R | 7 +++ www/scss/basic/_message.scss | 3 ++ www/scss/basic/_variables.scss | 1 + 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/server.R b/server.R index 09d09904..566a608a 100644 --- a/server.R +++ b/server.R @@ -181,6 +181,44 @@ shinyServer(function(input, output, session) { ) ######## Template Google Sheet Link ######## + + observeEvent(c(input[["tabs"]], input$dropdown_folder), { + req(input[["tabs"]] == "tab_template") + + dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) + # update selected folder ID + folder_synID <<- datatype_list$folders[[input$dropdown_folder]] + + # get file list in selected folder + # don't put in the observation of folder dropdown + # it will crash if users switch folders too often + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + datatype_list$files <<- list2Vector(file_list) + dcWaiter("hide") + + if (length(datatype_list$files) == 0) { + show("div_download_warn") + output$text_download_warn <- renderUI({ + tagList( + br(), + span(class="warn_msg", + HTML(paste0( + sQuote(input$dropdown_folder), " folder is empty, + please upload your data before generating manifest.", + "
", sQuote(input$dropdown_template), + " requires data files to be uploaded prior generating and submitting templates.", + "
", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later") + ) + ) + ) + }) + } + }) + observeEvent(input$btn_download, { # loading screen for template link generation @@ -189,38 +227,26 @@ shinyServer(function(input, output, session) { # update selected folder ID folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - if (is.null(input$dropdown_template)) { - output$text_download <- renderUI({ - tags$span(class = "error_msg", HTML("Please select a template from the 'Select your Dataset' tab !")) - }) - } else { - # checks if a manifest already exists - existing_manifestID <- synapse_driver$getDatasetManifest( - synStore_obj, - folder_synID - ) + # get file list in selected folder + # don't put in the observation of folder dropdown + # it will crash if users switch folders too often + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + datatype_list$files <<- list2Vector(file_list) - # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID + manifest_url <- + metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), + template_schema_name, + filenames = as.list(names(datatype_list$files)), + datasetId = folder_synID ) - datatype_list$files <<- list2Vector(file_list) - - manifest_url <- - metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), - template_schema_name, - filenames = as.list(names(datatype_list$files)), - datasetId = folder_synID - ) - # generate link - output$text_download <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") - }) - } + # generate link + output$text_download <- renderUI({ + tags$a(href = manifest_url, manifest_url, target = "_blank") + }) dcWaiter("hide", sleep = 1) # display link diff --git a/ui.R b/ui.R index 4ef5b418..b06f7525 100644 --- a/ui.R +++ b/ui.R @@ -124,6 +124,7 @@ ui <- shinydashboardPlus::dashboardPage( h2("Set Dataset and Metadata Template for Curation"), fluidRow( box( + id = "box_pick_project", status = "primary", width = 6, title = "Choose a Project and Folder: ", @@ -142,6 +143,7 @@ ui <- shinydashboardPlus::dashboardPage( ) ), box( + id = "box_pick_template", status = "primary", width = 6, title = "Choose a Metadata Template Type: ", @@ -168,6 +170,11 @@ ui <- shinydashboardPlus::dashboardPage( class = "btn-primary-color" ), hidden( + div( + id = "div_download_warn", + height = "100%", + htmlOutput("text_download_warn") + ), div( id = "div_download", height = "100%", diff --git a/www/scss/basic/_message.scss b/www/scss/basic/_message.scss index 8740a429..e7a89d0c 100644 --- a/www/scss/basic/_message.scss +++ b/www/scss/basic/_message.scss @@ -14,6 +14,9 @@ color: $success_col; } +.warn_msg { + color: $warning_col; +} // notification .shiny-notification { position:fixed; diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index 76a46442..61171e24 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -18,6 +18,7 @@ $footer_bg_col: #202020; // message color $error_col: #E53935; $success_col: #28a745; +$warning_col: #FF9900; $notif_process_col: #F7DC6F; $notif_success_col: #82E0AA; From 10bf9a6b62f7d2783757ab6638ac687c43d45039 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 16:31:37 +0000 Subject: [PATCH 096/260] test --- server.R | 91 ++++++++++++++++++++++++++------------------------------ ui.R | 2 -- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/server.R b/server.R index 566a608a..0de90a5a 100644 --- a/server.R +++ b/server.R @@ -161,6 +161,8 @@ shinyServer(function(input, output, session) { ) }) } + logjs(paste0("1----", input[["dropdown_project"]])) + logjs(paste0("1----", input[["dropdown_folder"]])) }) ######## Update Template ######## @@ -181,61 +183,52 @@ shinyServer(function(input, output, session) { ) ######## Template Google Sheet Link ######## - - observeEvent(c(input[["tabs"]], input$dropdown_folder), { - req(input[["tabs"]] == "tab_template") - - dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) - # update selected folder ID - folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - - # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - datatype_list$files <<- list2Vector(file_list) - dcWaiter("hide") - - if (length(datatype_list$files) == 0) { - show("div_download_warn") - output$text_download_warn <- renderUI({ - tagList( - br(), - span(class="warn_msg", - HTML(paste0( - sQuote(input$dropdown_folder), " folder is empty, - please upload your data before generating manifest.", - "
", sQuote(input$dropdown_template), - " requires data files to be uploaded prior generating and submitting templates.", - "
", "Filling in a template before uploading your data, - may result in errors and delays in your data submission later") - ) - ) - ) - }) - } - }) + # warning message if folder is empty and data type is assay + # observeEvent(c(input[["tabs"]], input$dropdown_folder), { + # req(input[["tabs"]] == "tab_template") + + # logjs(paste0("2----", input[["dropdown_project"]])) + # logjs(paste0("2----", input[["dropdown_folder"]])) + # dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) + # # update selected folder ID + # folder_synID <<- datatype_list$folders[[input$dropdown_folder]] + + # # get file list in selected folder + # # don't put in the observation of folder dropdown + # # it will crash if users switch folders too often + # file_list <- synapse_driver$getFilesInStorageDataset( + # synStore_obj, + # folder_synID + # ) + # datatype_list$files <<- list2Vector(file_list) + + # dcWaiter("hide") + + # if (length(datatype_list$files) == 0) { + # show("div_download_warn") + # output$text_download_warn <- renderUI({ + # tagList( + # br(), + # span(class="warn_msg", + # HTML(paste0( + # sQuote(input$dropdown_folder), " folder is empty, + # please upload your data before generating manifest.", + # "
", sQuote(input$dropdown_template), + # " requires data files to be uploaded prior generating and submitting templates.", + # "
", "Filling in a template before uploading your data, + # may result in errors and delays in your data submission later") + # ) + # ) + # ) + # }) + # } + # }) observeEvent(input$btn_download, { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") - # update selected folder ID - folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - - # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID - ) - datatype_list$files <<- list2Vector(file_list) - manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name, diff --git a/ui.R b/ui.R index b06f7525..fbcb30ce 100644 --- a/ui.R +++ b/ui.R @@ -124,7 +124,6 @@ ui <- shinydashboardPlus::dashboardPage( h2("Set Dataset and Metadata Template for Curation"), fluidRow( box( - id = "box_pick_project", status = "primary", width = 6, title = "Choose a Project and Folder: ", @@ -143,7 +142,6 @@ ui <- shinydashboardPlus::dashboardPage( ) ), box( - id = "box_pick_template", status = "primary", width = 6, title = "Choose a Metadata Template Type: ", From c73e9fd76ccc58407f3d0ba4a8899aeef77a3025 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 18:52:49 +0000 Subject: [PATCH 097/260] ensure selected folder updated after updating folder names from project dropdown --- server.R | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/server.R b/server.R index 09d09904..8769acc8 100644 --- a/server.R +++ b/server.R @@ -95,25 +95,6 @@ shinyServer(function(input, output, session) { switchTabServer(id = paste0("switchTab", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) }) - ######## Update Folder List ######## - lapply(c("header_dropdown_", "dropdown_"), function(x) { - observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { - # get synID of selected project - projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] - - # gets folders per project - folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() - - if (x == "dropdown_") { - project_synID <<- projectID - datatype_list$folders <<- folder_list - } - - # updates foldernames - updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) - }) - }) - ######## Header Dropdown Button ######## # Adjust header selection dropdown based on tabs observe({ @@ -155,7 +136,7 @@ shinyServer(function(input, output, session) { observeEvent(input$update_confirm, { if (input$update_confirm == TRUE) { - lapply(datatypes, function(x) { + lapply(c("project", "template"), function(x) { updateSelectInput(session, paste0("dropdown_", x), selected = input[[paste0("header_dropdown_", x)]] ) @@ -163,6 +144,28 @@ shinyServer(function(input, output, session) { } }) + ######## Update Folder List ######## + lapply(c("header_dropdown_", "dropdown_"), function(x) { + observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { + # get synID of selected project + projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] + + # gets folders per project + folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() + + # updates foldernames + updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) + + if (x == "dropdown_") { + project_synID <<- projectID + datatype_list$folders <<- folder_list + } + + req(input$update_confirm) + updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) + }) + }) + ######## Update Template ######## # update selected schema template name observeEvent(input$dropdown_template, { From 555ed5ff32b67929aa267803077de673cacc42c1 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 18:53:52 +0000 Subject: [PATCH 098/260] use css to place r chunk for ellipsis --- server.R | 10 ---------- www/scss/section/_header.scss | 20 ++++++++++++++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/server.R b/server.R index 8769acc8..ff3db271 100644 --- a/server.R +++ b/server.R @@ -106,16 +106,6 @@ shinyServer(function(input, output, session) { } }) - lapply(datatypes, function(x) { - selector <- paste0("header_dropdown_", x) - observeEvent(input[[selector]], { - if (nchar(input[[selector]]) > 20) { - short <- paste0(substr(input[[selector]], 1, 20), " ...") - runjs(paste0("$('#header_content_", x, " .item').text('", short, "');")) - } - }) - }) - lapply(datatypes, function(x) { observeEvent(input[[paste0("dropdown_", x)]], { updateSelectInput(session, paste0("header_dropdown_", x), diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index e940b4d6..70942233 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -29,7 +29,7 @@ // custom dropdown - leftUI // when the box open - .open>a { + .open>a { background-color: $glass_grey !important; &:focus, &:hover { @@ -44,11 +44,11 @@ animation: fadeIn 100ms; ul.menu { - + margin: 0px; padding: 0 5px !important; // reset all margin - & * { + * { margin: 0px; } @@ -62,7 +62,19 @@ .shiny-input-container{ width: 250px; margin: 5px; - height: 34px; // remove extra space bottom + height: 34px; // match button height + + .selectize-input { + height: 20px; + } + + .item { + display: inline-block; + width: 80%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } } From 64f5184bbc793e9085def0c4e6dd12c7ed0b193f Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 18:52:49 +0000 Subject: [PATCH 099/260] ensure selected folder updated after updating folder names from project dropdown --- server.R | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/server.R b/server.R index 0de90a5a..ea3a9573 100644 --- a/server.R +++ b/server.R @@ -95,25 +95,6 @@ shinyServer(function(input, output, session) { switchTabServer(id = paste0("switchTab", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) }) - ######## Update Folder List ######## - lapply(c("header_dropdown_", "dropdown_"), function(x) { - observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { - # get synID of selected project - projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] - - # gets folders per project - folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() - - if (x == "dropdown_") { - project_synID <<- projectID - datatype_list$folders <<- folder_list - } - - # updates foldernames - updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) - }) - }) - ######## Header Dropdown Button ######## # Adjust header selection dropdown based on tabs observe({ @@ -155,7 +136,7 @@ shinyServer(function(input, output, session) { observeEvent(input$update_confirm, { if (input$update_confirm == TRUE) { - lapply(datatypes, function(x) { + lapply(c("project", "template"), function(x) { updateSelectInput(session, paste0("dropdown_", x), selected = input[[paste0("header_dropdown_", x)]] ) @@ -165,6 +146,28 @@ shinyServer(function(input, output, session) { logjs(paste0("1----", input[["dropdown_folder"]])) }) + ######## Update Folder List ######## + lapply(c("header_dropdown_", "dropdown_"), function(x) { + observeEvent(ignoreInit = TRUE, input[[paste0(x, "project")]], { + # get synID of selected project + projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] + + # gets folders per project + folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() + + # updates foldernames + updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) + + if (x == "dropdown_") { + project_synID <<- projectID + datatype_list$folders <<- folder_list + } + + req(input$update_confirm) + updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) + }) + }) + ######## Update Template ######## # update selected schema template name observeEvent(input$dropdown_template, { From 76f827ad1a4aee09dbc722ce71d246e7d1eef910 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 21:03:11 +0000 Subject: [PATCH 100/260] wait folder list update first using reactiveValue --- server.R | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/server.R b/server.R index ff3db271..9e6ed2cd 100644 --- a/server.R +++ b/server.R @@ -35,7 +35,7 @@ shinyServer(function(input, output, session) { names(template_namedList) <- config$manifest_schemas$display_name synStore_obj <- NULL # gets list of projects they have access to - project_synID <- NULL # selected project synapse ID + project_synID <- reactiveVal() # selected project synapse ID folder_synID <- NULL # selected foler synapse ID template_schema_name <- NULL # selected template schema name @@ -124,14 +124,22 @@ shinyServer(function(input, output, session) { ) }) - observeEvent(input$update_confirm, { - if (input$update_confirm == TRUE) { - lapply(c("project", "template"), function(x) { + observe({ + input$update_confirm + req(input$update_confirm == TRUE) + isolate( + updateSelectInput(session, "dropdown_project", + selected = input[["header_dropdown_project"]]) + ) + # wait folder list updating finish first + project_synID() + isolate({ + lapply(c("folder", "template"), function(x) { updateSelectInput(session, paste0("dropdown_", x), selected = input[[paste0("header_dropdown_", x)]] ) }) - } + }) }) ######## Update Folder List ######## @@ -147,12 +155,9 @@ shinyServer(function(input, output, session) { updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) if (x == "dropdown_") { - project_synID <<- projectID + project_synID(projectID) datatype_list$folders <<- folder_list } - - req(input$update_confirm) - updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) }) }) From 320ae004bd6d4dccba58d1c3f0fce43e96150835 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 21:48:59 +0000 Subject: [PATCH 101/260] fix conflicts issues --- server.R | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/server.R b/server.R index 9e6ed2cd..d8c21f02 100644 --- a/server.R +++ b/server.R @@ -35,10 +35,11 @@ shinyServer(function(input, output, session) { names(template_namedList) <- config$manifest_schemas$display_name synStore_obj <- NULL # gets list of projects they have access to - project_synID <- reactiveVal() # selected project synapse ID + project_synID <- NULL # selected project synapse ID folder_synID <- NULL # selected foler synapse ID template_schema_name <- NULL # selected template schema name + isUpdateFolder <- reactiveVal(FALSE) datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") @@ -124,21 +125,14 @@ shinyServer(function(input, output, session) { ) }) - observe({ - input$update_confirm + observeEvent(input$update_confirm, { + req(input$update_confirm == TRUE) - isolate( - updateSelectInput(session, "dropdown_project", - selected = input[["header_dropdown_project"]]) - ) - # wait folder list updating finish first - project_synID() - isolate({ - lapply(c("folder", "template"), function(x) { - updateSelectInput(session, paste0("dropdown_", x), - selected = input[[paste0("header_dropdown_", x)]] - ) - }) + isUpdateFolder(TRUE) + lapply(datatypes, function(x) { + updateSelectInput(session, paste0("dropdown_", x), + selected = input[[paste0("header_dropdown_", x)]] + ) }) }) @@ -155,9 +149,14 @@ shinyServer(function(input, output, session) { updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) if (x == "dropdown_") { - project_synID(projectID) + project_synID <<- projectID datatype_list$folders <<- folder_list } + + req(isUpdateFolder() == TRUE) + # sync with header dropdown + updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) + isUpdateFolder(FALSE) }) }) From 87f646932e1a2d22a7faab84811c0192c591cac5 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 22:00:38 +0000 Subject: [PATCH 102/260] clean up --- www/scss/section/_header.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/www/scss/section/_header.scss b/www/scss/section/_header.scss index 70942233..71350ef9 100644 --- a/www/scss/section/_header.scss +++ b/www/scss/section/_header.scss @@ -44,7 +44,6 @@ animation: fadeIn 100ms; ul.menu { - margin: 0px; padding: 0 5px !important; // reset all margin From 7087649d42ad281b3fc12f03147d617ea029c0a3 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 22:46:54 +0000 Subject: [PATCH 103/260] clean up --- server.R | 97 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/server.R b/server.R index ea3a9573..17a67625 100644 --- a/server.R +++ b/server.R @@ -39,6 +39,7 @@ shinyServer(function(input, output, session) { folder_synID <- NULL # selected foler synapse ID template_schema_name <- NULL # selected template schema name + isUpdateFolder <- reactiveVal(FALSE) datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") @@ -135,15 +136,13 @@ shinyServer(function(input, output, session) { }) observeEvent(input$update_confirm, { - if (input$update_confirm == TRUE) { - lapply(c("project", "template"), function(x) { - updateSelectInput(session, paste0("dropdown_", x), - selected = input[[paste0("header_dropdown_", x)]] - ) - }) - } - logjs(paste0("1----", input[["dropdown_project"]])) - logjs(paste0("1----", input[["dropdown_folder"]])) + req(input$update_confirm == TRUE) + isUpdateFolder(TRUE) + lapply(datatypes, function(x) { + updateSelectInput(session, paste0("dropdown_", x), + selected = input[[paste0("header_dropdown_", x)]] + ) + }) }) ######## Update Folder List ######## @@ -163,8 +162,10 @@ shinyServer(function(input, output, session) { datatype_list$folders <<- folder_list } - req(input$update_confirm) + req(isUpdateFolder() == TRUE) + # sync with header dropdown updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) + isUpdateFolder(FALSE) }) }) @@ -187,45 +188,45 @@ shinyServer(function(input, output, session) { ######## Template Google Sheet Link ######## # warning message if folder is empty and data type is assay - # observeEvent(c(input[["tabs"]], input$dropdown_folder), { - # req(input[["tabs"]] == "tab_template") - - # logjs(paste0("2----", input[["dropdown_project"]])) - # logjs(paste0("2----", input[["dropdown_folder"]])) - # dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) - # # update selected folder ID - # folder_synID <<- datatype_list$folders[[input$dropdown_folder]] - - # # get file list in selected folder - # # don't put in the observation of folder dropdown - # # it will crash if users switch folders too often - # file_list <- synapse_driver$getFilesInStorageDataset( - # synStore_obj, - # folder_synID - # ) - # datatype_list$files <<- list2Vector(file_list) + observeEvent(input$dropdown_folder, { + + hide("div_download_warn") + req(input[["tabs"]]== "tab_template") + + dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) + # update selected folder ID + folder_synID <<- datatype_list$folders[[input$dropdown_folder]] + + # get file list in selected folder + # don't put in the observation of folder dropdown + # it will crash if users switch folders too often + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID + ) + datatype_list$files <<- list2Vector(file_list) - # dcWaiter("hide") - - # if (length(datatype_list$files) == 0) { - # show("div_download_warn") - # output$text_download_warn <- renderUI({ - # tagList( - # br(), - # span(class="warn_msg", - # HTML(paste0( - # sQuote(input$dropdown_folder), " folder is empty, - # please upload your data before generating manifest.", - # "
", sQuote(input$dropdown_template), - # " requires data files to be uploaded prior generating and submitting templates.", - # "
", "Filling in a template before uploading your data, - # may result in errors and delays in your data submission later") - # ) - # ) - # ) - # }) - # } - # }) + dcWaiter("hide") + + if (length(datatype_list$files) == 0) { + output$text_download_warn <- renderUI({ + tagList( + br(), + span(class="warn_msg", + HTML(paste0( + sQuote(input$dropdown_folder), " folder is empty, + please upload your data before generating manifest.", + "
", sQuote(input$dropdown_template), + " requires data files to be uploaded prior generating and submitting templates.", + "
", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later") + ) + ) + ) + }) + show("div_download_warn") + } + }) observeEvent(input$btn_download, { From 69600410e188103e6972521468af8ceeede29012 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 23:27:43 +0000 Subject: [PATCH 104/260] add template type validation --- server.R | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/server.R b/server.R index 7077842f..67f932b4 100644 --- a/server.R +++ b/server.R @@ -37,7 +37,7 @@ shinyServer(function(input, output, session) { synStore_obj <- NULL # gets list of projects they have access to project_synID <- NULL # selected project synapse ID folder_synID <- NULL # selected foler synapse ID - template_schema_name <- NULL # selected template schema name + template_schema_name <- reactiveVal(NULL) # selected template schema name isUpdateFolder <- reactiveVal(FALSE) datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) @@ -162,7 +162,7 @@ shinyServer(function(input, output, session) { ######## Update Template ######## # update selected schema template name observeEvent(input$dropdown_template, { - template_schema_name <<- template_namedList[match(input$dropdown_template, names(template_namedList))] + template_schema_name(template_namedList[match(input$dropdown_template, names(template_namedList))]) }) # hide tags when users select new template @@ -177,10 +177,8 @@ shinyServer(function(input, output, session) { ) ######## Template Google Sheet Link ######## - # warning message if folder is empty and data type is assay observeEvent(input$dropdown_folder, { - - hide("div_download_warn") + req(input[["tabs"]]== "tab_template") dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) @@ -195,10 +193,17 @@ shinyServer(function(input, output, session) { folder_synID ) datatype_list$files <<- list2Vector(file_list) - dcWaiter("hide") + }) - if (length(datatype_list$files) == 0) { + # display warning message if folder is empty and data type is assay + observeEvent(c(input$dropdown_folder, template_schema_name()), { + + req(input[["tabs"]]== "tab_template") + + hide("div_download_warn") + template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] + req(length(datatype_list$files) == 0 & template_type == "assay") output$text_download_warn <- renderUI({ tagList( br(), @@ -214,8 +219,7 @@ shinyServer(function(input, output, session) { ) ) }) - show("div_download_warn") - } + show("div_download_warn") }) observeEvent(input$btn_download, { @@ -225,7 +229,7 @@ shinyServer(function(input, output, session) { manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), - template_schema_name, + template_schema_name(), filenames = as.list(names(datatype_list$files)), datasetId = folder_synID ) From 0e667f9cab1cbcd752687f64ed761c6d2854b09e Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 8 Oct 2021 23:28:57 +0000 Subject: [PATCH 105/260] clean up --- server.R | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/server.R b/server.R index 67f932b4..5beca7ec 100644 --- a/server.R +++ b/server.R @@ -165,17 +165,6 @@ shinyServer(function(input, output, session) { template_schema_name(template_namedList[match(input$dropdown_template, names(template_namedList))]) }) - # hide tags when users select new template - observeEvent( - { - input$dropdown_folder - input$dropdown_template - }, - { - sapply(clean_tags, FUN = hide) - } - ) - ######## Template Google Sheet Link ######## observeEvent(input$dropdown_folder, { @@ -198,9 +187,12 @@ shinyServer(function(input, output, session) { # display warning message if folder is empty and data type is assay observeEvent(c(input$dropdown_folder, template_schema_name()), { - + + # hide tags when users select new template + sapply(clean_tags, FUN = hide) + req(input[["tabs"]]== "tab_template") - + hide("div_download_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") @@ -265,7 +257,7 @@ shinyServer(function(input, output, session) { silent = TRUE, annotation_status <- metadata_model$validateModelManifest( inFile$raw()$datapath, - template_schema_name + template_schema_name() ) ) @@ -326,7 +318,7 @@ shinyServer(function(input, output, session) { filled_manifest <- metadata_model$populateModelManifest(paste0( config$community, " ", input$dropdown_template - ), inFile$raw()$datapath, template_schema_name) + ), inFile$raw()$datapath, template_schema_name()) # rerender and change button to link output$val_gsheet <- renderUI({ From c4de46796d8e7cb4b4960b335f7696ed47a94c39 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 11 Oct 2021 19:12:16 +0000 Subject: [PATCH 106/260] improve logic & change folder_synID to reactiveVal --- functions/utils.R | 9 +++--- server.R | 71 ++++++++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/functions/utils.R b/functions/utils.R index edc46aa8..c22640d0 100644 --- a/functions/utils.R +++ b/functions/utils.R @@ -7,17 +7,16 @@ list2Vector <- function(list) { return(vector) } -# convert long string from "x1, x2, x3, x4, x5" into "x1, x2 ... x5" +# convert long string from "x1, x2, x3, x4, x5" into "x1, x2 ... x5" TruncateEllipsis <- function(string, max, split_pattern = NULL) { - if (!is.null(split_pattern)) { string <- str_split(string, split_pattern) } - - sapply(string,function(i) { + + sapply(string, function(i) { n <- length(i) if (n > max) { - firstMaX <- str_c(i[1:(max-1)], collapse = ", ") + firstMaX <- str_c(i[1:(max - 1)], collapse = ", ") str_c(c(firstMaX, "...", i[n]), collapse = " ") } else { str_c(i, collapse = ", ") diff --git a/server.R b/server.R index 5beca7ec..ec8bbc71 100644 --- a/server.R +++ b/server.R @@ -36,7 +36,7 @@ shinyServer(function(input, output, session) { synStore_obj <- NULL # gets list of projects they have access to project_synID <- NULL # selected project synapse ID - folder_synID <- NULL # selected foler synapse ID + folder_synID <- reactiveVal("") # selected foler synapse ID template_schema_name <- reactiveVal(NULL) # selected template schema name isUpdateFolder <- reactiveVal(FALSE) @@ -107,6 +107,7 @@ shinyServer(function(input, output, session) { } }) + # sync header dropdown with main dropdown lapply(datatypes, function(x) { observeEvent(input[[paste0("dropdown_", x)]], { updateSelectInput(session, paste0("header_dropdown_", x), @@ -152,10 +153,11 @@ shinyServer(function(input, output, session) { datatype_list$folders <<- folder_list } - req(isUpdateFolder() == TRUE) - # sync with header dropdown - updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) - isUpdateFolder(FALSE) + if (isUpdateFolder()) { + # sync with header dropdown + updateSelectInput(session, "dropdown_folder", selected = input[["header_dropdown_folder"]]) + isUpdateFolder(FALSE) + } }) }) @@ -166,51 +168,50 @@ shinyServer(function(input, output, session) { }) ######## Template Google Sheet Link ######## - observeEvent(input$dropdown_folder, { - - req(input[["tabs"]]== "tab_template") - + observeEvent(c(input$dropdown_folder, input$tabs), { + req(input$tabs == "tab_template") + tmp_folder_synID <- datatype_list$folders[[input$dropdown_folder]] + req(tmp_folder_synID != folder_synID()) # if folder changes + dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) # update selected folder ID - folder_synID <<- datatype_list$folders[[input$dropdown_folder]] + folder_synID(tmp_folder_synID) # get file list in selected folder - # don't put in the observation of folder dropdown - # it will crash if users switch folders too often file_list <- synapse_driver$getFilesInStorageDataset( synStore_obj, - folder_synID + folder_synID() ) datatype_list$files <<- list2Vector(file_list) dcWaiter("hide") }) # display warning message if folder is empty and data type is assay - observeEvent(c(input$dropdown_folder, template_schema_name()), { - + observeEvent(c(folder_synID(), template_schema_name()), { + # hide tags when users select new template sapply(clean_tags, FUN = hide) - - req(input[["tabs"]]== "tab_template") + req(input$tabs == "tab_template") hide("div_download_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") - output$text_download_warn <- renderUI({ - tagList( - br(), - span(class="warn_msg", - HTML(paste0( - sQuote(input$dropdown_folder), " folder is empty, + output$text_download_warn <- renderUI({ + tagList( + br(), + span( + class = "warn_msg", + HTML(paste0( + sQuote(input$dropdown_folder), " folder is empty, please upload your data before generating manifest.", - "
", sQuote(input$dropdown_template), - " requires data files to be uploaded prior generating and submitting templates.", - "
", "Filling in a template before uploading your data, - may result in errors and delays in your data submission later") - ) - ) + "
", sQuote(input$dropdown_template), + " requires data files to be uploaded prior generating and submitting templates.", + "
", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later" + )) ) - }) + ) + }) show("div_download_warn") }) @@ -223,7 +224,7 @@ shinyServer(function(input, output, session) { metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), filenames = as.list(names(datatype_list$files)), - datasetId = folder_synID + datasetId = folder_synID() ) # generate link @@ -343,7 +344,7 @@ shinyServer(function(input, output, session) { # the type to filter (eg assay) on could probably also be a config choice assay_schemas <- config$manifest_schemas$display_name[config$manifest_schemas$type == "assay"] # if folder_ID has not been updated yet - if (is.null(folder_synID)) folder_synID <<- datatype_list$folders[[input$dropdown_folder]] + if (folder_synID() == "") folder_synID(datatype_list$folders[[input$dropdown_folder]]) if (input$dropdown_template %in% assay_schemas) { # make into a csv or table for assay components already has entityId @@ -353,7 +354,7 @@ shinyServer(function(input, output, session) { quote = TRUE, row.names = FALSE, na = "" ) } else { - file_list <- synapse_driver$getFilesInStorageDataset(synStore_obj, folder_synID) + file_list <- synapse_driver$getFilesInStorageDataset(synStore_obj, folder_synID()) datatype_list$files <<- list2Vector(file_list) # better filename checking is needed @@ -372,7 +373,7 @@ shinyServer(function(input, output, session) { # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./tmp/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID() ) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) # if no error @@ -402,7 +403,7 @@ shinyServer(function(input, output, session) { # associates metadata with data and returns manifest id manifest_id <- synapse_driver$associateMetadataWithFiles( synStore_obj, - "./tmp/synapse_storage_manifest.csv", folder_synID + "./tmp/synapse_storage_manifest.csv", folder_synID() ) manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) From 9daa40c05e7c4b2847acc45f58df31b9bd23814a Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:06:20 +0000 Subject: [PATCH 107/260] make gsheet link more obvious --- server.R | 61 +++++++++++++++++++--------------- ui.R | 17 ++++------ www/scss/basic/_button.scss | 7 +++- www/scss/basic/_variables.scss | 1 + www/scss/section/_content.scss | 14 ++++++++ 5 files changed, 63 insertions(+), 37 deletions(-) diff --git a/server.R b/server.R index ec8bbc71..adfc5a7a 100644 --- a/server.R +++ b/server.R @@ -43,7 +43,7 @@ shinyServer(function(input, output, session) { datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") + clean_tags <- c("div_template", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") # add box effects boxEffect(zoom = TRUE, float = TRUE) @@ -193,50 +193,59 @@ shinyServer(function(input, output, session) { sapply(clean_tags, FUN = hide) req(input$tabs == "tab_template") - hide("div_download_warn") + hide("div_template_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") - output$text_download_warn <- renderUI({ - tagList( - br(), - span( - class = "warn_msg", - HTML(paste0( - sQuote(input$dropdown_folder), " folder is empty, - please upload your data before generating manifest.", - "
", sQuote(input$dropdown_template), - " requires data files to be uploaded prior generating and submitting templates.", - "
", "Filling in a template before uploading your data, - may result in errors and delays in your data submission later" - )) - ) - ) - }) - show("div_download_warn") + + warn_text <- paste0( + strong(sQuote(input$dropdown_folder)), " folder is empty, + please upload your data before generating manifest.", + "

", strong(sQuote(input$dropdown_template)), + " requires data files to be uploaded prior generating and submitting templates.", + "

", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later." + ) + + nx_report_warning("Warning", HTML(warn_text)) + output$text_template_warn <- renderUI(tagList(br(), span(class = "warn_msg", HTML(warn_text)))) + + show("div_template_warn") }) - observeEvent(input$btn_download, { + observeEvent(input$btn_template, { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") - + manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), filenames = as.list(names(datatype_list$files)), datasetId = folder_synID() ) - + # generate link - output$text_download <- renderUI({ - tags$a(href = manifest_url, manifest_url, target = "_blank") - }) + output$text_template <- renderUI( + tags$a(id = "template_link", href = manifest_url, list(icon("hand-point-right"), manifest_url), target = "_blank") + ) dcWaiter("hide", sleep = 1) + + nx_confirm( + inputId = "btn_template_confirm", + title = "Go to the spreadsheet now?", + button_ok = "Go", + ) + # display link - show("div_download") # TODO: add progress bar on (loading) screen + # TODO: add progress bar on (loading) screen with backend support + show("div_template") }) + observeEvent(input$btn_template_confirm, { + req(input$btn_template_confirm == TRUE) + runjs("$('#template_link')[0].click();") + }) ######## Reads .csv File ######## inFile <- csvInfileServer("inputFile", colsAsCharacters = TRUE, keepBlank = TRUE) diff --git a/ui.R b/ui.R index fbcb30ce..1a34a966 100644 --- a/ui.R +++ b/ui.R @@ -34,10 +34,7 @@ ui <- shinydashboardPlus::dashboardPage( ) ) }), - actionButton( - inputId = "btn_header_update", class = "btn-shiny-effect", - label = NULL, icon = icon("sync-alt") - ) + actionButton("btn_header_update", NULL, icon("sync-alt"), class = "btn-shiny-effect") ) ) ), @@ -94,7 +91,7 @@ ui <- shinydashboardPlus::dashboardPage( singleton(includeScript("www/js/readCookie.js")), tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Data Curator', window.location.pathname);},2000);")) ), - use_notiflix_report(), + use_notiflix_report(width = "400px"), use_waiter(), tabItems( # First tab content @@ -164,19 +161,19 @@ ui <- shinydashboardPlus::dashboardPage( title = "Get Link, Annotate, and Download Template as CSV", status = "primary", width = 12, - actionButton("btn_download", "Click to Generate Google Sheets Template", + actionButton("btn_template", "Click to Generate Google Sheets Template", class = "btn-primary-color" ), hidden( div( - id = "div_download_warn", + id = "div_template_warn", height = "100%", - htmlOutput("text_download_warn") + htmlOutput("text_template_warn") ), div( - id = "div_download", + id = "div_template", height = "100%", - htmlOutput("text_download") + htmlOutput("text_template") ) ), helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 31b83af6..661d8c1a 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -120,7 +120,6 @@ } } - // simple float effect // #btn_download, #btn_validate, #btn_val_gsheet, #btn_submit .btn-primary-color { @@ -144,3 +143,9 @@ background: $primary_col; border-radius: 40px; } + +// link +.btn_link { + @extend .btn-shiny-effect; + +} \ No newline at end of file diff --git a/www/scss/basic/_variables.scss b/www/scss/basic/_variables.scss index 61171e24..60011007 100644 --- a/www/scss/basic/_variables.scss +++ b/www/scss/basic/_variables.scss @@ -7,6 +7,7 @@ $light: #f8f9fa; $light2: #f4f4f4; $dark: #343a40; $glass_grey: rgba(104, 103, 103, 0.3); +$organe_red: #e55a17; // section color $bg_primary_col: $light; diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 746c823f..ff192122 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -52,6 +52,20 @@ } } +#div_template { + margin: 20px 0; + + #template_link { + margin-left: 2.5px; // align help text + color: $organe_red; + font-size: 1.2em; + + &:hover { + text-decoration: underline; + } + } +} + #div_download, #div_validate, #div_val_gsheet { font-size: 18px; background-color: white; From c3f319b5a632f287adab3e60d8d0ae45a7757cec Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:09:40 +0000 Subject: [PATCH 108/260] clean up --- server.R | 33 ++++++++++++++++++--------------- ui.R | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/server.R b/server.R index adfc5a7a..e657c22f 100644 --- a/server.R +++ b/server.R @@ -196,20 +196,23 @@ shinyServer(function(input, output, session) { hide("div_template_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") - - warn_text <- paste0( - strong(sQuote(input$dropdown_folder)), " folder is empty, - please upload your data before generating manifest.", - "

", strong(sQuote(input$dropdown_template)), - " requires data files to be uploaded prior generating and submitting templates.", - "

", "Filling in a template before uploading your data, - may result in errors and delays in your data submission later." - ) - - nx_report_warning("Warning", HTML(warn_text)) - output$text_template_warn <- renderUI(tagList(br(), span(class = "warn_msg", HTML(warn_text)))) - - show("div_template_warn") + output$text_download_warn <- renderUI({ + tagList( + br(), + span( + class = "warn_msg", + HTML(paste0( + sQuote(input$dropdown_folder), " folder is empty, + please upload your data before generating manifest.", + "
", sQuote(input$dropdown_template), + " requires data files to be uploaded prior generating and submitting templates.", + "
", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later" + )) + ) + ) + }) + show("div_download_warn") }) observeEvent(input$btn_template, { @@ -230,7 +233,7 @@ shinyServer(function(input, output, session) { ) dcWaiter("hide", sleep = 1) - + nx_confirm( inputId = "btn_template_confirm", title = "Go to the spreadsheet now?", diff --git a/ui.R b/ui.R index 1a34a966..0f2f5696 100644 --- a/ui.R +++ b/ui.R @@ -91,7 +91,7 @@ ui <- shinydashboardPlus::dashboardPage( singleton(includeScript("www/js/readCookie.js")), tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Data Curator', window.location.pathname);},2000);")) ), - use_notiflix_report(width = "400px"), + use_notiflix_report(), use_waiter(), tabItems( # First tab content From cb47bcd302bac78e6c1359f64a3f62ccb86bb2d8 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:14:56 +0000 Subject: [PATCH 109/260] update phrase --- server.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.R b/server.R index e657c22f..e64e27da 100644 --- a/server.R +++ b/server.R @@ -236,7 +236,8 @@ shinyServer(function(input, output, session) { nx_confirm( inputId = "btn_template_confirm", - title = "Go to the spreadsheet now?", + title = "Edit the template on the google sheet now?", + message = "click 'Go' to redirect to the template in a new tab", button_ok = "Go", ) From 26d2dac0e5c80819efdb33661b244abafc7b72e8 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:23:19 +0000 Subject: [PATCH 110/260] add template name --- server.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index e64e27da..8e5b1363 100644 --- a/server.R +++ b/server.R @@ -236,8 +236,8 @@ shinyServer(function(input, output, session) { nx_confirm( inputId = "btn_template_confirm", - title = "Edit the template on the google sheet now?", - message = "click 'Go' to redirect to the template in a new tab", + title = "Go to the template now?", + message = paste0("click 'Go' to edit your ", sQuote(input$dropdown_template), " template on the google sheet"), button_ok = "Go", ) From 833d7855d2dee7bb339e3f777a26fe427cf12eb6 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:32:50 +0000 Subject: [PATCH 111/260] add pop up box --- server.R | 30 +++++++++++++----------------- ui.R | 2 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/server.R b/server.R index ec8bbc71..f2f00484 100644 --- a/server.R +++ b/server.R @@ -196,23 +196,19 @@ shinyServer(function(input, output, session) { hide("div_download_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") - output$text_download_warn <- renderUI({ - tagList( - br(), - span( - class = "warn_msg", - HTML(paste0( - sQuote(input$dropdown_folder), " folder is empty, - please upload your data before generating manifest.", - "
", sQuote(input$dropdown_template), - " requires data files to be uploaded prior generating and submitting templates.", - "
", "Filling in a template before uploading your data, - may result in errors and delays in your data submission later" - )) - ) - ) - }) - show("div_download_warn") + warn_text <- paste0( + strong(sQuote(input$dropdown_folder)), " folder is empty, + please upload your data before generating manifest.", + "

", strong(sQuote(input$dropdown_template)), + " requires data files to be uploaded prior generating and submitting templates.", + "

", "Filling in a template before uploading your data, + may result in errors and delays in your data submission later." + ) + + nx_report_warning("Warning", HTML(warn_text)) + output$text_template_warn <- renderUI(tagList(br(), span(class = "warn_msg", HTML(warn_text)))) + + show("div_template_warn") }) observeEvent(input$btn_download, { diff --git a/ui.R b/ui.R index fbcb30ce..d09b9774 100644 --- a/ui.R +++ b/ui.R @@ -94,7 +94,7 @@ ui <- shinydashboardPlus::dashboardPage( singleton(includeScript("www/js/readCookie.js")), tags$script(htmlwidgets::JS("setTimeout(function(){history.pushState({}, 'Data Curator', window.location.pathname);},2000);")) ), - use_notiflix_report(), + use_notiflix_report(width = "400px"), use_waiter(), tabItems( # First tab content From 726fbf98f05d4e17309726f77d67330c7b8d42bd Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:36:45 +0000 Subject: [PATCH 112/260] change download to template --- server.R | 10 +++++----- ui.R | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/server.R b/server.R index f2f00484..7055a7b6 100644 --- a/server.R +++ b/server.R @@ -43,7 +43,7 @@ shinyServer(function(input, output, session) { datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") + clean_tags <- c("div_template", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") # add box effects boxEffect(zoom = TRUE, float = TRUE) @@ -193,7 +193,7 @@ shinyServer(function(input, output, session) { sapply(clean_tags, FUN = hide) req(input$tabs == "tab_template") - hide("div_download_warn") + hide("div_template_warn") template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") warn_text <- paste0( @@ -211,7 +211,7 @@ shinyServer(function(input, output, session) { show("div_template_warn") }) - observeEvent(input$btn_download, { + observeEvent(input$btn_template, { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") @@ -224,13 +224,13 @@ shinyServer(function(input, output, session) { ) # generate link - output$text_download <- renderUI({ + output$text_template <- renderUI({ tags$a(href = manifest_url, manifest_url, target = "_blank") }) dcWaiter("hide", sleep = 1) # display link - show("div_download") # TODO: add progress bar on (loading) screen + show("div_template") # TODO: add progress bar on (loading) screen }) diff --git a/ui.R b/ui.R index d09b9774..c36c6ae8 100644 --- a/ui.R +++ b/ui.R @@ -164,19 +164,19 @@ ui <- shinydashboardPlus::dashboardPage( title = "Get Link, Annotate, and Download Template as CSV", status = "primary", width = 12, - actionButton("btn_download", "Click to Generate Google Sheets Template", + actionButton("btn_template", "Click to Generate Google Sheets Template", class = "btn-primary-color" ), hidden( div( - id = "div_download_warn", + id = "div_template_warn", height = "100%", - htmlOutput("text_download_warn") + htmlOutput("text_template_warn") ), div( - id = "div_download", + id = "div_template", height = "100%", - htmlOutput("text_download") + htmlOutput("text_template") ) ), helpText("This link will leads to an empty template or your previously submitted template with new files if applicable.") From 83bab8523024bdff9ec427d951033e13282b8059 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:39:47 +0000 Subject: [PATCH 113/260] align helper message --- www/scss/section/_content.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/scss/section/_content.scss b/www/scss/section/_content.scss index 746c823f..9622744f 100644 --- a/www/scss/section/_content.scss +++ b/www/scss/section/_content.scss @@ -52,6 +52,10 @@ } } +#div_template_warn { + margin-left: 5px; +} + #div_download, #div_validate, #div_val_gsheet { font-size: 18px; background-color: white; From e3a7e02de51b5af3cf2e61cfde0d665b5d545281 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:51:56 +0000 Subject: [PATCH 114/260] remove not needed changes --- www/scss/basic/_button.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 661d8c1a..023ff473 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -142,10 +142,4 @@ .shiny-file-input-progress .progress-bar { background: $primary_col; border-radius: 40px; -} - -// link -.btn_link { - @extend .btn-shiny-effect; - } \ No newline at end of file From 2bf953a966aef7d41fe3adb11d94e15595554b31 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:52:41 +0000 Subject: [PATCH 115/260] remove not needed changes --- server.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/server.R b/server.R index 72a5979d..116efb27 100644 --- a/server.R +++ b/server.R @@ -215,14 +215,12 @@ shinyServer(function(input, output, session) { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") - manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), filenames = as.list(names(datatype_list$files)), datasetId = folder_synID() ) - # generate link output$text_template <- renderUI( tags$a(id = "template_link", href = manifest_url, list(icon("hand-point-right"), manifest_url), target = "_blank") From d130485e8671d01abe12b86c72751926bab7867f Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 12 Oct 2021 17:54:38 +0000 Subject: [PATCH 116/260] formatter --- server.R | 6 ++++-- www/scss/basic/_button.scss | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server.R b/server.R index 116efb27..4051d922 100644 --- a/server.R +++ b/server.R @@ -207,7 +207,7 @@ shinyServer(function(input, output, session) { nx_report_warning("Warning", HTML(warn_text)) output$text_template_warn <- renderUI(tagList(br(), span(class = "warn_msg", HTML(warn_text)))) - + show("div_template_warn") }) @@ -215,12 +215,14 @@ shinyServer(function(input, output, session) { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") + manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), filenames = as.list(names(datatype_list$files)), datasetId = folder_synID() ) + # generate link output$text_template <- renderUI( tags$a(id = "template_link", href = manifest_url, list(icon("hand-point-right"), manifest_url), target = "_blank") @@ -234,7 +236,7 @@ shinyServer(function(input, output, session) { message = paste0("click 'Go' to edit your ", sQuote(input$dropdown_template), " template on the google sheet"), button_ok = "Go", ) - + # display link show("div_template") # TODO: add progress bar on (loading) screen }) diff --git a/www/scss/basic/_button.scss b/www/scss/basic/_button.scss index 023ff473..00c11c53 100644 --- a/www/scss/basic/_button.scss +++ b/www/scss/basic/_button.scss @@ -142,4 +142,4 @@ .shiny-file-input-progress .progress-bar { background: $primary_col; border-radius: 40px; -} \ No newline at end of file +} From 39528f7cf62e187185f313949331a30b39595248 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 14 Oct 2021 21:08:56 +0000 Subject: [PATCH 117/260] not populate file list for record-based data type --- server.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server.R b/server.R index 4051d922..906bc078 100644 --- a/server.R +++ b/server.R @@ -38,6 +38,7 @@ shinyServer(function(input, output, session) { project_synID <- NULL # selected project synapse ID folder_synID <- reactiveVal("") # selected foler synapse ID template_schema_name <- reactiveVal(NULL) # selected template schema name + template_type <- NULL # type of selected template isUpdateFolder <- reactiveVal(FALSE) datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) @@ -194,7 +195,7 @@ shinyServer(function(input, output, session) { req(input$tabs == "tab_template") hide("div_template_warn") - template_type <- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] + template_type <<- config$manifest_schemas$type[match(template_schema_name(), template_namedList)] req(length(datatype_list$files) == 0 & template_type == "assay") warn_text <- paste0( strong(sQuote(input$dropdown_folder)), " folder is empty, @@ -215,11 +216,11 @@ shinyServer(function(input, output, session) { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") - + manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), - filenames = as.list(names(datatype_list$files)), + filenames = switch((template_type == "assay") + 1, NULL, as.list(names(datatype_list$files))), datasetId = folder_synID() ) From c7ecbca1a61de02541280a769ab1f32ab8e36bc0 Mon Sep 17 00:00:00 2001 From: Milen Nikolov Date: Mon, 18 Oct 2021 13:12:23 -0700 Subject: [PATCH 118/260] Adding SRRS data model components to config --- www/config.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/config.json b/www/config.json index d3144027..9ed901b1 100644 --- a/www/config.json +++ b/www/config.json @@ -31,7 +31,9 @@ {"display_name": "Clinical Tier 3: Prostate Precancer and Cancer", "schema_name": "ProstateCancerTier3", "type": "clinical"}, {"display_name": "Clinical Tier 3: Sarcoma", "schema_name": "SarcomaTier3", "type": "clinical"}, {"display_name": "Biospecimen Tier 1 & 2", "schema_name": "Biospecimen", "type": "biospecimen"}, - {"display_name": "Other Assay (Minimal Metadata)", "schema_name": "OtherAssay", "type": "assay"} + {"display_name": "Other Assay (Minimal Metadata)", "schema_name": "OtherAssay", "type": "assay"}, + {"display_name": "SRRS Biospecimen Tier 1 & 2", "schema_name": "SRRSBiospecimen", "type": "biospecimen"}, + {"display_name": "SRRS Clinical Tier 2", "schema_name": "SRRSClinicalDataTier2", "type": "clinical"} ], "main_fileview" : "syn20446927", "community" : "HTAN" From 2ac2790c66de8db771c3dd8b661b1bfad467f46b Mon Sep 17 00:00:00 2001 From: Milen Nikolov Date: Fri, 29 Oct 2021 11:59:29 -0700 Subject: [PATCH 119/260] Adding scATAC-seq level 4 to components --- www/config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/www/config.json b/www/config.json index 9ed901b1..9ce99d1d 100644 --- a/www/config.json +++ b/www/config.json @@ -5,6 +5,7 @@ {"display_name": "scRNA-seq Level 3", "schema_name": "ScRNA-seqLevel3", "type": "assay"}, {"display_name": "scRNA-seq Level 4", "schema_name": "ScRNA-seqLevel4", "type": "assay"}, {"display_name": "scATAC-seq Level 1", "schema_name": "ScATAC-seqLevel1", "type": "assay"}, + {"display_name": "scATAC-seq Level 4", "schema_name": "ScATAC-seqLevel4", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 1", "schema_name": "BulkRNA-seqLevel1", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 2", "schema_name": "BulkRNA-seqLevel2", "type": "assay"}, {"display_name": "Bulk RNA-seq Level 3", "schema_name": "BulkRNA-seqLevel3", "type": "assay"}, From 3c7ab7fb21991a93b8cc3a921a034088ad474573 Mon Sep 17 00:00:00 2001 From: Milen Nikolov Date: Fri, 5 Nov 2021 13:11:50 -0700 Subject: [PATCH 120/260] added SRRS imaging component to config --- www/config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/config.json b/www/config.json index 9ce99d1d..cf30aea7 100644 --- a/www/config.json +++ b/www/config.json @@ -34,7 +34,8 @@ {"display_name": "Biospecimen Tier 1 & 2", "schema_name": "Biospecimen", "type": "biospecimen"}, {"display_name": "Other Assay (Minimal Metadata)", "schema_name": "OtherAssay", "type": "assay"}, {"display_name": "SRRS Biospecimen Tier 1 & 2", "schema_name": "SRRSBiospecimen", "type": "biospecimen"}, - {"display_name": "SRRS Clinical Tier 2", "schema_name": "SRRSClinicalDataTier2", "type": "clinical"} + {"display_name": "SRRS Clinical Tier 2", "schema_name": "SRRSClinicalDataTier2", "type": "clinical"}, + {"display_name": "SRRS Imaging Level 2", "schema_name": "SRRSImagingLevel2", "type": "assay"} ], "main_fileview" : "syn20446927", "community" : "HTAN" From 70a3971703823449262629df4bef9aaae054f77a Mon Sep 17 00:00:00 2001 From: Yooree Chae Date: Tue, 9 Nov 2021 17:31:44 -0800 Subject: [PATCH 121/260] Update issue templates --- .github/ISSUE_TEMPLATE/bug-bash-report.md | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-bash-report.md diff --git a/.github/ISSUE_TEMPLATE/bug-bash-report.md b/.github/ISSUE_TEMPLATE/bug-bash-report.md new file mode 100644 index 00000000..cd7df885 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-bash-report.md @@ -0,0 +1,24 @@ +--- +name: Bug Bash Report +about: Bugs found in the Nov 10 2021 DCA Bug Bash +title: '' +labels: Bug Bash v1 +assignees: '' + +--- + +**Describe the bug** +- [ ] Server disconnect +- [ ] Wrong manifest +- [ ] Wrong values in manifest columns +- [ ] Other (please describe) + +**To Reproduce** +Center: +Template: + +**Screenshots (optional)** +If applicable, add screenshots to help explain your problem. + +**Additional context (optional)** +Add any other context about the problem here. From 27bdd6efcf684599df85be7b486c9be082ab8ef6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 17:55:05 +0000 Subject: [PATCH 122/260] Bump pip from 20.1.1 to 21.1 Bumps [pip](https://github.com/pypa/pip) from 20.1.1 to 21.1. - [Release notes](https://github.com/pypa/pip/releases) - [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst) - [Commits](https://github.com/pypa/pip/compare/20.1.1...21.1) --- updated-dependencies: - dependency-name: pip dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8c66a917..6e657760 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,7 @@ oauthlib==3.1.0 orderedset==2.0.1 packaging==20.9 pandas==1.2.3 -pip==20.1.1 +pip==21.1 protobuf==3.15.7 pyasn1==0.4.8 pyasn1-modules==0.2.8 From 2cdc3a08e4cd9a18179a3640291b706ff5bf65fb Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 16 Nov 2021 21:46:47 +0000 Subject: [PATCH 123/260] fix folder id not updated issue --- server.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index 906bc078..cd9aabec 100644 --- a/server.R +++ b/server.R @@ -170,7 +170,7 @@ shinyServer(function(input, output, session) { ######## Template Google Sheet Link ######## observeEvent(c(input$dropdown_folder, input$tabs), { - req(input$tabs == "tab_template") + req(input$tabs %in% c("tab_template", "tab_upload")) tmp_folder_synID <- datatype_list$folders[[input$dropdown_folder]] req(tmp_folder_synID != folder_synID()) # if folder changes @@ -259,7 +259,7 @@ shinyServer(function(input, output, session) { ######## Validation Section ####### observeEvent(input$btn_validate, { - + # loading screen for validating metadata dcWaiter("show", msg = "Validating...") From 33809a7107b89524cc809b301436dbd41ad78c7d Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 16 Nov 2021 21:51:30 +0000 Subject: [PATCH 124/260] not initiate updating files in the validation tab --- server.R | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/server.R b/server.R index cd9aabec..f6134637 100644 --- a/server.R +++ b/server.R @@ -174,17 +174,19 @@ shinyServer(function(input, output, session) { tmp_folder_synID <- datatype_list$folders[[input$dropdown_folder]] req(tmp_folder_synID != folder_synID()) # if folder changes - dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) # update selected folder ID folder_synID(tmp_folder_synID) - # get file list in selected folder - file_list <- synapse_driver$getFilesInStorageDataset( - synStore_obj, - folder_synID() - ) - datatype_list$files <<- list2Vector(file_list) - dcWaiter("hide") + if (input$tabs == "tab_template") { + dcWaiter("show", msg = paste0("Getting files in ", input$dropdown_folder, "...")) + # get file list in selected folder + file_list <- synapse_driver$getFilesInStorageDataset( + synStore_obj, + folder_synID() + ) + datatype_list$files <<- list2Vector(file_list) + dcWaiter("hide") + } }) # display warning message if folder is empty and data type is assay From 12dff98cd82dd004199580297fe091da6dd35a64 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 16 Nov 2021 21:57:08 +0000 Subject: [PATCH 125/260] reset input file after submitting --- server.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server.R b/server.R index f6134637..25807df6 100644 --- a/server.R +++ b/server.R @@ -392,11 +392,11 @@ shinyServer(function(input, output, session) { dcWaiter("hide") nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) - # clean up inputfile + # clean up old inputs/results sapply(clean_tags, FUN = hide) + reset("inputFile-file") DTableServer("tbl_preview", data.frame(NULL)) - # TODO: input file not reset yet - # reset(c(clean_tags, "inputFile", "tbl_preview")) if reset works + } else { dcWaiter("update", msg = HTML(paste0( "Uh oh, looks like something went wrong!", From 21a70cadcf2df246f3aae2f74a3cbb9a41eb4f15 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 16 Nov 2021 22:18:12 +0000 Subject: [PATCH 126/260] add redirection on submit success popup box --- server.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server.R b/server.R index 25807df6..e1a04cc2 100644 --- a/server.R +++ b/server.R @@ -386,11 +386,12 @@ shinyServer(function(input, output, session) { synStore_obj, "./tmp/synapse_storage_manifest.csv", folder_synID() ) - manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) + manifest_path <- tags$a(href = paste0("synapse.org/#!Synapse:", manifest_id), manifest_id, target = "_blank") + # if no error if (startsWith(manifest_id, "syn") == TRUE) { dcWaiter("hide") - nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) + nx_report_success("Success!", HTML(paste0("Manifest submitted to: ", manifest_path))) # clean up old inputs/results sapply(clean_tags, FUN = hide) @@ -416,12 +417,12 @@ shinyServer(function(input, output, session) { synStore_obj, "./tmp/synapse_storage_manifest.csv", folder_synID() ) - manifest_path <- paste0("synapse.org/#!Synapse:", manifest_id) + manifest_path <- tags$a(href = paste0("synapse.org/#!Synapse:", manifest_id), manifest_id, target = "_blank") # if uploaded provided valid synID message if (startsWith(manifest_id, "syn") == TRUE) { dcWaiter("hide") - nx_report_success("Success!", paste0("Manifest submitted to: ", manifest_path)) + nx_report_success("Success!", HTML(paste0("Manifest submitted to: ", manifest_path))) # clear inputs sapply(clean_tags, FUN = hide) From 341a9bb64afd265c0f4c351e40f24f1fb806968e Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 17 Nov 2021 16:20:02 +0000 Subject: [PATCH 127/260] add extra validations on initial loading page --- functions/dcWaiter.R | 59 ++++++++++++++++++++++---------- functions/synapse_func_alias.py | 2 +- server.R | 60 +++++++++++++++------------------ ui.R | 2 +- 4 files changed, 71 insertions(+), 52 deletions(-) diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R index 00f90a61..881d0ef8 100644 --- a/functions/dcWaiter.R +++ b/functions/dcWaiter.R @@ -1,12 +1,14 @@ # This is script to wrap up the waiter screen for data curator app # TODO: maybe we could split into UI and server if we need -dcWaiter <- function(stage = c("show", "update", "hide"), - isLogin = FALSE, isPass = TRUE, usrName = NULL, +dcWaiter <- function(stage = c("show", "update", "hide"), landing = FALSE, userName = NULL, + isLogin = TRUE, isCertified = TRUE, isPermission = TRUE, sleep = 2, msg = NULL, spin = NULL) { # validate arguments + if (!is.logical(landing)) stop("landing must be a boolean") if (!is.logical(isLogin)) stop("isLogin must be a boolean") - if (!is.logical(isPass)) stop("isPass must be a boolean") + if (!is.logical(isCertified)) stop("isCertified must be a boolean") + if (!is.logical(isPermission)) stop("isPermission must be a boolean") if (!is.numeric(sleep)) stop("sleep must be a numeric") if (!stage %in% c("show", "update", "hide")) { stop("Please provide a value for stage: 'show', 'update' or 'hide'.") @@ -20,9 +22,9 @@ dcWaiter <- function(stage = c("show", "update", "hide"), return(waiter_hide()) } - # log in screen - if (isLogin) { - # The message on initial loading page are not customizable + # first loading screen of app + if (landing) { + if (stage == "show") { waiter_show_on_load( html = tagList( @@ -31,28 +33,49 @@ dcWaiter <- function(stage = c("show", "update", "hide"), ), color = "#424874" ) - } else if (isPass) { + # } else if (!isLogin) { + # # when user is not login + # waiter_update(html = tagList( + # img(src = "img/synapse_logo.png", height = "120px"), + # h3("Looks like you're not logged in!"), + # span("Please ", + # a("login", href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank"), + # " to Synapse, then refresh this page." + # ) + # )) + } else if (!isCertified) { + # when user is not certified synapse user waiter_update(html = tagList( img(src = "img/synapse_logo.png", height = "120px"), - h3(sprintf("Welcome, %s!", usrName)) + h3("Looks like you're not a certified synapse user!"), + span("Please follow the ", + a("instruction", + href = "https://help.synapse.org/docs/User-Account-Tiers.2007072795.html#UserAccountTiers-CertifiedUsers", + target = "_blank" + ), + " to become a certified user, then refresh this page." + ) + )) + } else if (!isPermission) { + # when user is not certified synapse user + waiter_update(html = tagList( + img(src = "img/synapse_logo.png", height = "120px"), + h3("Looks like you dont have access to fileview"), + span("placeholder ...") )) - Sys.sleep(sleep) - waiter_hide() } else { - # ensure the synapse logo image is stored in www/ + # success loading page; userName needed to provide waiter_update(html = tagList( img(src = "img/synapse_logo.png", height = "120px"), - h3("Looks like you're not logged in!"), span( - "Please ", a("login", - href = "https://www.synapse.org/#!LoginPlace:0", target = "_blank" - ), - " to Synapse, then refresh this page." - ) + h3(sprintf("Welcome, %s!", userName)) )) + Sys.sleep(sleep) + waiter_hide() } + } else { + # other loading screens - if (stage == "show") { waiter_show( html = tagList(spin, br(), h3(msg)), diff --git a/functions/synapse_func_alias.py b/functions/synapse_func_alias.py index eb58d50f..72b5484c 100644 --- a/functions/synapse_func_alias.py +++ b/functions/synapse_func_alias.py @@ -5,4 +5,4 @@ syn_getUserProfile = syn.getUserProfile syn_tableQuery = syn.tableQuery syn_get = syn.get - +syn_is_certified = syn.is_certified diff --git a/server.R b/server.R index e1a04cc2..94834af1 100644 --- a/server.R +++ b/server.R @@ -53,45 +53,41 @@ shinyServer(function(input, output, session) { # synapse cookies session$sendCustomMessage(type = "readCookie", message = list()) - # login page + # initial loading page observeEvent(input$cookie, { - # login and update session; otherwise, notify to login to Synapse first - tryCatch( - { - syn_login(sessionToken = input$cookie, rememberMe = FALSE) - - # welcome message - # output$title <- renderUI({ - # titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) - # }) - - # updating global vars with values for projects - synStore_obj <<- synapse_driver(token = input$cookie) - - # get_projects_list(synStore_obj) - projects_list <- synapse_driver$getStorageProjects(synStore_obj) - datatype_list$projects <<- list2Vector(projects_list) - - # updates project dropdown - lapply(c("header_dropdown_", "dropdown_"), function(x) { - lapply(c(1, 3), function(i) { - updateSelectInput(session, paste0(x, datatypes[i]), - choices = sort(names(datatype_list[[i]])) - ) - }) + # login and update session + syn_login(sessionToken = input$cookie, rememberMe = FALSE) + + # updating syn storage + tryCatch(synStore_obj <<- synapse_driver(token = input$cookie), error = function(e) NULL) + + if (is.null(synStore_obj)) { + message("'synapse_driver' fails, run 'synapse_driver' to see detailed error") + dcWaiter("update", landing = TRUE, isPermission = FALSE) + } else { + projects_list <- synapse_driver$getStorageProjects(synStore_obj) + datatype_list$projects <<- list2Vector(projects_list) + + # updates project dropdown + lapply(c("header_dropdown_", "dropdown_"), function(x) { + lapply(c(1, 3), function(i) { + updateSelectInput(session, paste0(x, datatypes[i]), + choices = sort(names(datatype_list[[i]])) + ) }) + }) + + user_name <- syn_getUserProfile()$userName + if (!syn_is_certified(user_name)) { + dcWaiter("update", landing = TRUE, isCertified = FALSE) + } else { # update waiter loading screen once login successful - dcWaiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) - }, - error = function(err) { - message(err) # write log error - dcWaiter("update", isLogin = TRUE, isPass = FALSE) + dcWaiter("update", landing = TRUE, userName = user_name) } - ) + } }) - ######## Arrow Button ######## lapply(1:3, function(i) { switchTabServer(id = paste0("switchTab", i), tabId = "tabs", tab = reactive(input$tabs)(), tabList = tabs_list, parent = session) diff --git a/ui.R b/ui.R index 1a34a966..46ec9d30 100644 --- a/ui.R +++ b/ui.R @@ -227,7 +227,7 @@ ui <- shinydashboardPlus::dashboardPage( ) ), # waiter loading screen - dcWaiter("show", isLogin = TRUE) + dcWaiter("show", landing = TRUE) ) ) From dc1e1d8a6778ea8604708f4a1e72c7b79357970d Mon Sep 17 00:00:00 2001 From: Yooree Chae Date: Thu, 18 Nov 2021 10:46:40 -0800 Subject: [PATCH 128/260] add bug report issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..5aeec088 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (if applicable, please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. From bbf4b167fca968183811a6a9d60f03abe405c57c Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 22 Nov 2021 15:10:10 +0000 Subject: [PATCH 129/260] update readme --- README.md | 42 +++++++++++++++++++++++------------------- example_config.yaml | 18 +++++++++++------- global.R | 11 ++++++++++- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index c35c0452..e7a66508 100644 --- a/README.md +++ b/README.md @@ -12,32 +12,36 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor ### Data Curator App Setup -1. Clone this repo (front-end) with one single branch (i.e., *shiny-server-main*): +1. Clone this repo (front-end) with one single branch (i.e., _shiny-server-main_): git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -2. Create the configuration file and modify `OAuth Credential` ([how to obtain OAuth](https://github.com/Sage-Bionetworks/data_curator#authentication-oauth)), `App_URL` and `CONDA_ENV_NAME` in the `config.yaml` as needed: +2. Create and modify the configuration file: cp example_config.yaml config.yaml chmod 400 config.yaml -3. Create and activate the conda environment (our conda environment name `data_curator_env` is set by default in the `example_config.yaml`): + - `CLIENT_ID` and `CLIENT_SECRET`: [how to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication) + - `APP_URL`: the redirection url to your app + - `CONDA_NAME`: conda environment name - grep 'CONDA_ENV_NAME:' config.yaml | cut -f2 -d':' | xargs conda env create -f environment.yml -n - conda activate data_curator_env +3. Create and activate the conda environment: -5. Install required R pacakges dependencies: + export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':') + conda env create -f environment.yml -n $CONDA_NAME + conda activate $CONDA_NAME - R -e "renv::consent(provided=TRUE)" - R -e "renv::restore(lockfile='renv.lock')" +4. Install required R pacakges dependencies: + + R -e "renv::restore()" ### Schematic Setup -1. Clone the [schematic] (backend) as a folder `schematic` inside the `data_curator` folder: +1. Clone the [schematic] (backend) as a folder `schematic` inside the `data_curator` folder: git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git -2. Install the latest release of the `schematic` via `pip`: +2. Install the latest release of the `schematic` via `pip`: python -m pip install schematicpy @@ -47,24 +51,24 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor poetry build pip install dist/schematicpy-*-py3-none-any.whl -3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) +3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) ### Data Model Configuration -Use the app configuration file `www/config.json` to adapt this app to your DCC. +Use the app configuration file `www/config.json` to adapt this app to your DCC. -* `manifest schemas`: defines the list of schemas displayed under the "Choose a Metadata Template Type:" dropdown in the application. - * `display_name` : The display name for the dropdown. (e.g. _scRNA-seq Level 1_) - * `schema_name`: The name of the manifest in the JSON-LD schema (e.g. _ScRNA-seqLevel1_) - * `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type _assay_. -* `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) -* `community` : the abbreviated name of the community or project. (e.g. _HTAN_) +- `manifest schemas`: defines the list of schemas displayed under the "Choose a Metadata Template Type:" dropdown in the application. + - `display_name` : The display name for the dropdown. (e.g. _scRNA-seq Level 1_) + - `schema_name`: The name of the manifest in the JSON-LD schema (e.g. _ScRNA-seqLevel1_) + - `type`: The type of manifest. As currently configured in `app.R`, will only display manifests of type _assay_. +- `main_fileview` : The Synapse ID of a fileview that is scoped to all files, folders, & projects in your community. (e.g. _syn20446927_) +- `community` : the abbreviated name of the community or project. (e.g. _HTAN_) --- ## Authentication -This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `client_id` and `client_secret` make sure to add it to the configuration yaml file. +This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `CLIENT_ID` and `CLIENT_SECRET` make sure to add it to the configuration yaml file. --- diff --git a/example_config.yaml b/example_config.yaml index 224496d2..f65601e5 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -1,7 +1,11 @@ -# This file contains the oauth client id and secret required for -# the application. This file needs to have chmod 400 permissions -# client_id and APP_URL has to be a string -CLIENT_ID: -CLIENT_SECRET: -APP_URL: "https://shinypro.synapse.org/users/rchai/dc/" -CONDA_ENV_NAME: "data_curator_env" +# This file needs to have chmod 400 permissions + +# oauth client id and secret required for the application. +CLIENT_ID: '' +CLIENT_SECRET: '' + +# for local testing, the default port 8100 is used: http://localhost:8100/ +# change port based on your OAuth Client's redirect_uri +APP_URL: '' +# change the conda environment name here, this must be the last line +CONDA_NAME: 'data_curator_env' diff --git a/global.R b/global.R index 0252cc34..2abffceb 100644 --- a/global.R +++ b/global.R @@ -33,7 +33,16 @@ oauth_client <- yaml.load_file("config.yaml") client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) -app_url <- toString(oauth_client$APP_URL) + +if (interactive()) { + # for local development + options(shiny.port = 8100) + app_url <- "http://localhost:8100/" +} else { + # deployed url + app_url <- toString(oauth_client$APP_URL) +} + conda_name <- toString(oauth_client$CONDA_ENV_NAME) if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") From 2de40b86856169a63ed93c04b46d981914bd5b83 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 22 Nov 2021 15:20:33 +0000 Subject: [PATCH 130/260] remove hash in environment.yml --- environment.yml | 66 +++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/environment.yml b/environment.yml index 1dbe832b..f9d46597 100644 --- a/environment.yml +++ b/environment.yml @@ -1,47 +1,43 @@ channels: - defaults dependencies: - - _libgcc_mutex=0.1=main + - _libgcc_mutex=0.1 - ca-certificates=2020.6.24=0 - - cairo=1.14.12=h7636065_2 + - cairo=1.14.12 - certifi=2020.6.20=py37_0 - - expat=2.2.9=he6710b0_2 - - fontconfig=2.12.6=h49f89f6_0 - - freetype=2.8=hab7d2ae_1 - - fribidi=1.0.9=h7b6447c_0 - - glib=2.65.0=h3eb4bd4_0 - - graphite2=1.3.14=h23475e2_0 - - graphviz=2.40.1=h25d223c_0 - - harfbuzz=1.7.6=h5f0a787_1 - - icu=58.2=he6710b0_3 - - jpeg=9b=h024ee3a_2 - - ld_impl_linux-64=2.33.1=h53a641e_7 - - libedit=3.1.20191231=h7b6447c_0 - - libffi=3.3=he6710b0_2 - - libgcc-ng=9.1.0=hdf63c60_0 - - libpng=1.6.37=hbc83047_0 - - libstdcxx-ng=9.1.0=hdf63c60_0 - - libtiff=4.1.0=h2733197_1 - - libtool=2.4.6=h7b6447c_5 - - libxcb=1.14=h7b6447c_0 - - libxml2=2.9.10=he19cac6_1 - - lz4-c=1.9.2=he6710b0_0 - - ncurses=6.2=he6710b0_1 - - openssl=1.1.1g=h7b6447c_0 - - pango=1.42.0=h377f3fa_0 - - pcre=8.44=he6710b0_0 + - expat=2.2.9 + - fontconfig=2.12.6 + - freetype=2.8 + - fribidi=1.0.9 + - glib=2.65.0 + - graphite2=1.3.14 + - graphviz=2.40.1 + - harfbuzz=1.7.6 + - icu=58.2 + - jpeg=9b + - libedit=3.1.20191231 + - libffi=3.3 + - libpng=1.6.37 + - libtiff=4.1.0 + - libtool=2.4.6 + - libxml2=2.9.10 + - lz4-c=1.9.2 + - ncurses=6.2 + - openssl=1.1.1g + - pango=1.42.0 + - pcre=8.44 - pip=20.1.1=py37_1 - - pixman=0.40.0=h7b6447c_0 - - python=3.7.7=hcff3b4d_5 + - pixman=0.40.0 + - python=3.7.7 - python-graphviz=0.8.4=py37_1 - - readline=8.0=h7b6447c_0 + - readline=8.0 - setuptools=47.3.1=py37_0 - - sqlite=3.32.3=h62c20be_0 - - tk=8.6.10=hbc83047_0 + - sqlite=3.32.3 + - tk=8.6.10 - wheel=0.34.2=py37_0 - - xz=5.2.5=h7b6447c_0 - - zlib=1.2.11=h7b6447c_3 - - zstd=1.4.5=h0b5b093_0 + - xz=5.2.5 + - zlib=1.2.11 + - zstd=1.4.5 - pip: - attrs==19.3.0 - cachetools==4.1.1 From 6d5282a4c580a78cff789aa0a7a92e312cc4373d Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 22 Nov 2021 15:46:10 +0000 Subject: [PATCH 131/260] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7a66508..326734cf 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 3. Create and activate the conda environment: - export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':') + export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''"') conda env create -f environment.yml -n $CONDA_NAME conda activate $CONDA_NAME From 1ee077c7bb32b2ef55b2390bcfe6dfe836bbf318 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 22 Nov 2021 15:49:03 +0000 Subject: [PATCH 132/260] update renv --- init_python_venv.sh | 20 --- renv.lock | 182 +++++++++--------------- renv/activate.R | 340 ++++++++++++++++++++++++++++++++++---------- renv/settings.dcf | 3 +- 4 files changed, 336 insertions(+), 209 deletions(-) delete mode 100644 init_python_venv.sh diff --git a/init_python_venv.sh b/init_python_venv.sh deleted file mode 100644 index 67250c5f..00000000 --- a/init_python_venv.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# a sample initialization of a virtualenv for use with -# this project. a local virtualenv is created, the python -# dependencies are installed into it, and an environment -# variable is set to hint reticulate to use this virtualenv. - -# this assumes that a python3 command is available on the path -# with a python version >= 3.6 - -# Sample usage: -# $source init_python_venv.sh - -python3 -m venv venv -source venv/bin/activate - -pip install -r requirements.txt - -export RETICULATE_PYTHON=venv/bin/python - diff --git a/renv.lock b/renv.lock index 9804e4f4..abd0fcd5 100644 --- a/renv.lock +++ b/renv.lock @@ -22,10 +22,10 @@ }, "DT": { "Package": "DT", - "Version": "0.14", + "Version": "0.18", "Source": "Repository", "Repository": "CRAN", - "Hash": "a3580ce0309c94d061c23b0afb4accbd" + "Hash": "a7d6660c869d4f41f856504828af4645" }, "MASS": { "Package": "MASS", @@ -41,34 +41,6 @@ "Repository": "CRAN", "Hash": "08588806cba69f04797dab50627428ed" }, - "R.cache": { - "Package": "R.cache", - "Version": "0.15.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e92a8ea8388c47c82ed8aa435ed3be50" - }, - "R.methodsS3": { - "Package": "R.methodsS3", - "Version": "1.8.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bf6453323755202d5909697b6f7c109" - }, - "R.oo": { - "Package": "R.oo", - "Version": "1.24.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5709328352717e2f0a9c012be8a97554" - }, - "R.utils": { - "Package": "R.utils", - "Version": "2.10.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a9e316277ff12a43997266f2f6567780" - }, "R6": { "Package": "R6", "Version": "2.4.1", @@ -118,6 +90,20 @@ "Repository": "CRAN", "Hash": "543776ae6848fde2f48ff3816d0628bc" }, + "bslib": { + "Package": "bslib", + "Version": "0.2.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "4830a372b241d78ed6f53731ee3023ac" + }, + "cachem": { + "Package": "cachem", + "Version": "1.0.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2703a46dcabfb902f10060b2bca9f708" + }, "callr": { "Package": "callr", "Version": "3.4.3", @@ -153,13 +139,6 @@ "Repository": "CRAN", "Hash": "0f22be39ec1d141fd03683c06f3a6e67" }, - "cpp11": { - "Package": "cpp11", - "Version": "0.2.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "730eebcc741a5c36761f7d4d0f5e37b8" - }, "crayon": { "Package": "crayon", "Version": "1.3.4", @@ -204,10 +183,10 @@ }, "dplyr": { "Package": "dplyr", - "Version": "1.0.0", + "Version": "1.0.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "4011f62581a34080e44105d4aa05a97f" + "Hash": "d0d76c11ec807eb3f000eba4e3eb0f68" }, "ellipsis": { "Package": "ellipsis", @@ -253,10 +232,10 @@ }, "fs": { "Package": "fs", - "Version": "1.4.2", + "Version": "1.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "8c04112383ca1988e96f429255f95675" + "Hash": "44594a07a42e5f91fac9f93fda6d0109" }, "generics": { "Package": "generics", @@ -267,10 +246,10 @@ }, "ggplot2": { "Package": "ggplot2", - "Version": "3.3.2", + "Version": "3.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "4ded8b439797f7b1693bd3d238d0106b" + "Hash": "3eb6477d01eb5bbdc03f7d5f70f2733e" }, "glue": { "Package": "glue", @@ -286,13 +265,6 @@ "Repository": "CRAN", "Hash": "ac5c6baf7822ce8732b343f14c072c4d" }, - "hexbin": { - "Package": "hexbin", - "Version": "1.28.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3d59212f2814d65dff517e6899813c58" - }, "hms": { "Package": "hms", "Version": "0.5.3", @@ -302,22 +274,17 @@ }, "htmltools": { "Package": "htmltools", - "Version": "0.5.0", + "Version": "0.5.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "7d651b7131794fe007b1ad6f21aaa401" + "Hash": "af2c2531e55df5cf230c4b5444fc973c" }, "htmlwidgets": { "Package": "htmlwidgets", - "Version": "1.5.1.9001", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "htmlwidgets", - "RemoteUsername": "ramnathv", - "RemoteRef": "master", - "RemoteSha": "6fcc4b03ed3fc42be76d4e43d863db3d85c8babb", - "Hash": "43198daf611c2422a3969bf1f02213b4" + "Version": "1.5.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "6fdaa86d0700f8b3e92ee3c445a5a10d" }, "httpuv": { "Package": "httpuv", @@ -340,12 +307,19 @@ "Repository": "CRAN", "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" }, + "jquerylib": { + "Package": "jquerylib", + "Version": "0.1.4", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "5aab57a3bd297eee1c1d862735972182" + }, "jsonlite": { "Package": "jsonlite", - "Version": "1.7.0", + "Version": "1.7.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "2657f20b9a74c996c602e74ebe540b06" + "Hash": "98138e0994d41508c7a6b84a0600cfcb" }, "labeling": { "Package": "labeling", @@ -377,10 +351,10 @@ }, "lifecycle": { "Package": "lifecycle", - "Version": "0.2.0", + "Version": "1.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "361811f31f71f8a617a9a68bf63f1f42" + "Hash": "3471fb65971f1a7b2d4ae7848cf2db8d" }, "magrittr": { "Package": "magrittr", @@ -454,16 +428,17 @@ }, "plotly": { "Package": "plotly", - "Version": "4.9.2.9000", - "Source": "GitHub", - "RemoteType": "github", - "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", - "RemoteHost": "api.github.com", - "RemoteRepo": "plotly", - "RemoteUsername": "ropensci", - "RemoteRef": "master", - "RemoteSha": "1d1eddda377685cf900ed4a7b16e7796a24b8fe4", - "Hash": "d2858de9ced9d164806a7aa2eebb8b2c" + "Version": "4.9.3", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "f6b85d9e4ed88074ea0ede1aa74bb00e" + }, + "png": { + "Package": "png", + "Version": "0.1-7", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "03b7076c234cb3331288919983326c55" }, "praise": { "Package": "praise", @@ -516,17 +491,10 @@ }, "readr": { "Package": "readr", - "Version": "1.4.0", + "Version": "1.3.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "2639976851f71f330264a9c9c3d43a61" - }, - "rematch2": { - "Package": "rematch2", - "Version": "2.1.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "76c9e04c712a05848ae7a23d2f170a40" + "Hash": "af8ab99cd936773a148963905736907b" }, "renv": { "Package": "renv", @@ -542,10 +510,10 @@ }, "reticulate": { "Package": "reticulate", - "Version": "1.16", + "Version": "1.19", "Source": "Repository", "Repository": "CRAN", - "Hash": "5db95d35ae4605b46cea66b6e3bcab3e" + "Hash": "a793719f1b17126b503feef01ce63410" }, "rjson": { "Package": "rjson", @@ -556,10 +524,10 @@ }, "rlang": { "Package": "rlang", - "Version": "0.4.7", + "Version": "0.4.10", "Source": "Repository", "Repository": "CRAN", - "Hash": "c06d2a6887f4b414f8e927afd9ee976a" + "Hash": "599df23c40a4fce9c7b4764f28c37857" }, "rprojroot": { "Package": "rprojroot", @@ -577,10 +545,10 @@ }, "sass": { "Package": "sass", - "Version": "0.2.0", + "Version": "0.3.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "441417bbd40d5bbd07561cc40fb182ed" + "Hash": "3ef1adfe46b7b144b970d74ce33ab0d6" }, "scales": { "Package": "scales", @@ -591,10 +559,10 @@ }, "shiny": { "Package": "shiny", - "Version": "1.5.0", + "Version": "1.6.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "ee4ed72d7a5047d9e73cf922ad66e9c9" + "Hash": "6e3b6ae7fe02b5859e4bb277f218b8ae" }, "shinydashboard": { "Package": "shinydashboard", @@ -612,10 +580,10 @@ }, "shinyjs": { "Package": "shinyjs", - "Version": "1.1", + "Version": "2.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "b40a5207b6624f6e2b8cdb50689cdb69" + "Hash": "9ddfc91d4280eaa34c2103951538976f" }, "shinypop": { "Package": "shinypop", @@ -631,10 +599,10 @@ }, "shinythemes": { "Package": "shinythemes", - "Version": "1.1.2", + "Version": "1.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "8f047210d7d68ea4860a3c0d8cced272" + "Hash": "30f0ebc41feba25691073626ff5e2cf4" }, "sourcetools": { "Package": "sourcetools", @@ -657,13 +625,6 @@ "Repository": "CRAN", "Hash": "0759e6b6c0957edb1311028a49a35e76" }, - "styler": { - "Package": "styler", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2ec6308547ffe73208cef3ef3766fc33" - }, "sys": { "Package": "sys", "Version": "3.3", @@ -708,10 +669,10 @@ }, "vctrs": { "Package": "vctrs", - "Version": "0.3.1", + "Version": "0.3.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "1739235995f08583db4095a28c357207" + "Hash": "5cf1957f93076c19fdc81d01409d240b" }, "viridisLite": { "Package": "viridisLite", @@ -722,10 +683,10 @@ }, "waiter": { "Package": "waiter", - "Version": "0.1.3", + "Version": "0.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "7bfebcea9f02aa9b2821fb4f529031e6" + "Hash": "58bd688fb765cf778b633df0e2502003" }, "withr": { "Package": "withr", @@ -734,13 +695,6 @@ "Repository": "CRAN", "Hash": "ecd17882a0b4419545691e095b74ee89" }, - "xfun": { - "Package": "xfun", - "Version": "0.15", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ddeca7650052ff9131ac7c41a9a77b3b" - }, "xtable": { "Package": "xtable", "Version": "1.8-4", diff --git a/renv/activate.R b/renv/activate.R index 924c2d38..4184f5ff 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,7 +2,10 @@ local({ # the requested version of renv - version <- "0.8.2" + version <- "0.11.0-3" + + # the project directory + project <- getwd() # avoid recursion if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) @@ -33,45 +36,132 @@ local({ } - # construct path to renv in library - libpath <- local({ - - root <- Sys.getenv("RENV_PATHS_LIBRARY", unset = "renv/library") - prefix <- paste("R", getRversion()[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - file.path(root, prefix, R.version$platform) - - }) - - # try to load renv from the project library - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(renv::load()) - - # failed to find renv locally; we'll try to install from GitHub. - # first, set up download options as appropriate (try to use GITHUB_PAT) - install_renv <- function() { - - message("Failed to find installation of renv -- attempting to bootstrap...") - - # ensure .Rprofile doesn't get executed - rpu <- Sys.getenv("R_PROFILE_USER", unset = NA) - Sys.setenv(R_PROFILE_USER = "") - on.exit({ - if (is.na(rpu)) - Sys.unsetenv("R_PROFILE_USER") - else - Sys.setenv(R_PROFILE_USER = rpu) - }, add = TRUE) - + # load bootstrap tools + bootstrap <- function(version, library) { + + # read repos (respecting override if set) + repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) + if (is.na(repos)) + repos <- getOption("repos") + + # fix up repos + on.exit(options(repos = repos), add = TRUE) + repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" + options(repos = repos) + + # attempt to download renv + tarball <- tryCatch(renv_bootstrap_download(version), error = identity) + if (inherits(tarball, "error")) + stop("failed to download renv ", version) + + # now attempt to install + status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) + if (inherits(status, "error")) + stop("failed to install renv ", version) + + } + + renv_bootstrap_download_impl <- function(url, destfile) { + + mode <- "wb" + + # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 + fixup <- + Sys.info()[["sysname"]] == "Windows" && + substring(url, 1L, 5L) == "file:" + + if (fixup) + mode <- "w+b" + + download.file( + url = url, + destfile = destfile, + mode = mode, + quiet = TRUE + ) + + } + + renv_bootstrap_download <- function(version) { + + methods <- list( + renv_bootstrap_download_cran_latest, + renv_bootstrap_download_cran_archive, + renv_bootstrap_download_github + ) + + for (method in methods) { + path <- tryCatch(method(version), error = identity) + if (is.character(path) && file.exists(path)) + return(path) + } + + stop("failed to download renv ", version) + + } + + renv_bootstrap_download_cran_latest <- function(version) { + + # check for renv on CRAN matching this version + db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) + + entry <- db[db$Package %in% "renv" & db$Version %in% version, ] + if (nrow(entry) == 0) { + fmt <- "renv %s is not available from your declared package repositories" + stop(sprintf(fmt, version)) + } + + message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE) + + info <- tryCatch( + download.packages("renv", destdir = tempdir()), + condition = identity + ) + + if (inherits(info, "condition")) { + message("FAILED") + return(FALSE) + } + + message("OK") + info[1, 2] + + } + + renv_bootstrap_download_cran_archive <- function(version) { + + name <- sprintf("renv_%s.tar.gz", version) + repos <- getOption("repos") + urls <- file.path(repos, "src/contrib/Archive/renv", name) + destfile <- file.path(tempdir(), name) + + message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE) + + for (url in urls) { + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (identical(status, 0L)) { + message("OK") + return(destfile) + } + + } + + message("FAILED") + return(FALSE) + + } + + renv_bootstrap_download_github <- function(version) { + + enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") + if (!identical(enabled, "TRUE")) + return(FALSE) + # prepare download options pat <- Sys.getenv("GITHUB_PAT") if (nzchar(Sys.which("curl")) && nzchar(pat)) { @@ -87,58 +177,160 @@ local({ options(download.file.method = "wget", download.file.extra = extra) on.exit(do.call(base::options, saved), add = TRUE) } - - # fix up repos - repos <- getOption("repos") - on.exit(options(repos = repos), add = TRUE) - repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" - options(repos = repos) - - # check for renv on CRAN matching this version - db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) - if ("renv" %in% rownames(db)) { - entry <- db["renv", ] - if (identical(entry$Version, version)) { - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - utils::install.packages("renv", lib = libpath, quiet = TRUE) - message("Done!") - return(TRUE) - } + + message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) + + url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) + name <- sprintf("renv_%s.tar.gz", version) + destfile <- file.path(tempdir(), name) + + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), + condition = identity + ) + + if (!identical(status, 0L)) { + message("FAILED") + return(FALSE) } - - # try to download renv - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - prefix <- "https://api.github.com" - url <- file.path(prefix, "repos/rstudio/renv/tarball", version) - destfile <- tempfile("renv-", fileext = ".tar.gz") - on.exit(unlink(destfile), add = TRUE) - utils::download.file(url, destfile = destfile, mode = "wb", quiet = TRUE) + message("Done!") - + return(destfile) + + } + + renv_bootstrap_install <- function(version, tarball, library) { + # attempt to install it into project library message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - + dir.create(library, showWarnings = FALSE, recursive = TRUE) + # invoke using system2 so we can capture and report output bin <- R.home("bin") exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" r <- file.path(bin, exe) - args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(libpath), shQuote(destfile)) + args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball)) output <- system2(r, args, stdout = TRUE, stderr = TRUE) message("Done!") - + # check for successful install status <- attr(output, "status") if (is.numeric(status) && !identical(status, 0L)) { - text <- c("Error installing renv", "=====================", output) + header <- "Error installing renv:" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- c(header, lines, output) writeLines(text, con = stderr()) } + + status + + } + + renv_bootstrap_prefix <- function() { + + # construct version prefix + version <- paste(R.version$major, R.version$minor, sep = ".") + prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") + + # include SVN revision for development versions of R + # (to avoid sharing platform-specific artefacts with released versions of R) + devel <- + identical(R.version[["status"]], "Under development (unstable)") || + identical(R.version[["nickname"]], "Unsuffered Consequences") + + if (devel) + prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") + + # build list of path components + components <- c(prefix, R.version$platform) + + # include prefix if provided by user + prefix <- Sys.getenv("RENV_PATHS_PREFIX") + if (nzchar(prefix)) + components <- c(prefix, components) + + # build prefix + paste(components, collapse = "/") + + } + + renv_bootstrap_library_root <- function(project) { + + path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) + if (!is.na(path)) + return(path) + + path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) + if (!is.na(path)) + return(file.path(path, basename(project))) + + file.path(project, "renv/library") + + } + + renv_bootstrap_validate_version <- function(version) { + + loadedversion <- utils::packageDescription("renv", fields = "Version") + if (version == loadedversion) + return(TRUE) + + # assume four-component versions are from GitHub; three-component + # versions are from CRAN + components <- strsplit(loadedversion, "[.-]")[[1]] + remote <- if (length(components) == 4L) + paste("rstudio/renv", loadedversion, sep = "@") + else + paste("renv", loadedversion, sep = "@") + + fmt <- paste( + "renv %1$s was loaded from project library, but renv %2$s is recorded in lockfile.", + "Use `renv::record(\"%3$s\")` to record this version in the lockfile.", + "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", + sep = "\n" + ) + + msg <- sprintf(fmt, loadedversion, version, remote) + warning(msg, call. = FALSE) + + FALSE + + } + + renv_bootstrap_load <- function(project, libpath, version) { + + # try to load renv from the project library + if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) + return(FALSE) + + # warn if the version of renv loaded does not match + renv_bootstrap_validate_version(version) + + # load the project + renv::load(project) + + TRUE + + } + # construct path to library root + root <- renv_bootstrap_library_root(project) - } + # construct library prefix for platform + prefix <- renv_bootstrap_prefix() + + # construct full libpath + libpath <- file.path(root, prefix) + + # attempt to load + if (renv_bootstrap_load(project, libpath, version)) + return(TRUE) + + # load failed; attempt to bootstrap + bootstrap(version, libpath) - try(install_renv()) + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) # try again to load if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { diff --git a/renv/settings.dcf b/renv/settings.dcf index d04fb5e1..11a53eaf 100644 --- a/renv/settings.dcf +++ b/renv/settings.dcf @@ -1,5 +1,6 @@ external.libraries: ignored.packages: -snapshot.type: packrat +package.dependency.fields: Imports, Depends, LinkingTo +snapshot.type: implicit use.cache: TRUE vcs.ignore.library: TRUE From 2465b9445d37e6d5a086409293bad5dc7a046c30 Mon Sep 17 00:00:00 2001 From: rrchai Date: Mon, 22 Nov 2021 15:50:05 +0000 Subject: [PATCH 133/260] update .gitignore --- .gitignore | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 2457b636..817ca7a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .RData .Rhistory .Rproj.user/ +.DS_Store HTAN_test_shiny.Rproj app.bak.R get_manifest_anno.R @@ -11,12 +12,9 @@ www/getdata.js www/message-handler.js tmp/synapse_storage_manifest.csv .Rproj.user -schematic/schema_explorer/__pycache__/* -schematic/__pycache__/* -schematic/.DS_Store -schematic/credentials.json -schematic/token.pickle -credentials.json -token.pickle +schematic/ +**/credentials.json +**/schematic_service_account_creds.json +**/token.pickle **/__pycache__ config.yaml \ No newline at end of file From 05fcb42542b0fa761afb9e7255e219854077d556 Mon Sep 17 00:00:00 2001 From: Rongrong Chai <73901500+rrchai@users.noreply.github.com> Date: Mon, 22 Nov 2021 10:51:53 -0500 Subject: [PATCH 134/260] Update dcWaiter.R correct words --- functions/dcWaiter.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R index 881d0ef8..ffb29622 100644 --- a/functions/dcWaiter.R +++ b/functions/dcWaiter.R @@ -47,7 +47,7 @@ dcWaiter <- function(stage = c("show", "update", "hide"), landing = FALSE, userN # when user is not certified synapse user waiter_update(html = tagList( img(src = "img/synapse_logo.png", height = "120px"), - h3("Looks like you're not a certified synapse user!"), + h3("Looks like you're not a synapse certified user!"), span("Please follow the ", a("instruction", href = "https://help.synapse.org/docs/User-Account-Tiers.2007072795.html#UserAccountTiers-CertifiedUsers", From 9f1b8100eff41b5221f6b15bfc5bd38b1386a931 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 24 Nov 2021 23:43:59 +0000 Subject: [PATCH 135/260] remove localhost url --- global.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/global.R b/global.R index 2abffceb..52d805d1 100644 --- a/global.R +++ b/global.R @@ -36,10 +36,9 @@ client_secret <- toString(oauth_client$CLIENT_SECRET) if (interactive()) { # for local development + # change port number associated with your client, here options(shiny.port = 8100) - app_url <- "http://localhost:8100/" } else { - # deployed url app_url <- toString(oauth_client$APP_URL) } From 225b060c025d02c850046ad00d2757731abe9461 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 24 Nov 2021 23:45:17 +0000 Subject: [PATCH 136/260] fix typo on conda name --- global.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.R b/global.R index 52d805d1..01c2e9cf 100644 --- a/global.R +++ b/global.R @@ -42,12 +42,12 @@ if (interactive()) { app_url <- toString(oauth_client$APP_URL) } -conda_name <- toString(oauth_client$CONDA_ENV_NAME) +conda_name <- toString(oauth_client$CONDA_ENV) if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") if (is.null(app_url)) stop("config.yaml is missing APP_URL") -if (is.null(conda_name)) stop("config.yaml is missing CONDA_ENV_NAME") +if (is.null(conda_name)) stop("config.yaml is missing CONDA_ENV") app <- oauth_app("shinysynapse", key = client_id, From bfbbe761d091c30f1034562a1f5b65881d3de767 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 24 Nov 2021 23:46:18 +0000 Subject: [PATCH 137/260] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 326734cf..2bede3ac 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 3. Create and activate the conda environment: - export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''"') + export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''" ') conda env create -f environment.yml -n $CONDA_NAME conda activate $CONDA_NAME From abd31b552604986556693be3b939768ee059b761 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 2 Dec 2021 17:46:56 +0000 Subject: [PATCH 138/260] update message when no access to fileview --- functions/dcWaiter.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R index ffb29622..6daadda5 100644 --- a/functions/dcWaiter.R +++ b/functions/dcWaiter.R @@ -60,8 +60,9 @@ dcWaiter <- function(stage = c("show", "update", "hide"), landing = FALSE, userN # when user is not certified synapse user waiter_update(html = tagList( img(src = "img/synapse_logo.png", height = "120px"), - h3("Looks like you dont have access to fileview"), - span("placeholder ...") + h3("Fileview access denied!"), + span("You may not have sufficient permissions for curation. + Please contact your team and project administrators.") )) } else { # success loading page; userName needed to provide From 4fa32165a26c5739918f00f43f11dd960321e65a Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 2 Dec 2021 17:48:18 +0000 Subject: [PATCH 139/260] changeemessage to titlecase --- functions/dcWaiter.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/dcWaiter.R b/functions/dcWaiter.R index 6daadda5..938da9e0 100644 --- a/functions/dcWaiter.R +++ b/functions/dcWaiter.R @@ -60,7 +60,7 @@ dcWaiter <- function(stage = c("show", "update", "hide"), landing = FALSE, userN # when user is not certified synapse user waiter_update(html = tagList( img(src = "img/synapse_logo.png", height = "120px"), - h3("Fileview access denied!"), + h3("Fileview Access Denied!"), span("You may not have sufficient permissions for curation. Please contact your team and project administrators.") )) From 83f1abc395c5456008db93e53fade2f136b38359 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Fri, 10 Dec 2021 23:52:41 +0000 Subject: [PATCH 140/260] Use virtualenv instead of conda environment. --- .Rprofile | 3 ++- global.R | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.Rprofile b/.Rprofile index 407da0f4..ae148566 100644 --- a/.Rprofile +++ b/.Rprofile @@ -8,4 +8,5 @@ } options(stringsAsFactors = FALSE) -source("renv/activate.R") +#source("renv/activate.R") +Sys.setenv("RETICULATE_PYTHON" = "env/bin/python") diff --git a/global.R b/global.R index 2abffceb..10e0166a 100644 --- a/global.R +++ b/global.R @@ -43,7 +43,7 @@ if (interactive()) { app_url <- toString(oauth_client$APP_URL) } -conda_name <- toString(oauth_client$CONDA_ENV_NAME) +conda_name <- toString(oauth_client$CONDA_NAME) if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") @@ -87,7 +87,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv(conda_name) +reticulate::use_virtualenv(conda_name) # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) From e727631a3b3931802539364fe5317def74327d33 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Sat, 11 Dec 2021 00:09:41 +0000 Subject: [PATCH 141/260] Update setup instructions for using virtualenv --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 326734cf..042f2c96 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,19 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor - `APP_URL`: the redirection url to your app - `CONDA_NAME`: conda environment name -3. Create and activate the conda environment: +3. Create and activate the conda environment or virtualenv: export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''"') conda env create -f environment.yml -n $CONDA_NAME conda activate $CONDA_NAME -4. Install required R pacakges dependencies: + Or if using virtualenv + + export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''"') + python -m venv $CONDA_NAME + source "$CONDA_NAME"/bin/activate + +4. Install required R pacakges dependencies. SKIP THIS IF NOT USING A CONDA ENVIRONMENT: R -e "renv::restore()" @@ -53,6 +59,10 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) +4. If not using a conda environment. Install the required dependencies. + + pip install -r requirements.txt + ### Data Model Configuration Use the app configuration file `www/config.json` to adapt this app to your DCC. From 7ea6cfb578d27ec5f8403fb493660467a9c6985d Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 14 Dec 2021 00:34:28 +0000 Subject: [PATCH 142/260] modify functions to adapt regex validation rules --- functions/validationResult.R | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index 23a68679..c621151d 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -59,34 +59,33 @@ validationResult <- function(valRes, template, inFile) { ) } - errorDT <- data.frame( - Row = sapply(valRes, function(i) i[[1]]), - Column = sapply(valRes, function(i) i[[2]]), - Value = sapply(valRes, function(i) i[[4]][[1]]), - Error = sapply(valRes, function(i) i[[3]]) - ) + errorDT <- lapply(valRes, function(i) { + error_row <- i[[1]] + error_col <- i[[2]] + error_val <- inFile[as.numeric(error_row) - 1, error_col] + tibble( + Row = error_row, + Column = error_col, + Value = error_val, + Error = i[[3]] + ) %>% mutate(across(everything(), as.character)) + }) %>% bind_rows() # collapse similiar errors into one row errorDT <- errorDT %>% - mutate(Options = gsub("^'.*?'(.*)", "\\1", Error)) %>% - group_by(Column, Options) %>% + mutate(Error = gsub(".*(not .*)[[:punct:]]", "\\1", Error)) %>% + group_by(Column, Error) %>% summarise( - n = n_distinct(Value), Row = str_c(unique(Row), collapse = ", ") %>% TruncateEllipsis(10, ", "), Value = str_c(unique(Value), collapse = ", ") %>% TruncateEllipsis(10, ", "), .groups = "drop" ) %>% - mutate( - Options = ifelse(n > 1, str_replace(Options, "^ is", " are"), Options), - Error = str_c(sQuote(Value), Options) - ) %>% ungroup() %>% dplyr::select(Row, Column, Value, Error) # sort rows based on input column names errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] - # TODO: to reduce parameter, sort just based on alphabetic - # errorDT <- errorDT[order(errorDT$Column),] + } else { validation_res <- "valid" errorType <- "No Error" From 452b17da39bdb25be504168145e866b216b8558b Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Tue, 14 Dec 2021 00:35:24 +0000 Subject: [PATCH 143/260] Update python requirements and use R package installation script in lieu of renv --- install-pkgs.R | 25 ++++++++++ requirements.txt | 122 +++++++++++++++++++++++------------------------ 2 files changed, 86 insertions(+), 61 deletions(-) create mode 100644 install-pkgs.R diff --git a/install-pkgs.R b/install-pkgs.R new file mode 100644 index 00000000..85e633bc --- /dev/null +++ b/install-pkgs.R @@ -0,0 +1,25 @@ +cran <- c("shiny", +"httr", +"rjson", +"yaml", +"shinyjs", +"dplyr", +"shinythemes", +"shinydashboard", +"stringr", +"DT", +"jsonlite", +"reticulate", +"ggplot2", +"purrr", +"plotly", +"shinydashboardPlus", +"waiter", +"readr", +"sass", +"remotes") + +gh <- "dreamRs/shinypop" + +install.packages(cran) +remotes::install_github(gh) diff --git a/requirements.txt b/requirements.txt index 6e657760..9b067224 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,61 +1,61 @@ -attrs==19.3.0 -cachetools==4.1.1 -certifi==2020.6.20 -cffi==1.14.0 -chardet==3.0.4 -click==7.1.2 -click-log==0.3.2 -cryptography==3.3.2 -decorator==4.4.2 -Deprecated==1.2.4 -entrypoints==0.3 -fastjsonschema==2.14.4 -google-api-core==1.26.3 -google-api-python-client==1.12.8 -google-auth==1.19.1 -google-auth-httplib2==0.0.4 -google-auth-oauthlib==0.4.4 -googleapis-common-protos==1.53.0 -graphviz==0.16 -httplib2==0.19.0 -idna==2.10 -importlib-metadata==1.7.0 -inflection==0.5.1 -isodate==0.6.0 -jsonschema==3.2.0 -keyring==12.0.2 -keyrings.alt==3.1 -networkx==2.5.1 -numpy==1.19.0 -oauth2client==3.0.0 -oauthlib==3.1.0 -orderedset==2.0.1 -packaging==20.9 -pandas==1.2.3 -pip==21.1 -protobuf==3.15.7 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -pycparser==2.20 -pygsheets==2.0.5 -pyparsing==2.4.7 -pyrsistent==0.16.0 -python-dateutil==2.8.1 -pytz==2020.1 -PyYAML==5.4.1 -rdflib==5.0.0 -requests==2.24.0 -requests-oauthlib==1.3.0 -rsa==4.7 -schematicpy==0.1.13 -SecretStorage==2.3.1 -setuptools==52.0.0 -six==1.15.0 -synapseclient==2.3.0 -tabletext==0.1 -toml==0.10.2 -uritemplate==3.0.1 -urllib3==1.26.5 -wheel==0.34.2 -wrapt==1.12.1 -zipp==3.1.0 +attrs>=19.3.0 +cachetools>=4.1.1 +certifi>=2020.6.20 +cffi>=1.14.0 +chardet>=3.0.4 +click>=7.1.2 +click-log>=0.3.2 +cryptography>=3.3.2 +decorator>=4.4.2 +Deprecated>=1.2.4 +entrypoints>=0.3 +fastjsonschema>=2.14.4 +google-api-core>=1.26.3 +google-api-python-client>=1.12.8 +google-auth>=1.19.1 +google-auth-httplib2>=0.0.4 +google-auth-oauthlib>=0.4.4 +googleapis-common-protos>=1.53.0 +graphviz>=0.16 +httplib2>=0.19.0 +idna>=2.10 +importlib-metadata>=1.7.0 +inflection>=0.5.1 +isodate>=0.6.0 +jsonschema>=3.2.0 +keyring>=12.0.2 +keyrings.alt>=3.1 +networkx>=2.5.1 +numpy>=1.19.0 +oauth2client>=3.0.0 +oauthlib>=3.1.0 +orderedset>=2.0.1 +packaging>=20.9 +pandas>=1.2.3 +pip>=21.1 +protobuf>=3.15.7 +pyasn1>=0.4.8 +pyasn1-modules>=0.2.8 +pycparser>=2.20 +pygsheets>=2.0.5 +pyparsing>=2.4.7 +pyrsistent>=0.16.0 +python-dateutil>=2.8.1 +pytz>=2020.1 +PyYAML>=5.4.1 +rdflib>=5.0.0 +requests>=2.24.0 +requests-oauthlib>=1.3.0 +rsa>=4.7 +schematicpy>=0.1.13 +SecretStorage>=2.3.1 +setuptools>=52.0.0 +six>=1.15.0 +synapseclient>=2.3.0 +tabletext>=0.1 +toml>=0.10.2 +uritemplate>=3.0.1 +urllib3>=1.26.5 +wheel>=0.34.2 +wrapt>=1.12.1 +zipp>=3.1.0 From 7398cd6b1e7b683ca8bf864feb9372059cb4223d Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Tue, 14 Dec 2021 00:35:24 +0000 Subject: [PATCH 144/260] Add instructions --- README.md | 5 ++ install-pkgs.R | 25 ++++++++++ requirements.txt | 122 +++++++++++++++++++++++------------------------ 3 files changed, 91 insertions(+), 61 deletions(-) create mode 100644 install-pkgs.R diff --git a/README.md b/README.md index 042f2c96..5de51d98 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor R -e "renv::restore()" +4a. If not using a conda environment nor renv, install the necessary packages using +the installation script provided. + + R -f install-pkgs.R + ### Schematic Setup 1. Clone the [schematic] (backend) as a folder `schematic` inside the `data_curator` folder: diff --git a/install-pkgs.R b/install-pkgs.R new file mode 100644 index 00000000..85e633bc --- /dev/null +++ b/install-pkgs.R @@ -0,0 +1,25 @@ +cran <- c("shiny", +"httr", +"rjson", +"yaml", +"shinyjs", +"dplyr", +"shinythemes", +"shinydashboard", +"stringr", +"DT", +"jsonlite", +"reticulate", +"ggplot2", +"purrr", +"plotly", +"shinydashboardPlus", +"waiter", +"readr", +"sass", +"remotes") + +gh <- "dreamRs/shinypop" + +install.packages(cran) +remotes::install_github(gh) diff --git a/requirements.txt b/requirements.txt index 6e657760..9b067224 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,61 +1,61 @@ -attrs==19.3.0 -cachetools==4.1.1 -certifi==2020.6.20 -cffi==1.14.0 -chardet==3.0.4 -click==7.1.2 -click-log==0.3.2 -cryptography==3.3.2 -decorator==4.4.2 -Deprecated==1.2.4 -entrypoints==0.3 -fastjsonschema==2.14.4 -google-api-core==1.26.3 -google-api-python-client==1.12.8 -google-auth==1.19.1 -google-auth-httplib2==0.0.4 -google-auth-oauthlib==0.4.4 -googleapis-common-protos==1.53.0 -graphviz==0.16 -httplib2==0.19.0 -idna==2.10 -importlib-metadata==1.7.0 -inflection==0.5.1 -isodate==0.6.0 -jsonschema==3.2.0 -keyring==12.0.2 -keyrings.alt==3.1 -networkx==2.5.1 -numpy==1.19.0 -oauth2client==3.0.0 -oauthlib==3.1.0 -orderedset==2.0.1 -packaging==20.9 -pandas==1.2.3 -pip==21.1 -protobuf==3.15.7 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -pycparser==2.20 -pygsheets==2.0.5 -pyparsing==2.4.7 -pyrsistent==0.16.0 -python-dateutil==2.8.1 -pytz==2020.1 -PyYAML==5.4.1 -rdflib==5.0.0 -requests==2.24.0 -requests-oauthlib==1.3.0 -rsa==4.7 -schematicpy==0.1.13 -SecretStorage==2.3.1 -setuptools==52.0.0 -six==1.15.0 -synapseclient==2.3.0 -tabletext==0.1 -toml==0.10.2 -uritemplate==3.0.1 -urllib3==1.26.5 -wheel==0.34.2 -wrapt==1.12.1 -zipp==3.1.0 +attrs>=19.3.0 +cachetools>=4.1.1 +certifi>=2020.6.20 +cffi>=1.14.0 +chardet>=3.0.4 +click>=7.1.2 +click-log>=0.3.2 +cryptography>=3.3.2 +decorator>=4.4.2 +Deprecated>=1.2.4 +entrypoints>=0.3 +fastjsonschema>=2.14.4 +google-api-core>=1.26.3 +google-api-python-client>=1.12.8 +google-auth>=1.19.1 +google-auth-httplib2>=0.0.4 +google-auth-oauthlib>=0.4.4 +googleapis-common-protos>=1.53.0 +graphviz>=0.16 +httplib2>=0.19.0 +idna>=2.10 +importlib-metadata>=1.7.0 +inflection>=0.5.1 +isodate>=0.6.0 +jsonschema>=3.2.0 +keyring>=12.0.2 +keyrings.alt>=3.1 +networkx>=2.5.1 +numpy>=1.19.0 +oauth2client>=3.0.0 +oauthlib>=3.1.0 +orderedset>=2.0.1 +packaging>=20.9 +pandas>=1.2.3 +pip>=21.1 +protobuf>=3.15.7 +pyasn1>=0.4.8 +pyasn1-modules>=0.2.8 +pycparser>=2.20 +pygsheets>=2.0.5 +pyparsing>=2.4.7 +pyrsistent>=0.16.0 +python-dateutil>=2.8.1 +pytz>=2020.1 +PyYAML>=5.4.1 +rdflib>=5.0.0 +requests>=2.24.0 +requests-oauthlib>=1.3.0 +rsa>=4.7 +schematicpy>=0.1.13 +SecretStorage>=2.3.1 +setuptools>=52.0.0 +six>=1.15.0 +synapseclient>=2.3.0 +tabletext>=0.1 +toml>=0.10.2 +uritemplate>=3.0.1 +urllib3>=1.26.5 +wheel>=0.34.2 +wrapt>=1.12.1 +zipp>=3.1.0 From e362c039f34d30b49635b10d0f63b83b922ebfcb Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Tue, 14 Dec 2021 00:43:35 +0000 Subject: [PATCH 145/260] Update README to manually install packages instead of renv --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5de51d98..3521b753 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 4a. If not using a conda environment nor renv, install the necessary packages using the installation script provided. - R -f install-pkgs.R + R -f install-pkgs.R ### Schematic Setup From c4de3dd77f5caea0a18978a728307965a3b3dea1 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 14 Dec 2021 15:19:42 +0000 Subject: [PATCH 146/260] fix typo on conda env name --- example_config.yaml | 4 ++-- global.R | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/example_config.yaml b/example_config.yaml index f65601e5..4ffa4f16 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -4,8 +4,8 @@ CLIENT_ID: '' CLIENT_SECRET: '' -# for local testing, the default port 8100 is used: http://localhost:8100/ -# change port based on your OAuth Client's redirect_uri +# url of your deployed app +# for local testing, change port based on your OAuth Client's redirect_uri, e.g. https://localhost:8100/ APP_URL: '' # change the conda environment name here, this must be the last line CONDA_NAME: 'data_curator_env' diff --git a/global.R b/global.R index 01c2e9cf..04cdaba2 100644 --- a/global.R +++ b/global.R @@ -38,11 +38,10 @@ if (interactive()) { # for local development # change port number associated with your client, here options(shiny.port = 8100) -} else { - app_url <- toString(oauth_client$APP_URL) } -conda_name <- toString(oauth_client$CONDA_ENV) +app_url <- toString(oauth_client$APP_URL) +conda_name <- toString(oauth_client$CONDA_NAME) if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") @@ -86,7 +85,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv(conda_name) +reticulate::use_condaenv(conda_name, required = TRUE) # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) From 19a0c53edad7bb5b95f073932a9de7bea50947e5 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 14 Dec 2021 16:10:42 +0000 Subject: [PATCH 147/260] modify regex --- functions/validationResult.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index c621151d..31ead931 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -62,6 +62,7 @@ validationResult <- function(valRes, template, inFile) { errorDT <- lapply(valRes, function(i) { error_row <- i[[1]] error_col <- i[[2]] + # get invalid value error_val <- inFile[as.numeric(error_row) - 1, error_col] tibble( Row = error_row, @@ -73,7 +74,7 @@ validationResult <- function(valRes, template, inFile) { # collapse similiar errors into one row errorDT <- errorDT %>% - mutate(Error = gsub(".*(not .*)[[:punct:]]", "\\1", Error)) %>% + mutate(Error = gsub(".*(not.*)\\.?$", "\\1", Error)) %>% group_by(Column, Error) %>% summarise( Row = str_c(unique(Row), collapse = ", ") %>% TruncateEllipsis(10, ", "), From 7fc7c3eb09e9be25a82bc3c05dbec26fa52072a6 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 06:23:52 -0800 Subject: [PATCH 148/260] deploy to ShinyApps using venv --- .github/workflows/shinyapps_deploy.yml | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/shinyapps_deploy.yml diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml new file mode 100644 index 00000000..3c2793c2 --- /dev/null +++ b/.github/workflows/shinyapps_deploy.yml @@ -0,0 +1,71 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help + +name: shiny-deploy + +on: + push: + branches: + - shiny-server-main + - release* + +jobs: + shiny-deploy: + runs-on: ubuntu-latest + env: + CONDA_ENV_NAME: "virtual_env" + + steps: + - name: Install libcurl + run: sudo apt-get install -y libcurl4-openssl-dev + + - uses: actions/checkout@v2 + + - uses: r-lib/actions/setup-pandoc@v1 + + - uses: r-lib/actions/setup-r@v1 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-renv@v1 + + - name: Install rsconnect + shell: Rscript {0} + run: install.packages(c("rsconnect", "yaml", "reticulate")) + + - name: Virtual Environment, Schematic install, R packages install + run: | + python -m venv ${{ env.CONDA_ENV_NAME }} + source "${{ env.CONDA_ENV_NAME }}"/bin/activate + python -m pip install schematicpy + pip install -r requirements.txt + R -f install-pkgs.R + + - name: Authorize and deploy app + shell: Rscript {0} + run: | + branch<-Sys.getenv("GITHUB_REF_NAME") + repo<-Sys.getenv("GITHUB_REPOSITORY") + appName<-strsplit(repo, "/")[[1]][2] + if (!startsWith(branch, "release")) { + appName <- paste(appName, "staging", sep="-") + } + rsConnectUser <-"${{ secrets.RSCONNECT_USER }}" + rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" + rsConnectSecret <- "${{ secrets.RSCONNECT_SECRET }}" + + # create config file + config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" + config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") + config <- c(config, "CONDA_ENV_NAME: ${{ env.CONDA_ENV_NAME }}") + appUrl<- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) + config <- c(config, sprintf("APP_URL: %s", appUrl)) + + configFileConn<-file("config.yaml") + tryCatch( + writeLines(config, configFileConn), + finally=close(configFileConn) + ) + rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) + rsconnect::deployApp(appName = appName) + \ No newline at end of file From a7dfc3dabda1b5e5c62103495b5aa11667e8034b Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 06:25:19 -0800 Subject: [PATCH 149/260] deploy 'switch-python-venv' branch --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3c2793c2..557a1801 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -7,6 +7,7 @@ on: push: branches: - shiny-server-main + - switch-python-venv - release* jobs: From ea31f733e40b9e280acc11ebae820150661c5044 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 06:51:24 -0800 Subject: [PATCH 150/260] clean up installation workflow --- .github/workflows/shinyapps_deploy.yml | 13 +++++++------ install-pkgs.R | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 557a1801..6876144a 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -30,16 +30,17 @@ jobs: - uses: r-lib/actions/setup-renv@v1 - - name: Install rsconnect - shell: Rscript {0} - run: install.packages(c("rsconnect", "yaml", "reticulate")) - - - name: Virtual Environment, Schematic install, R packages install + - name: Create and Activate Python Virtual Environment run: | python -m venv ${{ env.CONDA_ENV_NAME }} source "${{ env.CONDA_ENV_NAME }}"/bin/activate - python -m pip install schematicpy + + - name: Install Python Dependencies + run: | pip install -r requirements.txt + + - name: Install R packages + run: | R -f install-pkgs.R - name: Authorize and deploy app diff --git a/install-pkgs.R b/install-pkgs.R index 85e633bc..c19307ed 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -17,7 +17,8 @@ cran <- c("shiny", "waiter", "readr", "sass", -"remotes") +"remotes", +"rsconnect") gh <- "dreamRs/shinypop" From a9d3cef491bc0918b5207e06cefa2b6fc672fced Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 07:04:27 -0800 Subject: [PATCH 151/260] installing 'pillar', got error that 'ellipsis' was too old --- install-pkgs.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install-pkgs.R b/install-pkgs.R index c19307ed..ef831510 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -1,4 +1,6 @@ -cran <- c("shiny", +cran <- c( +"ellipsis", +"shiny", "httr", "rjson", "yaml", From 660de8010d53066215cf8b4dcf68d79e663e8ca6 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 07:33:03 -0800 Subject: [PATCH 152/260] remotes auth --- install-pkgs.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install-pkgs.R b/install-pkgs.R index ef831510..a6b9effb 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -25,4 +25,5 @@ cran <- c( gh <- "dreamRs/shinypop" install.packages(cran) -remotes::install_github(gh) +# auth_token=NULL only works for public repo's +remotes::install_github(gh, auth_token=NULL) From 6fae99cfef2d28902563b8d2d23cfa649da36ba5 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 07:48:03 -0800 Subject: [PATCH 153/260] remotes auth --- .gitignore | 4 +++- install-pkgs.R | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 817ca7a9..fe60551d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ schematic/ **/schematic_service_account_creds.json **/token.pickle **/__pycache__ -config.yaml \ No newline at end of file +config.yaml +.project +.settings/** \ No newline at end of file diff --git a/install-pkgs.R b/install-pkgs.R index a6b9effb..1e23ccdd 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -25,5 +25,7 @@ cran <- c( gh <- "dreamRs/shinypop" install.packages(cran) -# auth_token=NULL only works for public repo's -remotes::install_github(gh, auth_token=NULL) + +# We will only install public repo's from Github +Sys.unsetenv("GITHUB_PAT") +remotes::install_github(gh) From df51549fb9429efeb56e50eb61a11945e7ab6755 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 08:14:31 -0800 Subject: [PATCH 154/260] split cran and github installs --- .github/workflows/shinyapps_deploy.yml | 6 +++++- install-github.R | 6 ++++++ install-pkgs.R | 5 ----- 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 install-github.R diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 6876144a..cc1258d9 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -39,10 +39,14 @@ jobs: run: | pip install -r requirements.txt - - name: Install R packages + - name: Install R packages from CRAN run: | R -f install-pkgs.R + - name: Install R packages from GitHub + run: | + R -f install-github.R + - name: Authorize and deploy app shell: Rscript {0} run: | diff --git a/install-github.R b/install-github.R new file mode 100644 index 00000000..912e4985 --- /dev/null +++ b/install-github.R @@ -0,0 +1,6 @@ + +gh <- "dreamRs/shinypop" + +# We will only install public repo's from Github +Sys.unsetenv("GITHUB_PAT") +remotes::install_github(gh) diff --git a/install-pkgs.R b/install-pkgs.R index 1e23ccdd..36c65dc6 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -22,10 +22,5 @@ cran <- c( "remotes", "rsconnect") -gh <- "dreamRs/shinypop" install.packages(cran) - -# We will only install public repo's from Github -Sys.unsetenv("GITHUB_PAT") -remotes::install_github(gh) From 2ffbdc89cf438e2196a4ca36e95461970a79ab78 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 10:13:36 -0800 Subject: [PATCH 155/260] set auth_token to NULL in install_github --- install-github.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-github.R b/install-github.R index 912e4985..61296526 100644 --- a/install-github.R +++ b/install-github.R @@ -3,4 +3,4 @@ gh <- "dreamRs/shinypop" # We will only install public repo's from Github Sys.unsetenv("GITHUB_PAT") -remotes::install_github(gh) +remotes::install_github(gh, auth_token=NULL) From 21b5a89d85d759fbb66fd35b45545b72d38c31d9 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 10:29:04 -0800 Subject: [PATCH 156/260] add traceback to install_github --- install-github.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/install-github.R b/install-github.R index 61296526..e12f801c 100644 --- a/install-github.R +++ b/install-github.R @@ -3,4 +3,7 @@ gh <- "dreamRs/shinypop" # We will only install public repo's from Github Sys.unsetenv("GITHUB_PAT") -remotes::install_github(gh, auth_token=NULL) +tryCatch( + remotes::install_github(gh, auth_token=NULL), + error = function(e) {message(traceback())} +) From c4ce8d5d913abe8177e61bbe825d70278b524b7b Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 11:39:07 -0800 Subject: [PATCH 157/260] remove traceback from install_github --- install-github.R | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/install-github.R b/install-github.R index e12f801c..61296526 100644 --- a/install-github.R +++ b/install-github.R @@ -3,7 +3,4 @@ gh <- "dreamRs/shinypop" # We will only install public repo's from Github Sys.unsetenv("GITHUB_PAT") -tryCatch( - remotes::install_github(gh, auth_token=NULL), - error = function(e) {message(traceback())} -) +remotes::install_github(gh, auth_token=NULL) From 434288070151e607e0bbaa91980a7943379a5264 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 12:00:22 -0800 Subject: [PATCH 158/260] added Github PAT (shouldn't be necessary but it) --- .github/workflows/shinyapps_deploy.yml | 2 ++ install-github.R | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index cc1258d9..be56fb7a 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest env: CONDA_ENV_NAME: "virtual_env" + # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. + GITHUB_PAT: ${{ secrets.REPO_PAT }} steps: - name: Install libcurl diff --git a/install-github.R b/install-github.R index 61296526..73f38489 100644 --- a/install-github.R +++ b/install-github.R @@ -1,6 +1,4 @@ gh <- "dreamRs/shinypop" -# We will only install public repo's from Github -Sys.unsetenv("GITHUB_PAT") -remotes::install_github(gh, auth_token=NULL) +remotes::install_github(gh) From be564f9c0aeb965167a75674cd1a79d06e3eb095 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 12:35:04 -0800 Subject: [PATCH 159/260] rolled back split of r package installation --- .github/workflows/shinyapps_deploy.yml | 6 +----- global.R | 1 + install-github.R | 4 ---- install-pkgs.R | 2 ++ 4 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 install-github.R diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index be56fb7a..52e8f1f1 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -41,14 +41,10 @@ jobs: run: | pip install -r requirements.txt - - name: Install R packages from CRAN + - name: Install R packages run: | R -f install-pkgs.R - - name: Install R packages from GitHub - run: | - R -f install-github.R - - name: Authorize and deploy app shell: Rscript {0} run: | diff --git a/global.R b/global.R index 10e0166a..dfaa0998 100644 --- a/global.R +++ b/global.R @@ -87,6 +87,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable +message(sprintf("Activating virtual environment %s", conda_name)) reticulate::use_virtualenv(conda_name) # Import functions/modules diff --git a/install-github.R b/install-github.R deleted file mode 100644 index 73f38489..00000000 --- a/install-github.R +++ /dev/null @@ -1,4 +0,0 @@ - -gh <- "dreamRs/shinypop" - -remotes::install_github(gh) diff --git a/install-pkgs.R b/install-pkgs.R index 36c65dc6..ef831510 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -22,5 +22,7 @@ cran <- c( "remotes", "rsconnect") +gh <- "dreamRs/shinypop" install.packages(cran) +remotes::install_github(gh) From e918f7a9e11b2c748461756ca88e2aca242155eb Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 12:58:49 -0800 Subject: [PATCH 160/260] debug missing venv name --- .github/workflows/shinyapps_deploy.yml | 4 ++-- global.R | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 52e8f1f1..afcb9751 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -61,10 +61,10 @@ jobs: # create config file config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") - config <- c(config, "CONDA_ENV_NAME: ${{ env.CONDA_ENV_NAME }}") appUrl<- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) config <- c(config, sprintf("APP_URL: %s", appUrl)) - + config <- c(config, "CONDA_ENV_NAME: ${{ env.CONDA_ENV_NAME }}") + configFileConn<-file("config.yaml") tryCatch( writeLines(config, configFileConn), diff --git a/global.R b/global.R index dfaa0998..3bb2bbf0 100644 --- a/global.R +++ b/global.R @@ -31,9 +31,14 @@ has_auth_code <- function(params) { oauth_client <- yaml.load_file("config.yaml") + client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) +message(sprintf("Read client id %s", client_id)) +message(sprintf("venv name %s", oauth_client$CONDA_NAME)) + + if (interactive()) { # for local development options(shiny.port = 8100) @@ -48,7 +53,7 @@ conda_name <- toString(oauth_client$CONDA_NAME) if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") if (is.null(app_url)) stop("config.yaml is missing APP_URL") -if (is.null(conda_name)) stop("config.yaml is missing CONDA_ENV_NAME") +if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") app <- oauth_app("shinysynapse", key = client_id, @@ -87,7 +92,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -message(sprintf("Activating virtual environment %s", conda_name)) +message(sprintf("Activating virtual environment <%s>", conda_name)) reticulate::use_virtualenv(conda_name) # Import functions/modules From f5463ec9de2355a9b4633f3de63b508d4e1dade9 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 13:19:35 -0800 Subject: [PATCH 161/260] fixed CONDA_NAME label in config file --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index afcb9751..3a2c7f81 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -63,7 +63,7 @@ jobs: config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") appUrl<- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) config <- c(config, sprintf("APP_URL: %s", appUrl)) - config <- c(config, "CONDA_ENV_NAME: ${{ env.CONDA_ENV_NAME }}") + config <- c(config, "CONDA_NAME: ${{ env.CONDA_ENV_NAME }}") configFileConn<-file("config.yaml") tryCatch( From c05516a6c1f765b764e4aff7168844ad2ace8a22 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 13:39:48 -0800 Subject: [PATCH 162/260] try unsetting RETICULATE_PYTHON --- global.R | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/global.R b/global.R index 3bb2bbf0..87da0bcd 100644 --- a/global.R +++ b/global.R @@ -31,14 +31,9 @@ has_auth_code <- function(params) { oauth_client <- yaml.load_file("config.yaml") - client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) -message(sprintf("Read client id %s", client_id)) -message(sprintf("venv name %s", oauth_client$CONDA_NAME)) - - if (interactive()) { # for local development options(shiny.port = 8100) @@ -50,9 +45,9 @@ if (interactive()) { conda_name <- toString(oauth_client$CONDA_NAME) -if (is.null(client_id)) stop("config.yaml is missing CLIENT_ID") -if (is.null(client_secret)) stop("config.yaml is missing CLIENT_SECRET") -if (is.null(app_url)) stop("config.yaml is missing APP_URL") +if (is.null(client_id) || nchar(client_id)==0) stop("config.yaml is missing CLIENT_ID") +if (is.null(client_secret) || nchar(client_secret)==0) stop("config.yaml is missing CLIENT_SECRET") +if (is.null(app_url) || nchar(app_url)==0) stop("config.yaml is missing APP_URL") if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") app <- oauth_app("shinysynapse", @@ -92,7 +87,7 @@ scope <- "openid view download modify" # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable -message(sprintf("Activating virtual environment <%s>", conda_name)) +Sys.unsetenv("RETICULATE_PYTHON") reticulate::use_virtualenv(conda_name) # Import functions/modules From 46ace876a8c47e4e8f686165655bc3affad43626 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 14:41:01 -0800 Subject: [PATCH 163/260] activate venv before installing dependencies --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3a2c7f81..12273496 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -39,6 +39,7 @@ jobs: - name: Install Python Dependencies run: | + source "${{ env.CONDA_ENV_NAME }}"/bin/activate pip install -r requirements.txt - name: Install R packages From 3a91a92cdc9ec0246d601b37e2e9bf2849d59fb1 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 17:07:05 -0800 Subject: [PATCH 164/260] trying to switch from 'python' to 'python3' --- .github/workflows/shinyapps_deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 12273496..f64f0465 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -34,13 +34,13 @@ jobs: - name: Create and Activate Python Virtual Environment run: | - python -m venv ${{ env.CONDA_ENV_NAME }} + python3 -m venv ${{ env.CONDA_ENV_NAME }} source "${{ env.CONDA_ENV_NAME }}"/bin/activate - name: Install Python Dependencies run: | source "${{ env.CONDA_ENV_NAME }}"/bin/activate - pip install -r requirements.txt + pip3 install -r requirements.txt - name: Install R packages run: | From 7b15d00a879659dfe934aa87faf77766ba64d8d4 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 17:40:25 -0800 Subject: [PATCH 165/260] trying to run the build in a rocker/rstudio container --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index f64f0465..e764cd2a 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -13,6 +13,7 @@ on: jobs: shiny-deploy: runs-on: ubuntu-latest + container: rocker/rstudio env: CONDA_ENV_NAME: "virtual_env" # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. From e123830069101a66034ebb2edaaa2facd99fe694 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 17:45:06 -0800 Subject: [PATCH 166/260] removing 'r-lib/actions/setup-r' since we are running in a container --- .github/workflows/shinyapps_deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index e764cd2a..ef9834b7 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -27,9 +27,9 @@ jobs: - uses: r-lib/actions/setup-pandoc@v1 - - uses: r-lib/actions/setup-r@v1 - with: - use-public-rspm: true + # - uses: r-lib/actions/setup-r@v1 + # with: + # use-public-rspm: true - uses: r-lib/actions/setup-renv@v1 From d2c532e5e19dd83c143a3c7d1e4e60f521406585 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 17:59:07 -0800 Subject: [PATCH 167/260] try skipping setup-renv --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index ef9834b7..2cafb8d6 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -31,7 +31,7 @@ jobs: # with: # use-public-rspm: true - - uses: r-lib/actions/setup-renv@v1 + # - uses: r-lib/actions/setup-renv@v1 - name: Create and Activate Python Virtual Environment run: | From 2da0a20bf575ba0c3c439737d9101b47e122d46e Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 20:26:03 -0800 Subject: [PATCH 168/260] install dependencies --- .github/workflows/shinyapps_deploy.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 2cafb8d6..2bb1ed3f 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -20,8 +20,9 @@ jobs: GITHUB_PAT: ${{ secrets.REPO_PAT }} steps: - - name: Install libcurl - run: sudo apt-get install -y libcurl4-openssl-dev + - name: Install System Dependencies + run: sudo apt-get update + run: sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev - uses: actions/checkout@v2 From cd758c94d18dbd2ef965ce2e2b6bf989b9a150cd Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 20:28:42 -0800 Subject: [PATCH 169/260] install dependencies --- .github/workflows/shinyapps_deploy.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 2bb1ed3f..07949ccf 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -21,8 +21,9 @@ jobs: steps: - name: Install System Dependencies - run: sudo apt-get update - run: sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev + run: | + sudo apt-get update + sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev - uses: actions/checkout@v2 From e7cfeb63b192fa6f8f342527198086ebe7cc1fb7 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 20:30:42 -0800 Subject: [PATCH 170/260] install dependencies --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 07949ccf..cc759817 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -38,7 +38,7 @@ jobs: - name: Create and Activate Python Virtual Environment run: | python3 -m venv ${{ env.CONDA_ENV_NAME }} - source "${{ env.CONDA_ENV_NAME }}"/bin/activate + "${{ env.CONDA_ENV_NAME }}"/bin/activate - name: Install Python Dependencies run: | From 42a6f5347cbb1df484a80df15b00860665ffbb92 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 20:32:47 -0800 Subject: [PATCH 171/260] install dependencies --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index cc759817..c44e836b 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -38,6 +38,7 @@ jobs: - name: Create and Activate Python Virtual Environment run: | python3 -m venv ${{ env.CONDA_ENV_NAME }} + chmod 755 "${{ env.CONDA_ENV_NAME }}"/bin/activate "${{ env.CONDA_ENV_NAME }}"/bin/activate - name: Install Python Dependencies From cad19a0039bb544a54da29d8d455db67861ccbd0 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 20:35:42 -0800 Subject: [PATCH 172/260] install dependencies --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index c44e836b..a8c3b881 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -43,7 +43,7 @@ jobs: - name: Install Python Dependencies run: | - source "${{ env.CONDA_ENV_NAME }}"/bin/activate + "${{ env.CONDA_ENV_NAME }}"/bin/activate pip3 install -r requirements.txt - name: Install R packages From b29033bc0ef173121e05413e67be723b42602c43 Mon Sep 17 00:00:00 2001 From: bhoff Date: Wed, 15 Dec 2021 21:04:33 -0800 Subject: [PATCH 173/260] install dependencies --- install-pkgs.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install-pkgs.R b/install-pkgs.R index ef831510..ac2bd51d 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -20,7 +20,8 @@ cran <- c( "readr", "sass", "remotes", -"rsconnect") +"rsconnect", +"png") gh <- "dreamRs/shinypop" From d24e21e2fc1e7ece415fd0582e0c483ba63f7bb0 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 06:28:58 -0800 Subject: [PATCH 174/260] trying adding repository of precompiled R libraries --- install-pkgs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-pkgs.R b/install-pkgs.R index ac2bd51d..1dfb7946 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -24,6 +24,6 @@ cran <- c( "png") gh <- "dreamRs/shinypop" - +options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) install.packages(cran) remotes::install_github(gh) From 0225f49ab09d67781309dd8e73fbb8531f0b0632 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 16 Dec 2021 14:36:13 +0000 Subject: [PATCH 175/260] not need to get invalid value followed by schematic update --- functions/validationResult.R | 15 +++++++-------- server.R | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index 31ead931..62121037 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -60,16 +60,15 @@ validationResult <- function(valRes, template, inFile) { } errorDT <- lapply(valRes, function(i) { - error_row <- i[[1]] - error_col <- i[[2]] - # get invalid value - error_val <- inFile[as.numeric(error_row) - 1, error_col] tibble( - Row = error_row, - Column = error_col, - Value = error_val, + Row = i[[1]], + Column = i[[2]], + Value = i[[4]][[1]], Error = i[[3]] - ) %>% mutate(across(everything(), as.character)) + ) %>% + # ensure highlight function to work + # convert to all characters since {inFile} in preview are all characters + mutate(across(everything(), as.character)) }) %>% bind_rows() # collapse similiar errors into one row diff --git a/server.R b/server.R index 94834af1..40a47949 100644 --- a/server.R +++ b/server.R @@ -268,7 +268,7 @@ shinyServer(function(input, output, session) { template_schema_name() ) ) - + logjs(annotation_status) # validation messages valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) From 1e8b8fbcf51a796bef8b14bdcd0fd12bf96080d6 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 16 Dec 2021 14:38:05 +0000 Subject: [PATCH 176/260] remove logjs --- server.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.R b/server.R index 40a47949..94834af1 100644 --- a/server.R +++ b/server.R @@ -268,7 +268,7 @@ shinyServer(function(input, output, session) { template_schema_name() ) ) - logjs(annotation_status) + # validation messages valRes <- validationResult(annotation_status, input$dropdown_template, inFile$data()) ValidationMsgServer("text_validate", valRes, input$dropdown_template, inFile$data()) From 6ca6681ab1ef6255178d228262a1cfa7d233cfaf Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 16 Dec 2021 14:42:43 +0000 Subject: [PATCH 177/260] only convert value to character --- functions/validationResult.R | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index 62121037..c977e899 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -63,12 +63,11 @@ validationResult <- function(valRes, template, inFile) { tibble( Row = i[[1]], Column = i[[2]], - Value = i[[4]][[1]], + # ensure highlight function to work + # convert to all characters since {inFile} in preview are all characters + Value = as.character(i[[4]][[1]]), Error = i[[3]] - ) %>% - # ensure highlight function to work - # convert to all characters since {inFile} in preview are all characters - mutate(across(everything(), as.character)) + ) }) %>% bind_rows() # collapse similiar errors into one row From dec0674739154a02d2262d1ec3b41d7eb8de89c6 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 07:33:36 -0800 Subject: [PATCH 178/260] must use 'source' to call venv activate script --- .github/workflows/shinyapps_deploy.yml | 11 +++-------- install-pkgs.R | 2 ++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index a8c3b881..ed94c266 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -13,6 +13,7 @@ on: jobs: shiny-deploy: runs-on: ubuntu-latest + # This image seems to be based on rocker/r-ver which in turn is based on debian container: rocker/rstudio env: CONDA_ENV_NAME: "virtual_env" @@ -29,21 +30,15 @@ jobs: - uses: r-lib/actions/setup-pandoc@v1 - # - uses: r-lib/actions/setup-r@v1 - # with: - # use-public-rspm: true - - # - uses: r-lib/actions/setup-renv@v1 - - name: Create and Activate Python Virtual Environment run: | python3 -m venv ${{ env.CONDA_ENV_NAME }} chmod 755 "${{ env.CONDA_ENV_NAME }}"/bin/activate - "${{ env.CONDA_ENV_NAME }}"/bin/activate + source "${{ env.CONDA_ENV_NAME }}"/bin/activate - name: Install Python Dependencies run: | - "${{ env.CONDA_ENV_NAME }}"/bin/activate + source "${{ env.CONDA_ENV_NAME }}"/bin/activate pip3 install -r requirements.txt - name: Install R packages diff --git a/install-pkgs.R b/install-pkgs.R index 1dfb7946..8706355c 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -24,6 +24,8 @@ cran <- c( "png") gh <- "dreamRs/shinypop" +# For Ubuntu 18.04 (Bionic) it's https://packagemanager.rstudio.com/all/__linux__/bionic/latest +# For Ubuntu 20.04 (Focal) it's https://packagemanager.rstudio.com/all/__linux__/focal/latest options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) install.packages(cran) remotes::install_github(gh) From d36ddb929633e9a35d7b623c4f2927dde82f4a5f Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 16 Dec 2021 15:47:48 +0000 Subject: [PATCH 179/260] Revert "only convert value to character" This reverts commit 6ca6681ab1ef6255178d228262a1cfa7d233cfaf. --- functions/validationResult.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index c977e899..62121037 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -63,11 +63,12 @@ validationResult <- function(valRes, template, inFile) { tibble( Row = i[[1]], Column = i[[2]], - # ensure highlight function to work - # convert to all characters since {inFile} in preview are all characters - Value = as.character(i[[4]][[1]]), + Value = i[[4]][[1]], Error = i[[3]] - ) + ) %>% + # ensure highlight function to work + # convert to all characters since {inFile} in preview are all characters + mutate(across(everything(), as.character)) }) %>% bind_rows() # collapse similiar errors into one row From ed1a7eab2b7094bbb61af668c3ead6928563eb49 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 09:13:58 -0800 Subject: [PATCH 180/260] rm quotes from virtual_env to try to fix the 'not found' error --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index ed94c266..3f77cc9d 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -16,7 +16,7 @@ jobs: # This image seems to be based on rocker/r-ver which in turn is based on debian container: rocker/rstudio env: - CONDA_ENV_NAME: "virtual_env" + CONDA_ENV_NAME: virtual_env # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. GITHUB_PAT: ${{ secrets.REPO_PAT }} From 4a4a3579c06021c57318d77454bac5c9bab3bfae Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 09:15:54 -0800 Subject: [PATCH 181/260] rm quotes from virtual_env to try to fix the 'not found' error --- .github/workflows/shinyapps_deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3f77cc9d..fbfd95fd 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -33,8 +33,8 @@ jobs: - name: Create and Activate Python Virtual Environment run: | python3 -m venv ${{ env.CONDA_ENV_NAME }} - chmod 755 "${{ env.CONDA_ENV_NAME }}"/bin/activate - source "${{ env.CONDA_ENV_NAME }}"/bin/activate + chmod 755 ${{ env.CONDA_ENV_NAME }}/bin/activate + source ${{ env.CONDA_ENV_NAME }}/bin/activate - name: Install Python Dependencies run: | From d3b3ea328f788720bbaa96dd3f93925863f8a34d Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 09:21:59 -0800 Subject: [PATCH 182/260] use bash shell --- .github/workflows/shinyapps_deploy.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index fbfd95fd..3b905fcb 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -31,12 +31,14 @@ jobs: - uses: r-lib/actions/setup-pandoc@v1 - name: Create and Activate Python Virtual Environment + shell: bash run: | - python3 -m venv ${{ env.CONDA_ENV_NAME }} - chmod 755 ${{ env.CONDA_ENV_NAME }}/bin/activate - source ${{ env.CONDA_ENV_NAME }}/bin/activate + python3 -m venv "${{ env.CONDA_ENV_NAME }}" + chmod 755 "${{ env.CONDA_ENV_NAME }}"/bin/activate + source "${{ env.CONDA_ENV_NAME }}"/bin/activate - name: Install Python Dependencies + shell: bash run: | source "${{ env.CONDA_ENV_NAME }}"/bin/activate pip3 install -r requirements.txt From 80026f60e177b139cf37ff1e2f58eb49c2dfa871 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 09:39:39 -0800 Subject: [PATCH 183/260] restrict setuptools <58 to fix error 'error in tabletext setup command: use_2to3 is invalid' --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9b067224..ebbca042 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,7 +49,7 @@ requests-oauthlib>=1.3.0 rsa>=4.7 schematicpy>=0.1.13 SecretStorage>=2.3.1 -setuptools>=52.0.0 +setuptools>=52.0.0,<58 six>=1.15.0 synapseclient>=2.3.0 tabletext>=0.1 From 65e8ad23536787267db5f06dba5e7ad74ef2f6bc Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 09:59:36 -0800 Subject: [PATCH 184/260] debug --- .github/workflows/shinyapps_deploy.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3b905fcb..3c9d3309 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -42,11 +42,21 @@ jobs: run: | source "${{ env.CONDA_ENV_NAME }}"/bin/activate pip3 install -r requirements.txt + # where did the dependencies end up? Let's look for a couple: + find / -name "*jeepney*" + find / -name "*inflection*" - name: Install R packages run: | R -f install-pkgs.R - + + - name: Spot check Python dependencies + shell: bash + run: | + # Could it be that the dependencies get lost between steps? + find / -name "*jeepney*" + find / -name "*inflection*" + - name: Authorize and deploy app shell: Rscript {0} run: | From bbcbddb8e1d39a3e2d0459db87ed3afe426fea18 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 10:19:45 -0800 Subject: [PATCH 185/260] increase rsconnect max files in deployed bundle --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3c9d3309..c97c7b90 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -82,6 +82,7 @@ jobs: writeLines(config, configFileConn), finally=close(configFileConn) ) + options("rsconnect.max.bundle.files option"=20000) # doubled from the default rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) \ No newline at end of file From 679e5a01dc8bafdcd49e425f972af281c6702e84 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 10:35:07 -0800 Subject: [PATCH 186/260] typo --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index c97c7b90..e35897c0 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -82,7 +82,7 @@ jobs: writeLines(config, configFileConn), finally=close(configFileConn) ) - options("rsconnect.max.bundle.files option"=20000) # doubled from the default + options("rsconnect.max.bundle.files"=20000) # doubled from the default rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) \ No newline at end of file From baf165956646f79430740078076d1ff5d15f0865 Mon Sep 17 00:00:00 2001 From: bhoff Date: Thu, 16 Dec 2021 10:52:56 -0800 Subject: [PATCH 187/260] increased file count even mor --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index e35897c0..bd1e7d3e 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -82,7 +82,7 @@ jobs: writeLines(config, configFileConn), finally=close(configFileConn) ) - options("rsconnect.max.bundle.files"=20000) # doubled from the default + options("rsconnect.max.bundle.files"=200000) # 20x the default rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) \ No newline at end of file From db6d4f73fd65835699d52a877647b445c3040f63 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Thu, 16 Dec 2021 19:34:23 +0000 Subject: [PATCH 188/260] Update python requirements.txt --- requirements.txt | 369 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 308 insertions(+), 61 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9b067224..ac9f738c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,61 +1,308 @@ -attrs>=19.3.0 -cachetools>=4.1.1 -certifi>=2020.6.20 -cffi>=1.14.0 -chardet>=3.0.4 -click>=7.1.2 -click-log>=0.3.2 -cryptography>=3.3.2 -decorator>=4.4.2 -Deprecated>=1.2.4 -entrypoints>=0.3 -fastjsonschema>=2.14.4 -google-api-core>=1.26.3 -google-api-python-client>=1.12.8 -google-auth>=1.19.1 -google-auth-httplib2>=0.0.4 -google-auth-oauthlib>=0.4.4 -googleapis-common-protos>=1.53.0 -graphviz>=0.16 -httplib2>=0.19.0 -idna>=2.10 -importlib-metadata>=1.7.0 -inflection>=0.5.1 -isodate>=0.6.0 -jsonschema>=3.2.0 -keyring>=12.0.2 -keyrings.alt>=3.1 -networkx>=2.5.1 -numpy>=1.19.0 -oauth2client>=3.0.0 -oauthlib>=3.1.0 -orderedset>=2.0.1 -packaging>=20.9 -pandas>=1.2.3 -pip>=21.1 -protobuf>=3.15.7 -pyasn1>=0.4.8 -pyasn1-modules>=0.2.8 -pycparser>=2.20 -pygsheets>=2.0.5 -pyparsing>=2.4.7 -pyrsistent>=0.16.0 -python-dateutil>=2.8.1 -pytz>=2020.1 -PyYAML>=5.4.1 -rdflib>=5.0.0 -requests>=2.24.0 -requests-oauthlib>=1.3.0 -rsa>=4.7 -schematicpy>=0.1.13 -SecretStorage>=2.3.1 -setuptools>=52.0.0 -six>=1.15.0 -synapseclient>=2.3.0 -tabletext>=0.1 -toml>=0.10.2 -uritemplate>=3.0.1 -urllib3>=1.26.5 -wheel>=0.34.2 -wrapt>=1.12.1 -zipp>=3.1.0 +alabaster==0.7.12 +anaconda-client==1.9.0 +anaconda-navigator==2.1.1 +anaconda-project==0.10.1 +anyio==2.2.0 +appdirs==1.4.4 +argh==0.26.2 +argon2-cffi==20.1.0 +arrow==0.13.1 +asn1crypto==1.4.0 +astroid==2.6.6 +astropy==4.3.1 +async-generator==1.10 +atomicwrites==1.4.0 +attrs==21.2.0 +autopep8==1.5.7 +Babel==2.9.1 +backcall==0.2.0 +backports.functools-lru-cache==1.6.4 +backports.shutil-get-terminal-size==1.0.0 +backports.tempfile==1.0 +backports.weakref==1.0.post1 +beautifulsoup4==4.10.0 +binaryornot==0.4.4 +bitarray==2.3.0 +bkcharts==0.2 +black==19.10b0 +bleach==4.0.0 +bokeh==2.4.1 +boto==2.49.0 +Bottleneck==1.3.2 +brotlipy==0.7.0 +cached-property==1.5.2 +cachetools==4.2.4 +certifi==2021.10.8 +cffi==1.14.6 +chardet==4.0.0 +charset-normalizer==2.0.4 +click==7.1.2 +click-log==0.3.2 +clickclick==20.10.2 +cloudpickle==2.0.0 +clyent==1.2.2 +colorama==0.4.4 +conda==4.10.3 +conda-build==3.21.5 +conda-content-trust==0+unknown +conda-pack==0.6.0 +conda-package-handling==1.7.3 +conda-repo-cli==1.0.4 +conda-token==0.3.0 +conda-verify==3.4.2 +connexion==2.9.0 +contextlib2==0.6.0.post1 +cookiecutter==1.7.2 +cryptography==3.4.8 +cycler==0.10.0 +Cython==0.29.24 +cytoolz==0.11.0 +daal4py==2021.3.0 +dask==2021.10.0 +debugpy==1.4.1 +decorator==5.1.0 +defusedxml==0.7.1 +Deprecated==1.2.13 +diff-match-patch==20200713 +distributed==2021.10.0 +docutils==0.17.1 +entrypoints==0.3 +et-xmlfile==1.1.0 +fastcache==1.1.0 +filelock==3.3.1 +flake8==3.9.2 +Flask==1.1.4 +fonttools==4.25.0 +fsspec==2021.8.1 +future==0.18.2 +gevent==21.8.0 +glob2==0.7 +gmpy2==2.0.8 +google-api-core==1.31.4 +google-api-python-client==1.12.8 +google-auth==1.35.0 +google-auth-httplib2==0.0.4 +google-auth-oauthlib==0.4.6 +googleapis-common-protos==1.53.0 +graphviz==0.16 +greenlet==1.1.1 +h5py==3.3.0 +HeapDict==1.0.1 +html5lib==1.1 +httplib2==0.20.2 +idna==3.2 +imagecodecs==2021.8.26 +imageio==2.9.0 +imagesize==1.2.0 +importlib-metadata==4.8.1 +inflection==0.5.1 +iniconfig==1.1.1 +intervaltree==3.1.0 +ipykernel==6.4.1 +ipython==7.29.0 +ipython-genutils==0.2.0 +ipywidgets==7.6.5 +isodate==0.6.0 +isort==5.9.3 +itsdangerous==1.1.0 +jdcal==1.4.1 +jedi==0.18.0 +jeepney==0.7.1 +Jinja2==2.11.3 +jinja2-time==0.2.0 +joblib==1.1.0 +json5==0.9.6 +jsonschema==3.2.0 +jupyter==1.0.0 +jupyter-client==6.1.12 +jupyter-console==6.4.0 +jupyter-core==4.8.1 +jupyter-server==1.4.1 +jupyterlab==3.2.1 +jupyterlab-pygments==0.1.2 +jupyterlab-server==2.8.2 +jupyterlab-widgets==1.0.0 +keyring==12.0.2 +keyrings.alt==3.1 +kiwisolver==1.3.1 +lazy-object-proxy==1.6.0 +libarchive-c==2.9 +llvmlite==0.37.0 +locket==0.2.1 +lxml==4.6.3 +MarkupSafe==1.1.1 +matplotlib==3.4.3 +matplotlib-inline==0.1.2 +mccabe==0.6.1 +mistune==0.8.4 +mkl-fft==1.3.1 +mkl-random==1.2.2 +mkl-service==2.4.0 +mock==4.0.3 +more-itertools==8.10.0 +mpmath==1.2.1 +msgpack==1.0.2 +multipledispatch==0.6.0 +munkres==1.1.4 +mypy-extensions==0.4.3 +navigator-updater==0.2.1 +nbclassic==0.2.6 +nbclient==0.5.3 +nbconvert==6.1.0 +nbformat==5.1.3 +nest-asyncio==1.5.1 +networkx==2.6.3 +nltk==3.6.5 +nose==1.3.7 +notebook==6.4.5 +numba==0.54.1 +numexpr==2.7.3 +numpy==1.20.3 +numpydoc==1.1.0 +oauth2client==3.0.0 +oauthlib==3.1.1 +olefile==0.46 +openapi-schema-validator==0.1.5 +openapi-spec-validator==0.3.1 +openpyxl==3.0.9 +packaging==21.0 +pandas==1.3.4 +pandocfilters==1.4.3 +parso==0.8.2 +partd==1.2.0 +path==16.0.0 +pathlib2==2.3.6 +pathspec==0.7.0 +patsy==0.5.2 +pep8==1.7.1 +pexpect==4.8.0 +pickleshare==0.7.5 +Pillow==8.4.0 +pip==21.2.4 +pkginfo==1.7.1 +pluggy==0.13.1 +ply==3.11 +poyo==0.5.0 +prometheus-client==0.11.0 +prompt-toolkit==3.0.20 +protobuf==3.19.1 +psutil==5.8.0 +ptyprocess==0.7.0 +py==1.10.0 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycodestyle==2.7.0 +pycosat==0.6.3 +pycparser==2.20 +pycurl==7.44.1 +pydocstyle==6.1.1 +pyerfa==2.0.0 +pyflakes==2.3.1 +Pygments==2.10.0 +pygsheets==2.0.5 +PyJWT==2.1.0 +pylint==2.9.6 +pyls-spyder==0.4.0 +pyodbc==4.0.0-unsupported +pyOpenSSL==21.0.0 +pyparsing==3.0.4 +pyrsistent==0.18.0 +PySocks==1.7.1 +pytest==6.2.4 +python-dateutil==2.8.2 +python-lsp-black==1.0.0 +python-lsp-jsonrpc==1.0.0 +python-lsp-server==1.2.4 +python-slugify==5.0.2 +pytz==2021.3 +PyWavelets==1.1.1 +pyxdg==0.27 +PyYAML==5.4.1 +pyzmq==22.2.1 +QDarkStyle==3.0.2 +qstylizer==0.1.10 +QtAwesome==1.0.2 +qtconsole==5.1.1 +QtPy==1.10.0 +rdflib==5.0.0 +regex==2021.8.3 +requests==2.26.0 +requests-oauthlib==1.3.0 +rope==0.19.0 +rsa==4.8 +Rtree==0.9.7 +ruamel-yaml-conda==0.15.100 +schematicpy==1.0.0 +scikit-image==0.18.3 +scikit-learn==0.24.2 +scikit-learn-intelex==2021.20210714.170444 +scipy==1.7.1 +seaborn==0.11.2 +SecretStorage==2.3.1 +Send2Trash==1.8.0 +setuptools==52.0.0 +simplegeneric==0.8.1 +singledispatch==3.7.0 +sip==4.19.13 +six==1.16.0 +sniffio==1.2.0 +snowballstemmer==2.1.0 +sortedcollections==2.1.0 +sortedcontainers==2.4.0 +soupsieve==2.2.1 +Sphinx==4.2.0 +sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib-websupport==1.2.4 +spyder==5.1.5 +spyder-kernels==2.1.3 +SQLAlchemy==1.4.22 +statsmodels==0.12.2 +swagger-ui-bundle==0.0.9 +sympy==1.9 +synapseclient==2.5.0 +tables==3.6.1 +TBB==0.2 +tblib==1.7.0 +terminado==0.9.4 +testpath==0.5.0 +text-unidecode==1.3 +textdistance==4.2.1 +threadpoolctl==2.2.0 +three-merge==0.1.1 +tifffile==2021.7.2 +tinycss==0.4 +toml==0.10.2 +toolz==0.11.1 +tornado==6.1 +tqdm==4.62.3 +traitlets==5.1.0 +typed-ast==1.4.3 +typing-extensions==3.10.0.2 +ujson==4.0.2 +unicodecsv==0.14.1 +Unidecode==1.2.0 +uritemplate==3.0.1 +urllib3==1.26.7 +watchdog==2.1.3 +wcwidth==0.2.5 +webencodings==0.5.1 +Werkzeug==1.0.1 +wheel==0.37.0 +whichcraft==0.6.1 +widgetsnbextension==3.5.1 +wrapt==1.12.1 +wurlitzer==2.1.1 +xlrd==2.0.1 +XlsxWriter==3.0.1 +xlwt==1.3.0 +xmltodict==0.12.0 +yapf==0.31.0 +zict==2.0.0 +zipp==3.6.0 +zope.event==4.5.0 +zope.interface==5.4.0 From 8ba19e7549bdd52ae92f09511bf35022b2b2c126 Mon Sep 17 00:00:00 2001 From: Anthony Williams Date: Thu, 16 Dec 2021 19:59:40 +0000 Subject: [PATCH 189/260] Update README and requirements.txt to update installations without conda. Simply running pip install on the devel version of schematic should work. --- README.md | 4 +- requirements.txt | 329 ++++++----------------------------------------- 2 files changed, 43 insertions(+), 290 deletions(-) diff --git a/README.md b/README.md index 3521b753..3a4d5cab 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ the installation script provided. git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git -2. Install the latest release of the `schematic` via `pip`: +2. Install the latest release of the `schematic` via `pip`. IF NOT USING CONDA, install the devel version below: python -m pip install schematicpy @@ -64,7 +64,7 @@ the installation script provided. 3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) -4. If not using a conda environment. Install the required dependencies. +4. If not using a conda environment. Install the required dependencies. Skip this step if not using conda. pip install -r requirements.txt diff --git a/requirements.txt b/requirements.txt index ac9f738c..58929685 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,308 +1,61 @@ -alabaster==0.7.12 -anaconda-client==1.9.0 -anaconda-navigator==2.1.1 -anaconda-project==0.10.1 -anyio==2.2.0 -appdirs==1.4.4 -argh==0.26.2 -argon2-cffi==20.1.0 -arrow==0.13.1 -asn1crypto==1.4.0 -astroid==2.6.6 -astropy==4.3.1 -async-generator==1.10 -atomicwrites==1.4.0 -attrs==21.2.0 -autopep8==1.5.7 -Babel==2.9.1 -backcall==0.2.0 -backports.functools-lru-cache==1.6.4 -backports.shutil-get-terminal-size==1.0.0 -backports.tempfile==1.0 -backports.weakref==1.0.post1 -beautifulsoup4==4.10.0 -binaryornot==0.4.4 -bitarray==2.3.0 -bkcharts==0.2 -black==19.10b0 -bleach==4.0.0 -bokeh==2.4.1 -boto==2.49.0 -Bottleneck==1.3.2 -brotlipy==0.7.0 -cached-property==1.5.2 -cachetools==4.2.4 -certifi==2021.10.8 -cffi==1.14.6 -chardet==4.0.0 -charset-normalizer==2.0.4 -click==7.1.2 -click-log==0.3.2 -clickclick==20.10.2 -cloudpickle==2.0.0 -clyent==1.2.2 -colorama==0.4.4 -conda==4.10.3 -conda-build==3.21.5 -conda-content-trust==0+unknown -conda-pack==0.6.0 -conda-package-handling==1.7.3 -conda-repo-cli==1.0.4 -conda-token==0.3.0 -conda-verify==3.4.2 -connexion==2.9.0 -contextlib2==0.6.0.post1 -cookiecutter==1.7.2 -cryptography==3.4.8 -cycler==0.10.0 -Cython==0.29.24 -cytoolz==0.11.0 -daal4py==2021.3.0 -dask==2021.10.0 -debugpy==1.4.1 -decorator==5.1.0 -defusedxml==0.7.1 -Deprecated==1.2.13 -diff-match-patch==20200713 -distributed==2021.10.0 -docutils==0.17.1 +attrs==19.3.0 +cachetools==4.1.1 +certifi==2020.6.20 +cffi==1.14.0 +chardet==3.0.4 +click>=7.1.2 +click-log>=0.3.2 +cryptography==3.3.2 +decorator==4.4.2 +Deprecated==1.2.4 entrypoints==0.3 -et-xmlfile==1.1.0 -fastcache==1.1.0 -filelock==3.3.1 -flake8==3.9.2 -Flask==1.1.4 -fonttools==4.25.0 -fsspec==2021.8.1 -future==0.18.2 -gevent==21.8.0 -glob2==0.7 -gmpy2==2.0.8 -google-api-core==1.31.4 -google-api-python-client==1.12.8 -google-auth==1.35.0 -google-auth-httplib2==0.0.4 -google-auth-oauthlib==0.4.6 +fastjsonschema==2.14.4 +google-api-core==1.26.3 +google-api-python-client>=1.12.8 +google-auth>=1.19.1 +google-auth-httplib2>=0.0.4 +google-auth-oauthlib>=0.4.4 googleapis-common-protos==1.53.0 -graphviz==0.16 -greenlet==1.1.1 -h5py==3.3.0 -HeapDict==1.0.1 -html5lib==1.1 -httplib2==0.20.2 -idna==3.2 -imagecodecs==2021.8.26 -imageio==2.9.0 -imagesize==1.2.0 -importlib-metadata==4.8.1 +graphviz>=0.16 +httplib2==0.19.0 +idna==2.10 +importlib-metadata==1.7.0 inflection==0.5.1 -iniconfig==1.1.1 -intervaltree==3.1.0 -ipykernel==6.4.1 -ipython==7.29.0 -ipython-genutils==0.2.0 -ipywidgets==7.6.5 isodate==0.6.0 -isort==5.9.3 -itsdangerous==1.1.0 -jdcal==1.4.1 -jedi==0.18.0 -jeepney==0.7.1 -Jinja2==2.11.3 -jinja2-time==0.2.0 -joblib==1.1.0 -json5==0.9.6 jsonschema==3.2.0 -jupyter==1.0.0 -jupyter-client==6.1.12 -jupyter-console==6.4.0 -jupyter-core==4.8.1 -jupyter-server==1.4.1 -jupyterlab==3.2.1 -jupyterlab-pygments==0.1.2 -jupyterlab-server==2.8.2 -jupyterlab-widgets==1.0.0 keyring==12.0.2 keyrings.alt==3.1 -kiwisolver==1.3.1 -lazy-object-proxy==1.6.0 -libarchive-c==2.9 -llvmlite==0.37.0 -locket==0.2.1 -lxml==4.6.3 -MarkupSafe==1.1.1 -matplotlib==3.4.3 -matplotlib-inline==0.1.2 -mccabe==0.6.1 -mistune==0.8.4 -mkl-fft==1.3.1 -mkl-random==1.2.2 -mkl-service==2.4.0 -mock==4.0.3 -more-itertools==8.10.0 -mpmath==1.2.1 -msgpack==1.0.2 -multipledispatch==0.6.0 -munkres==1.1.4 -mypy-extensions==0.4.3 -navigator-updater==0.2.1 -nbclassic==0.2.6 -nbclient==0.5.3 -nbconvert==6.1.0 -nbformat==5.1.3 -nest-asyncio==1.5.1 -networkx==2.6.3 -nltk==3.6.5 -nose==1.3.7 -notebook==6.4.5 -numba==0.54.1 -numexpr==2.7.3 -numpy==1.20.3 -numpydoc==1.1.0 +networkx==2.5.1 +numpy==1.19.0 oauth2client==3.0.0 -oauthlib==3.1.1 -olefile==0.46 -openapi-schema-validator==0.1.5 -openapi-spec-validator==0.3.1 -openpyxl==3.0.9 -packaging==21.0 -pandas==1.3.4 -pandocfilters==1.4.3 -parso==0.8.2 -partd==1.2.0 -path==16.0.0 -pathlib2==2.3.6 -pathspec==0.7.0 -patsy==0.5.2 -pep8==1.7.1 -pexpect==4.8.0 -pickleshare==0.7.5 -Pillow==8.4.0 -pip==21.2.4 -pkginfo==1.7.1 -pluggy==0.13.1 -ply==3.11 -poyo==0.5.0 -prometheus-client==0.11.0 -prompt-toolkit==3.0.20 -protobuf==3.19.1 -psutil==5.8.0 -ptyprocess==0.7.0 -py==1.10.0 +oauthlib==3.1.0 +orderedset==2.0.1 +packaging==20.9 +pandas==1.2.3 +pip==21.1 +protobuf==3.15.7 pyasn1==0.4.8 pyasn1-modules==0.2.8 -pycodestyle==2.7.0 -pycosat==0.6.3 pycparser==2.20 -pycurl==7.44.1 -pydocstyle==6.1.1 -pyerfa==2.0.0 -pyflakes==2.3.1 -Pygments==2.10.0 pygsheets==2.0.5 -PyJWT==2.1.0 -pylint==2.9.6 -pyls-spyder==0.4.0 -pyodbc==4.0.0-unsupported -pyOpenSSL==21.0.0 -pyparsing==3.0.4 -pyrsistent==0.18.0 -PySocks==1.7.1 -pytest==6.2.4 -python-dateutil==2.8.2 -python-lsp-black==1.0.0 -python-lsp-jsonrpc==1.0.0 -python-lsp-server==1.2.4 -python-slugify==5.0.2 -pytz==2021.3 -PyWavelets==1.1.1 -pyxdg==0.27 +pyparsing==2.4.7 +pyrsistent==0.16.0 +python-dateutil==2.8.1 +pytz==2020.1 PyYAML==5.4.1 -pyzmq==22.2.1 -QDarkStyle==3.0.2 -qstylizer==0.1.10 -QtAwesome==1.0.2 -qtconsole==5.1.1 -QtPy==1.10.0 rdflib==5.0.0 -regex==2021.8.3 -requests==2.26.0 -requests-oauthlib==1.3.0 -rope==0.19.0 -rsa==4.8 -Rtree==0.9.7 -ruamel-yaml-conda==0.15.100 +requests>=2.24.0 +requests-oauthlib>=1.3.0 +rsa==4.7 schematicpy==1.0.0 -scikit-image==0.18.3 -scikit-learn==0.24.2 -scikit-learn-intelex==2021.20210714.170444 -scipy==1.7.1 -seaborn==0.11.2 SecretStorage==2.3.1 -Send2Trash==1.8.0 setuptools==52.0.0 -simplegeneric==0.8.1 -singledispatch==3.7.0 -sip==4.19.13 -six==1.16.0 -sniffio==1.2.0 -snowballstemmer==2.1.0 -sortedcollections==2.1.0 -sortedcontainers==2.4.0 -soupsieve==2.2.1 -Sphinx==4.2.0 -sphinxcontrib-applehelp==1.0.2 -sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==2.0.0 -sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 -sphinxcontrib-websupport==1.2.4 -spyder==5.1.5 -spyder-kernels==2.1.3 -SQLAlchemy==1.4.22 -statsmodels==0.12.2 -swagger-ui-bundle==0.0.9 -sympy==1.9 -synapseclient==2.5.0 -tables==3.6.1 -TBB==0.2 -tblib==1.7.0 -terminado==0.9.4 -testpath==0.5.0 -text-unidecode==1.3 -textdistance==4.2.1 -threadpoolctl==2.2.0 -three-merge==0.1.1 -tifffile==2021.7.2 -tinycss==0.4 +six==1.15.0 +synapseclient==2.5.1 +tabletext==0.1 toml==0.10.2 -toolz==0.11.1 -tornado==6.1 -tqdm==4.62.3 -traitlets==5.1.0 -typed-ast==1.4.3 -typing-extensions==3.10.0.2 -ujson==4.0.2 -unicodecsv==0.14.1 -Unidecode==1.2.0 uritemplate==3.0.1 -urllib3==1.26.7 -watchdog==2.1.3 -wcwidth==0.2.5 -webencodings==0.5.1 -Werkzeug==1.0.1 -wheel==0.37.0 -whichcraft==0.6.1 -widgetsnbextension==3.5.1 +urllib3==1.26.5 +wheel==0.34.2 wrapt==1.12.1 -wurlitzer==2.1.1 -xlrd==2.0.1 -XlsxWriter==3.0.1 -xlwt==1.3.0 -xmltodict==0.12.0 -yapf==0.31.0 -zict==2.0.0 -zipp==3.6.0 -zope.event==4.5.0 -zope.interface==5.4.0 +zipp==3.1.0 From c03fe648803dbd61d1a18df02696958fe867e198 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 16 Dec 2021 21:41:55 +0000 Subject: [PATCH 190/260] 1. improve highlight function to ensure highlight right position; 2. fix csvInfile function regarding replacing NA; --- functions/validationResult.R | 49 +++++++++++++------------ global.R | 1 + modules/DTable.R | 70 ++++++++++++++++++++---------------- modules/csvInfile.R | 4 +-- server.R | 6 ++-- 5 files changed, 70 insertions(+), 60 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index 62121037..79767c49 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -2,9 +2,9 @@ validationResult <- function(valRes, template, inFile) { validation_res <- NULL error_msg <- NULL help_msg <- NULL - outMsg <- NULL - errorDT <- NULL - errorType <- NULL + out_msg <- NULL + error_table <- NULL + error_type <- NULL if (!is.null(inFile) && !is.null(template) && length(inFile) != 0) { if (length(valRes) != 0) { @@ -26,7 +26,7 @@ validationResult <- function(valRes, template, inFile) { if (length(inx_mt) > 0) { # mismatched error(s): selected template mismatched with validating template - errorType <- "Mismatched Template" + error_type <- "Mismatched Template" # get all mismatched components error_values <- sapply(valRes[inx_mt], function(x) x[[4]][[1]]) %>% unique() @@ -47,32 +47,30 @@ validationResult <- function(valRes, template, inFile) { ) } else if (length(inx_ws) > 0) { # wrong schema error(s): validating metadata miss any required columns - errorType <- "Wrong Schema" + error_type <- "Wrong Schema" error_msg <- "The submitted metadata does not contain all required column(s)." help_msg <- "Please check that you used the correct template in the 'Get Metadata Template' tab and ensure your metadata contains all required columns." } else { - errorType <- "Invalid Value" + error_type <- "Invalid Value" error_msg <- paste0( "The submitted metadata have ", length(valRes), " errors." ) } - errorDT <- lapply(valRes, function(i) { - tibble( - Row = i[[1]], - Column = i[[2]], - Value = i[[4]][[1]], - Error = i[[3]] - ) %>% - # ensure highlight function to work - # convert to all characters since {inFile} in preview are all characters - mutate(across(everything(), as.character)) - }) %>% bind_rows() + # create table to display errors for users + error_table <- lapply(valRes, function(i) { + data.frame(Row = as.numeric(i[[1]]), Column = i[[2]], Value = i[[4]][[1]], Error = i[[3]]) + }) %>% bind_rows() + + # create list for hightlight function; key: error_column, value: error_value + highlight_values <- sapply(unique(error_table$Column), function(col) { + error_table$Value[error_table$Column == col] + }) # collapse similiar errors into one row - errorDT <- errorDT %>% + error_table <- error_table %>% mutate(Error = gsub(".*(not.*)\\.?$", "\\1", Error)) %>% group_by(Column, Error) %>% summarise( @@ -82,17 +80,17 @@ validationResult <- function(valRes, template, inFile) { ) %>% ungroup() %>% dplyr::select(Row, Column, Value, Error) - + # sort rows based on input column names - errorDT <- errorDT[order(match(errorDT$Column, colnames(inFile))), ] + error_table <- error_table[order(match(error_table$Column, colnames(inFile))), ] } else { validation_res <- "valid" - errorType <- "No Error" + error_type <- "No Error" } # combine all error messages into one, add an extra empty line to bottom - outMsg <- paste0(c( + out_msg <- paste0(c( paste0("Your metadata is ", validation_res, " !!!"), error_msg, help_msg ), collapse = "

") @@ -100,8 +98,9 @@ validationResult <- function(valRes, template, inFile) { return(list( validationRes = validation_res, - outMsg = outMsg, - errorDT = errorDT, - errorType = errorType + outMsg = out_msg, + errorDT = error_table, + errorHighlight = highlight_values, + errorType = error_type )) } diff --git a/global.R b/global.R index 04cdaba2..5b74b122 100644 --- a/global.R +++ b/global.R @@ -5,6 +5,7 @@ suppressPackageStartupMessages({ library(yaml) library(shinyjs) library(dplyr) + library(tidyr) library(shinythemes) library(shinydashboard) library(stringr) diff --git a/modules/DTable.R b/modules/DTable.R index eeb416a3..1f05403b 100644 --- a/modules/DTable.R +++ b/modules/DTable.R @@ -1,5 +1,14 @@ -# This moduel is to peformrender DT table function for preview/highlight - +#' This moduel is to wrap some of DT table functions, especially for hightlight functions +#' +#' @param id id name of this module +#' @param data a data object (either a matrix or a data frame) +#' @param rownames TRUE (show row names) or FALSE (hide row names) +#' @param caption a character vector or a tag object generated from \code{htmltools::tags$caption()} +#' @param filter whether/where to use column filters, either "none", "top" or "bottom" +#' @param options a list of initialization options (see https://datatables.net/reference/option/) +#' @param highlight whether to highlight cells in the table, either "full" (highlight entired table) or "partial" (highlight certain cells based on \code{highlightValues}) +#' @param highlightValues a list of values to be highlighted; each element of list following by key (column names) and value (a vector of values) +#' @return a reactive table DTableUI <- function(id) { ns <- NS(id) DT::DTOutput(ns("table")) @@ -8,38 +17,39 @@ DTableUI <- function(id) { DTableServer <- function(id, data, rownames = TRUE, caption = NULL, filter = "top", options = list(lengthChange = FALSE, scrollX = TRUE), - highlight = NULL, hightlight.col = NULL, hightlight.value = NULL) { - if (!is.null(highlight)) { - if (!highlight %in% c("full", "partial")) { - Stop("Please choose a value for highlight: 'full', 'partial'.") - } - - column <- hightlight.col - value <- hightlight.value - } - - df <- datatable(data, - caption = caption, - rownames = rownames, - filter = filter, - options = options - ) - - if (!is.null(highlight)) { - if (highlight == "full") { - df <- df %>% - formatStyle(1, target = "row", backgroundColor = "yellow") - } else if (highlight == "partial") { - df <- df %>% - formatStyle(column, backgroundColor = styleEqual( - value, rep("yellow", length(value)) - )) - } - } + highlight = NULL, highlightValues = NULL) { moduleServer( id, function(input, output, session) { + + df <- datatable(data, + caption = caption, + rownames = rownames, + filter = filter, + options = options + ) + + if (!is.null(highlight)) { + + match.arg(highlight, c("full", "partial")) + + if (highlight == "full") { + + df <- df %>% formatStyle(1, target = "row", backgroundColor = "yellow") + + } else if (highlight == "partial") { + + # iterate each col to avoid messing around same value in multiple columns + for (col in names(highlightValues)) { + + values <- highlightValues[[col]] + df <- df %>% + formatStyle(col, backgroundColor = styleEqual(values, rep("yellow", length(values)))) + } + } + } + output$table <- renderDT(df) } ) diff --git a/modules/csvInfile.R b/modules/csvInfile.R index 9c959e91..4aab24bc 100644 --- a/modules/csvInfile.R +++ b/modules/csvInfile.R @@ -28,8 +28,8 @@ csvInfileServer <- function(id, na = c("", "NA"), colsAsCharacters = FALSE, keep } if (keepBlank) { - # change NA to blank to match schema output) - infile <- infile %>% replace(., is.na(.), "") + # change NA to blank to match schematic output + infile <- infile %>% mutate(across(everything(), ~replace_na(., ""))) } # remove empty rows/columns where readr called it 'X'[digit] for unnamed col diff --git a/server.R b/server.R index 94834af1..81768f07 100644 --- a/server.R +++ b/server.R @@ -295,9 +295,9 @@ shinyServer(function(input, output, session) { if (valRes$errorType == "Wrong Schema") { DTableServer("tbl_preview", data = inFile$data(), highlight = "full") } else { - DTableServer("tbl_preview", - data = inFile$data(), - highlight = "partial", hightlight.col = valRes$errorDT$Column, hightlight.value = valRes$errorDT$Value + DTableServer( + "tbl_preview", data = inFile$data(), + highlight = "partial", highlightValues = valRes$errorHighlight ) } From 1ee19595f1c22f9f9be28d261ff0260a28d0a517 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 17:18:00 -0800 Subject: [PATCH 191/260] build schematic from Github --- .github/workflows/shinyapps_deploy.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index bd1e7d3e..58e79ca9 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -41,7 +41,11 @@ jobs: shell: bash run: | source "${{ env.CONDA_ENV_NAME }}"/bin/activate - pip3 install -r requirements.txt + git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git + cd schematic + poetry build + pip3 install dist/schematicpy-1.0.0-py3-none-any.whl + # This was the old way: pip3 install -r requirements.txt # where did the dependencies end up? Let's look for a couple: find / -name "*jeepney*" find / -name "*inflection*" From 6bcb6eb5de161d4bdb3c5c5c2413108724320bb4 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 17:18:43 -0800 Subject: [PATCH 192/260] build poetry branch --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 58e79ca9..e4d307f3 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -8,6 +8,7 @@ on: branches: - shiny-server-main - switch-python-venv + - poetry - release* jobs: From 2f508f4970cedf2ace94b1bb780d2d8d82665030 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 17:29:44 -0800 Subject: [PATCH 193/260] build poetry branch --- .github/workflows/shinyapps_deploy.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index e4d307f3..3091af08 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -41,7 +41,10 @@ jobs: - name: Install Python Dependencies shell: bash run: | - source "${{ env.CONDA_ENV_NAME }}"/bin/activate + source "${{ env.CONDA_ENV_NAME }}"/bin/activate + #wget -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py + #python3 get-poetry.py + pip3 install poetry git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git cd schematic poetry build From a2d190d454ca65ab10ae95ab835e8db0323ff0c3 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 18:18:58 -0800 Subject: [PATCH 194/260] remove dependency spot check --- .github/workflows/shinyapps_deploy.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3091af08..6abcda64 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -50,20 +50,10 @@ jobs: poetry build pip3 install dist/schematicpy-1.0.0-py3-none-any.whl # This was the old way: pip3 install -r requirements.txt - # where did the dependencies end up? Let's look for a couple: - find / -name "*jeepney*" - find / -name "*inflection*" - name: Install R packages run: | R -f install-pkgs.R - - - name: Spot check Python dependencies - shell: bash - run: | - # Could it be that the dependencies get lost between steps? - find / -name "*jeepney*" - find / -name "*inflection*" - name: Authorize and deploy app shell: Rscript {0} From 45966156084262693e27920908688d03ffe6cd87 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 18:43:08 -0800 Subject: [PATCH 195/260] zip/unzip venv --- .github/workflows/shinyapps_deploy.yml | 6 ++++++ global.R | 26 +++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 6abcda64..001e0ce6 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -54,6 +54,12 @@ jobs: - name: Install R packages run: | R -f install-pkgs.R + + - name: zip virtual env + shell: bash + run: | + zip -r "${{ env.CONDA_ENV_NAME }}".zip "${{ env.CONDA_ENV_NAME }}" + rm -r "${{ env.CONDA_ENV_NAME }}" - name: Authorize and deploy app shell: Rscript {0} diff --git a/global.R b/global.R index 87da0bcd..be2a1a18 100644 --- a/global.R +++ b/global.R @@ -1,8 +1,22 @@ +library(yaml) + +oauth_client <- yaml.load_file("config.yaml") + +client_id <- toString(oauth_client$CLIENT_ID) +client_secret <- toString(oauth_client$CLIENT_SECRET) +conda_name <- toString(oauth_client$CONDA_NAME) + +if (is.null(client_id) || nchar(client_id)==0) stop("config.yaml is missing CLIENT_ID") +if (is.null(client_secret) || nchar(client_secret)==0) stop("config.yaml is missing CLIENT_SECRET") +if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") + +# unzip .zip +utils::unzip(paste0(conda_name, ".zip")) + suppressPackageStartupMessages({ library(shiny) library(httr) library(rjson) - library(yaml) library(shinyjs) library(dplyr) library(shinythemes) @@ -29,11 +43,6 @@ has_auth_code <- function(params) { return(!is.null(params$code)) } -oauth_client <- yaml.load_file("config.yaml") - -client_id <- toString(oauth_client$CLIENT_ID) -client_secret <- toString(oauth_client$CLIENT_SECRET) - if (interactive()) { # for local development options(shiny.port = 8100) @@ -43,12 +52,7 @@ if (interactive()) { app_url <- toString(oauth_client$APP_URL) } -conda_name <- toString(oauth_client$CONDA_NAME) - -if (is.null(client_id) || nchar(client_id)==0) stop("config.yaml is missing CLIENT_ID") -if (is.null(client_secret) || nchar(client_secret)==0) stop("config.yaml is missing CLIENT_SECRET") if (is.null(app_url) || nchar(app_url)==0) stop("config.yaml is missing APP_URL") -if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") app <- oauth_app("shinysynapse", key = client_id, From 1995b58d5f18ee243d014ae164d618754bad825c Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 19:06:56 -0800 Subject: [PATCH 196/260] where did my venv go? --- global.R | 1 + 1 file changed, 1 insertion(+) diff --git a/global.R b/global.R index be2a1a18..00f0bc7f 100644 --- a/global.R +++ b/global.R @@ -12,6 +12,7 @@ if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CO # unzip .zip utils::unzip(paste0(conda_name, ".zip")) +message(sprintf("unzipped %s.zip to %s", conda_name, getwd())) suppressPackageStartupMessages({ library(shiny) From bb94a35d46d5d72c2d456601837e12a738a825d8 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 19:33:59 -0800 Subject: [PATCH 197/260] where did my venv go? --- global.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/global.R b/global.R index 00f0bc7f..7bc05c71 100644 --- a/global.R +++ b/global.R @@ -13,6 +13,12 @@ if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CO # unzip .zip utils::unzip(paste0(conda_name, ".zip")) message(sprintf("unzipped %s.zip to %s", conda_name, getwd())) +message(paste(dir(), collapse="\n")) +# Activate conda env +# Don't necessarily have to set `RETICULATE_PYTHON` env variable +Sys.unsetenv("RETICULATE_PYTHON") +reticulate::use_virtualenv(file.path(getwd(),conda_name)) + suppressPackageStartupMessages({ library(shiny) @@ -90,11 +96,6 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" -# Activate conda env -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -Sys.unsetenv("RETICULATE_PYTHON") -reticulate::use_virtualenv(conda_name) - # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) From 231c2088e235eb18bf40a11434528bed8c3b7123 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 20:04:56 -0800 Subject: [PATCH 198/260] where did reticulate go? --- global.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/global.R b/global.R index 7bc05c71..b800e8f6 100644 --- a/global.R +++ b/global.R @@ -17,6 +17,9 @@ message(paste(dir(), collapse="\n")) # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable Sys.unsetenv("RETICULATE_PYTHON") +d<-"/opt/R/4.1.2/lib/R/library/reticulate/config/" +message(sprintf("contents of %s:", d)) +message(paste(dir(d), collapse="\n")) reticulate::use_virtualenv(file.path(getwd(),conda_name)) From 2a65c23ea8fed626af5e2f5d7b04484b5a3ed21b Mon Sep 17 00:00:00 2001 From: bhoff Date: Sat, 18 Dec 2021 20:44:49 -0800 Subject: [PATCH 199/260] made all executable in venv --- global.R | 1 + 1 file changed, 1 insertion(+) diff --git a/global.R b/global.R index b800e8f6..ffe5182f 100644 --- a/global.R +++ b/global.R @@ -12,6 +12,7 @@ if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CO # unzip .zip utils::unzip(paste0(conda_name, ".zip")) +system(sprintf("chmod -R +x %s", conda_name)) message(sprintf("unzipped %s.zip to %s", conda_name, getwd())) message(paste(dir(), collapse="\n")) # Activate conda env From 06dc690f0c71534ca3bf9108e29389b85d53d8b8 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 06:21:42 -0800 Subject: [PATCH 200/260] add .jsonld file --- .github/workflows/shinyapps_deploy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 001e0ce6..7ecda36e 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -50,6 +50,10 @@ jobs: poetry build pip3 install dist/schematicpy-1.0.0-py3-none-any.whl # This was the old way: pip3 install -r requirements.txt + # + # This is to fix the error I see when the app starts up: + # No such file or directory: 'tests/data/example.model.jsonld' + cp -R schematic/tests/data/ tests/data/ - name: Install R packages run: | From 3bdd920a2bfe3ff919df3dc346b115a824898982 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 06:27:16 -0800 Subject: [PATCH 201/260] add .jsonld file --- .github/workflows/shinyapps_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 7ecda36e..3cc5374b 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -53,7 +53,7 @@ jobs: # # This is to fix the error I see when the app starts up: # No such file or directory: 'tests/data/example.model.jsonld' - cp -R schematic/tests/data/ tests/data/ + cp -R tests/data/ ../tests/data/ - name: Install R packages run: | From eafc75a1035605243086af8990ae60c789abb3b4 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 06:43:59 -0800 Subject: [PATCH 202/260] add .jsonld file --- .github/workflows/shinyapps_deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 3cc5374b..deddf376 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -53,7 +53,8 @@ jobs: # # This is to fix the error I see when the app starts up: # No such file or directory: 'tests/data/example.model.jsonld' - cp -R tests/data/ ../tests/data/ + mkdir -p ../tests/data/ + cp -R tests/data/ ../tests/ - name: Install R packages run: | From b78de27ad4e25000c86b0f544b1ddfd7306b1cf6 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 08:04:53 -0800 Subject: [PATCH 203/260] correct OAuth login --- global.R | 13 ++++++++----- server.R | 20 ++++++++++++++++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/global.R b/global.R index ffe5182f..a3883cae 100644 --- a/global.R +++ b/global.R @@ -10,17 +10,20 @@ if (is.null(client_id) || nchar(client_id)==0) stop("config.yaml is missing CLIE if (is.null(client_secret) || nchar(client_secret)==0) stop("config.yaml is missing CLIENT_SECRET") if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") +# ShinyAppys has a limit of 7000 files which this app' grossly exceeds +# due to its Python dependencies. To get around the limit we zip up +# the virtual environment before deployment and unzip it here. +# # unzip .zip utils::unzip(paste0(conda_name, ".zip")) +# +# We get a '126' error (non-executable) if we don't do this: system(sprintf("chmod -R +x %s", conda_name)) -message(sprintf("unzipped %s.zip to %s", conda_name, getwd())) -message(paste(dir(), collapse="\n")) + # Activate conda env # Don't necessarily have to set `RETICULATE_PYTHON` env variable Sys.unsetenv("RETICULATE_PYTHON") -d<-"/opt/R/4.1.2/lib/R/library/reticulate/config/" -message(sprintf("contents of %s:", d)) -message(paste(dir(d), collapse="\n")) + reticulate::use_virtualenv(file.path(getwd(),conda_name)) diff --git a/server.R b/server.R index 94834af1..71f809d2 100644 --- a/server.R +++ b/server.R @@ -21,6 +21,8 @@ shinyServer(function(input, output, session) { stop_for_status(req, task = "get an access token") token_response <- content(req, type = NULL) access_token <- token_response$access_token + + session$userData$access_token<-access_token ######## session global variables ######## source_python("functions/synapse_func_alias.py") @@ -54,12 +56,26 @@ shinyServer(function(input, output, session) { session$sendCustomMessage(type = "readCookie", message = list()) # initial loading page + # + # TODO: If we don't use cookies, then what event sbould trigger this? + # observeEvent(input$cookie, { # login and update session - syn_login(sessionToken = input$cookie, rememberMe = FALSE) + # + # The original code pulled the auth token from a cookie, but it + # should actually come from session$userData. The former is + # the Synapse login, only works when the Shiny app' is hosted + # in the synapse.org domain, and is unscoped. The latter will + # work in any domain and is scoped to the access required by the + # Shiny app' + # + access_token<-session$userData$access_token + message(sprintf("In server.R, cookie: %s access_token: %s", input$cookie, access_token)) + + syn_login(authToken = access_token, rememberMe = FALSE) # updating syn storage - tryCatch(synStore_obj <<- synapse_driver(token = input$cookie), error = function(e) NULL) + tryCatch(synStore_obj <<- synapse_driver(token = access_token), error = function(e) NULL) if (is.null(synStore_obj)) { message("'synapse_driver' fails, run 'synapse_driver' to see detailed error") From bc5ca8ea78731a35b91ac669530b4556c15eb362 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 08:35:56 -0800 Subject: [PATCH 204/260] fixed schematic Synapse login --- server.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index 71f809d2..3dd30b32 100644 --- a/server.R +++ b/server.R @@ -57,7 +57,7 @@ shinyServer(function(input, output, session) { # initial loading page # - # TODO: If we don't use cookies, then what event sbould trigger this? + # TODO: If we don't use cookies, then what event should trigger this? # observeEvent(input$cookie, { # login and update session @@ -75,7 +75,7 @@ shinyServer(function(input, output, session) { syn_login(authToken = access_token, rememberMe = FALSE) # updating syn storage - tryCatch(synStore_obj <<- synapse_driver(token = access_token), error = function(e) NULL) + tryCatch(synStore_obj <<- synapse_driver(access_token = access_token), error = function(e) NULL) if (is.null(synStore_obj)) { message("'synapse_driver' fails, run 'synapse_driver' to see detailed error") From 0da6bb31150a30c906a8030097e6e661eeaff096 Mon Sep 17 00:00:00 2001 From: bhoff Date: Sun, 19 Dec 2021 08:48:23 -0800 Subject: [PATCH 205/260] clean up --- .github/workflows/shinyapps_deploy.yml | 10 ++++++---- install-pkgs.R | 2 ++ server.R | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index deddf376..6b0cea08 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -42,16 +42,16 @@ jobs: shell: bash run: | source "${{ env.CONDA_ENV_NAME }}"/bin/activate - #wget -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py - #python3 get-poetry.py + # install 'poetry' and then use it to install 'schematic' pip3 install poetry git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git cd schematic poetry build pip3 install dist/schematicpy-1.0.0-py3-none-any.whl # This was the old way: pip3 install -r requirements.txt + # However, per Anthony Williams, "poetry will install all of the dependencies necessary for the app to run" # - # This is to fix the error I see when the app starts up: + # This is to fix the error we otherwise see when the app starts up: # No such file or directory: 'tests/data/example.model.jsonld' mkdir -p ../tests/data/ cp -R tests/data/ ../tests/ @@ -61,6 +61,9 @@ jobs: R -f install-pkgs.R - name: zip virtual env + # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies + # that this app' has. As a workaround we zip the virtual environment and later + # unzip it in 'global.R' shell: bash run: | zip -r "${{ env.CONDA_ENV_NAME }}".zip "${{ env.CONDA_ENV_NAME }}" @@ -91,7 +94,6 @@ jobs: writeLines(config, configFileConn), finally=close(configFileConn) ) - options("rsconnect.max.bundle.files"=200000) # 20x the default rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) \ No newline at end of file diff --git a/install-pkgs.R b/install-pkgs.R index 8706355c..d22d41fe 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -24,6 +24,8 @@ cran <- c( "png") gh <- "dreamRs/shinypop" + +# The binary package distributions from R Studio dramatically speed up installation time # For Ubuntu 18.04 (Bionic) it's https://packagemanager.rstudio.com/all/__linux__/bionic/latest # For Ubuntu 20.04 (Focal) it's https://packagemanager.rstudio.com/all/__linux__/focal/latest options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) diff --git a/server.R b/server.R index 3dd30b32..1065e205 100644 --- a/server.R +++ b/server.R @@ -70,7 +70,6 @@ shinyServer(function(input, output, session) { # Shiny app' # access_token<-session$userData$access_token - message(sprintf("In server.R, cookie: %s access_token: %s", input$cookie, access_token)) syn_login(authToken = access_token, rememberMe = FALSE) From 8bf1fd4113f8bfd8b9a39d4a5a3814bfe9a40750 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 28 Dec 2021 04:58:36 +0000 Subject: [PATCH 206/260] fix highlighting bug --- functions/validationResult.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/functions/validationResult.R b/functions/validationResult.R index 79767c49..ec1295ce 100644 --- a/functions/validationResult.R +++ b/functions/validationResult.R @@ -5,6 +5,7 @@ validationResult <- function(valRes, template, inFile) { out_msg <- NULL error_table <- NULL error_type <- NULL + highlight_values <- list() if (!is.null(inFile) && !is.null(template) && length(inFile) != 0) { if (length(valRes) != 0) { @@ -65,8 +66,8 @@ validationResult <- function(valRes, template, inFile) { }) %>% bind_rows() # create list for hightlight function; key: error_column, value: error_value - highlight_values <- sapply(unique(error_table$Column), function(col) { - error_table$Value[error_table$Column == col] + lapply(unique(error_table$Column), function(col) { + highlight_values[[col]] <<- error_table$Value[error_table$Column == col] }) # collapse similiar errors into one row From e0121ebcc7ee8c3b9fb9164ec68d4b2647b36443 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 20:24:53 +0000 Subject: [PATCH 207/260] deprecate conda env --- .Rprofile | 8 +++--- .github/workflows/shinyapps_deploy.yml | 29 ++++++++++------------ README.md | 29 +++++----------------- example_config.yaml | 2 -- global.R | 34 ++++++++------------------ 5 files changed, 34 insertions(+), 68 deletions(-) diff --git a/.Rprofile b/.Rprofile index ae148566..fb7200db 100644 --- a/.Rprofile +++ b/.Rprofile @@ -6,7 +6,9 @@ ) ) } - +# no needed if R >= 4.0.0 options(stringsAsFactors = FALSE) -#source("renv/activate.R") -Sys.setenv("RETICULATE_PYTHON" = "env/bin/python") + +# for local development +# change port number associated with your client, here +if (interactive()) options(shiny.port = 8100) \ No newline at end of file diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 6b0cea08..7e41fa2a 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -17,7 +17,6 @@ jobs: # This image seems to be based on rocker/r-ver which in turn is based on debian container: rocker/rstudio env: - CONDA_ENV_NAME: virtual_env # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. GITHUB_PAT: ${{ secrets.REPO_PAT }} @@ -26,7 +25,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev - + - uses: actions/checkout@v2 - uses: r-lib/actions/setup-pandoc@v1 @@ -34,14 +33,14 @@ jobs: - name: Create and Activate Python Virtual Environment shell: bash run: | - python3 -m venv "${{ env.CONDA_ENV_NAME }}" - chmod 755 "${{ env.CONDA_ENV_NAME }}"/bin/activate - source "${{ env.CONDA_ENV_NAME }}"/bin/activate - + python3 -m venv .venv + chmod 755 .venv/bin/activate + source .venv/bin/activate + - name: Install Python Dependencies shell: bash run: | - source "${{ env.CONDA_ENV_NAME }}"/bin/activate + source .venv/bin/activate # install 'poetry' and then use it to install 'schematic' pip3 install poetry git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git @@ -55,20 +54,20 @@ jobs: # No such file or directory: 'tests/data/example.model.jsonld' mkdir -p ../tests/data/ cp -R tests/data/ ../tests/ - + - name: Install R packages run: | R -f install-pkgs.R - + - name: zip virtual env # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies # that this app' has. As a workaround we zip the virtual environment and later # unzip it in 'global.R' shell: bash run: | - zip -r "${{ env.CONDA_ENV_NAME }}".zip "${{ env.CONDA_ENV_NAME }}" - rm -r "${{ env.CONDA_ENV_NAME }}" - + zip -r .venv.zip .venv + rm -r .venv + - name: Authorize and deploy app shell: Rscript {0} run: | @@ -81,14 +80,13 @@ jobs: rsConnectUser <-"${{ secrets.RSCONNECT_USER }}" rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" rsConnectSecret <- "${{ secrets.RSCONNECT_SECRET }}" - + # create config file config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") appUrl<- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) config <- c(config, sprintf("APP_URL: %s", appUrl)) - config <- c(config, "CONDA_NAME: ${{ env.CONDA_ENV_NAME }}") - + configFileConn<-file("config.yaml") tryCatch( writeLines(config, configFileConn), @@ -96,4 +94,3 @@ jobs: ) rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) - \ No newline at end of file diff --git a/README.md b/README.md index ed228ea6..fa59dfd9 100644 --- a/README.md +++ b/README.md @@ -23,28 +23,15 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor - `CLIENT_ID` and `CLIENT_SECRET`: [how to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication) - `APP_URL`: the redirection url to your app - - `CONDA_NAME`: conda environment name -3. Create and activate the conda environment or virtualenv: +3. Create and activate a virtual environment within which you can install the package: - export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''" ') - conda env create -f environment.yml -n $CONDA_NAME - conda activate $CONDA_NAME + python -m venv .venv + source .venv/bin/activate - Or if using virtualenv +4. Install required R pacakges dependencies. - export CONDA_NAME=$(tail -n1 config.yaml | cut -f2 -d':' | tr -d \''"') - python -m venv $CONDA_NAME - source "$CONDA_NAME"/bin/activate - -4. Install required R pacakges dependencies. SKIP THIS IF NOT USING A CONDA ENVIRONMENT: - - R -e "renv::restore()" - -4a. If not using a conda environment nor renv, install the necessary packages using -the installation script provided. - - R -f install-pkgs.R + R -f install-pkgs.R ### Schematic Setup @@ -60,14 +47,10 @@ the installation script provided. cd schematic poetry build - pip install dist/schematicpy-*-py3-none-any.whl + pip install dist/schematicpy-1.0.0-py3-none-any.whl 3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) -4. If not using a conda environment. Install the required dependencies. Skip this step if not using conda. - - pip install -r requirements.txt - ### Data Model Configuration Use the app configuration file `www/config.json` to adapt this app to your DCC. diff --git a/example_config.yaml b/example_config.yaml index 4ffa4f16..aa7431c4 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -7,5 +7,3 @@ CLIENT_SECRET: '' # url of your deployed app # for local testing, change port based on your OAuth Client's redirect_uri, e.g. https://localhost:8100/ APP_URL: '' -# change the conda environment name here, this must be the last line -CONDA_NAME: 'data_curator_env' diff --git a/global.R b/global.R index fee40b92..b44c1787 100644 --- a/global.R +++ b/global.R @@ -1,31 +1,25 @@ -library(yaml) - -oauth_client <- yaml.load_file("config.yaml") - +oauth_client <- yaml::yaml.load_file("config.yaml") client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) -conda_name <- toString(oauth_client$CONDA_NAME) -if (is.null(client_id) || nchar(client_id)==0) stop("config.yaml is missing CLIENT_ID") -if (is.null(client_secret) || nchar(client_secret)==0) stop("config.yaml is missing CLIENT_SECRET") -if (is.null(conda_name) || nchar(conda_name)==0) stop("config.yaml is missing CONDA_ENV_NAME") +if (is.null(client_id) || nchar(client_id) == 0) stop("config.yaml is missing CLIENT_ID") +if (is.null(client_secret) || nchar(client_secret) == 0) stop("config.yaml is missing CLIENT_SECRET") +if (is.null(app_url) || nchar(app_url) == 0) stop("config.yaml is missing APP_URL") # ShinyAppys has a limit of 7000 files which this app' grossly exceeds # due to its Python dependencies. To get around the limit we zip up # the virtual environment before deployment and unzip it here. # -# unzip .zip -utils::unzip(paste0(conda_name, ".zip")) +# unzip virtual environment, named as ".venv.zip" +utils::unzip(".venv.zip") # # We get a '126' error (non-executable) if we don't do this: -system(sprintf("chmod -R +x %s", conda_name)) +system("chmod -R +x .venv") -# Activate conda env +# Activate virtual env # Don't necessarily have to set `RETICULATE_PYTHON` env variable Sys.unsetenv("RETICULATE_PYTHON") - -reticulate::use_virtualenv(file.path(getwd(),conda_name)) - +reticulate::use_virtualenv(file.path(getwd(), ".venv")) suppressPackageStartupMessages({ library(shiny) @@ -58,14 +52,6 @@ has_auth_code <- function(params) { return(!is.null(params$code)) } -if (interactive()) { - # for local development - # change port number associated with your client, here - options(shiny.port = 8100) -} - -if (is.null(app_url) || nchar(app_url)==0) stop("config.yaml is missing APP_URL") - app <- oauth_app("shinysynapse", key = client_id, secret = client_secret, @@ -107,4 +93,4 @@ sapply(source_files, FUN = source) # Global variables datatypes <- c("project", "folder", "template") -options(sass.cache = FALSE) +options(sass.cache = FALSE) \ No newline at end of file From c3ff18cbba45597411b4e08d945fcf42885d3b41 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 20:28:29 +0000 Subject: [PATCH 208/260] add app_url that is missing --- global.R | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/global.R b/global.R index b44c1787..eed86cbf 100644 --- a/global.R +++ b/global.R @@ -1,6 +1,13 @@ +suppressPackageStartupMessages({ + library(yaml) + library(reticulate) +}) + oauth_client <- yaml::yaml.load_file("config.yaml") + client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) +app_url <- toString(oauth_client$APP_URL) if (is.null(client_id) || nchar(client_id) == 0) stop("config.yaml is missing CLIENT_ID") if (is.null(client_secret) || nchar(client_secret) == 0) stop("config.yaml is missing CLIENT_SECRET") @@ -33,7 +40,6 @@ suppressPackageStartupMessages({ library(stringr) library(DT) library(jsonlite) - library(reticulate) library(ggplot2) library(purrr) library(plotly) From 31abbe2513c0453d01f8bdce0cf9b185f836c802 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 20:39:01 +0000 Subject: [PATCH 209/260] not unzip for .venv exists for local testing --- .github/workflows/shinyapps_deploy.yml | 3 +-- global.R | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 7e41fa2a..0bf43acb 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -65,8 +65,7 @@ jobs: # unzip it in 'global.R' shell: bash run: | - zip -r .venv.zip .venv - rm -r .venv + zip -rm .venv.zip .venv - name: Authorize and deploy app shell: Rscript {0} diff --git a/global.R b/global.R index eed86cbf..cd3ca60c 100644 --- a/global.R +++ b/global.R @@ -18,8 +18,8 @@ if (is.null(app_url) || nchar(app_url) == 0) stop("config.yaml is missing APP_UR # the virtual environment before deployment and unzip it here. # # unzip virtual environment, named as ".venv.zip" -utils::unzip(".venv.zip") -# +if (!file.exists(".venv")) utils::unzip(".venv.zip") + # We get a '126' error (non-executable) if we don't do this: system("chmod -R +x .venv") From dc15f86f7c9936127cbf765d64f9ada8db226433 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 20:48:19 +0000 Subject: [PATCH 210/260] update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa59dfd9..0c86c121 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 2. Create and modify the configuration file: +- `CLIENT_ID` and `CLIENT_SECRET`: [how to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication) +- `APP_URL`: the redirection url to your app + cp example_config.yaml config.yaml chmod 400 config.yaml - - `CLIENT_ID` and `CLIENT_SECRET`: [how to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication) - - `APP_URL`: the redirection url to your app - 3. Create and activate a virtual environment within which you can install the package: python -m venv .venv @@ -49,7 +49,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor poetry build pip install dist/schematicpy-1.0.0-py3-none-any.whl -3. Set up the `schematic` configuration. To do so, follow the instructions on the `schematic` repository [README](https://github.com/Sage-Bionetworks/schematic/tree/develop#12-installation-requirements-and-pre-requisites) +3. Set up the `schematic` configuration. To do so, follow the instructions on the [schematic's documentation](https://sage-schematic.readthedocs.io/en/develop/index.html#package-installation-and-setup) ### Data Model Configuration From 317713ab90796758bb89dbed80c40ff2ad22b1ec Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 20:52:52 +0000 Subject: [PATCH 211/260] fix styler --- .Rprofile | 2 +- .github/workflows/shinyapps_deploy.yml | 12 ++++----- global.R | 2 +- server.R | 35 ++++++++++++++------------ 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/.Rprofile b/.Rprofile index fb7200db..67a0dad3 100644 --- a/.Rprofile +++ b/.Rprofile @@ -11,4 +11,4 @@ options(stringsAsFactors = FALSE) # for local development # change port number associated with your client, here -if (interactive()) options(shiny.port = 8100) \ No newline at end of file +if (interactive()) options(shiny.port = 8100) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 0bf43acb..764d2d84 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -70,23 +70,23 @@ jobs: - name: Authorize and deploy app shell: Rscript {0} run: | - branch<-Sys.getenv("GITHUB_REF_NAME") - repo<-Sys.getenv("GITHUB_REPOSITORY") - appName<-strsplit(repo, "/")[[1]][2] + branch <- Sys.getenv("GITHUB_REF_NAME") + repo <- Sys.getenv("GITHUB_REPOSITORY") + appName <- strsplit(repo, "/")[[1]][2] if (!startsWith(branch, "release")) { appName <- paste(appName, "staging", sep="-") } - rsConnectUser <-"${{ secrets.RSCONNECT_USER }}" + rsConnectUser <- "${{ secrets.RSCONNECT_USER }}" rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" rsConnectSecret <- "${{ secrets.RSCONNECT_SECRET }}" # create config file config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") - appUrl<- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) + appUrl <- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) config <- c(config, sprintf("APP_URL: %s", appUrl)) - configFileConn<-file("config.yaml") + configFileConn <- file("config.yaml") tryCatch( writeLines(config, configFileConn), finally=close(configFileConn) diff --git a/global.R b/global.R index cd3ca60c..21534dee 100644 --- a/global.R +++ b/global.R @@ -99,4 +99,4 @@ sapply(source_files, FUN = source) # Global variables datatypes <- c("project", "folder", "template") -options(sass.cache = FALSE) \ No newline at end of file +options(sass.cache = FALSE) diff --git a/server.R b/server.R index 00527937..d8342320 100644 --- a/server.R +++ b/server.R @@ -21,8 +21,8 @@ shinyServer(function(input, output, session) { stop_for_status(req, task = "get an access token") token_response <- content(req, type = NULL) access_token <- token_response$access_token - - session$userData$access_token<-access_token + + session$userData$access_token <- access_token ######## session global variables ######## source_python("functions/synapse_func_alias.py") @@ -56,33 +56,33 @@ shinyServer(function(input, output, session) { session$sendCustomMessage(type = "readCookie", message = list()) # initial loading page - # + # # TODO: If we don't use cookies, then what event should trigger this? # observeEvent(input$cookie, { # login and update session # # The original code pulled the auth token from a cookie, but it - # should actually come from session$userData. The former is + # should actually come from session$userData. The former is # the Synapse login, only works when the Shiny app' is hosted # in the synapse.org domain, and is unscoped. The latter will - # work in any domain and is scoped to the access required by the + # work in any domain and is scoped to the access required by the # Shiny app' # - access_token<-session$userData$access_token - + access_token <- session$userData$access_token + syn_login(authToken = access_token, rememberMe = FALSE) - + # updating syn storage tryCatch(synStore_obj <<- synapse_driver(access_token = access_token), error = function(e) NULL) - + if (is.null(synStore_obj)) { message("'synapse_driver' fails, run 'synapse_driver' to see detailed error") dcWaiter("update", landing = TRUE, isPermission = FALSE) } else { projects_list <- synapse_driver$getStorageProjects(synStore_obj) datatype_list$projects <<- list2Vector(projects_list) - + # updates project dropdown lapply(c("header_dropdown_", "dropdown_"), function(x) { lapply(c(1, 3), function(i) { @@ -229,11 +229,14 @@ shinyServer(function(input, output, session) { # loading screen for template link generation dcWaiter("show", msg = "Generating link...") - + manifest_url <- metadata_model$getModelManifest(paste0(config$community, " ", input$dropdown_template), template_schema_name(), - filenames = switch((template_type == "assay") + 1, NULL, as.list(names(datatype_list$files))), + filenames = switch((template_type == "assay") + 1, + NULL, + as.list(names(datatype_list$files)) + ), datasetId = folder_synID() ) @@ -272,7 +275,7 @@ shinyServer(function(input, output, session) { ######## Validation Section ####### observeEvent(input$btn_validate, { - + # loading screen for validating metadata dcWaiter("show", msg = "Validating...") @@ -311,7 +314,8 @@ shinyServer(function(input, output, session) { DTableServer("tbl_preview", data = inFile$data(), highlight = "full") } else { DTableServer( - "tbl_preview", data = inFile$data(), + "tbl_preview", + data = inFile$data(), highlight = "partial", highlightValues = valRes$errorHighlight ) } @@ -397,7 +401,7 @@ shinyServer(function(input, output, session) { synStore_obj, "./tmp/synapse_storage_manifest.csv", folder_synID() ) - manifest_path <- tags$a(href = paste0("synapse.org/#!Synapse:", manifest_id), manifest_id, target = "_blank") + manifest_path <- tags$a(href = paste0("synapse.org/#!Synapse:", manifest_id), manifest_id, target = "_blank") # if no error if (startsWith(manifest_id, "syn") == TRUE) { @@ -408,7 +412,6 @@ shinyServer(function(input, output, session) { sapply(clean_tags, FUN = hide) reset("inputFile-file") DTableServer("tbl_preview", data.frame(NULL)) - } else { dcWaiter("update", msg = HTML(paste0( "Uh oh, looks like something went wrong!", From 648c24aedeba2469d01264cf07690535751d144a Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 21:02:30 +0000 Subject: [PATCH 212/260] remove unused pkgs --- global.R | 8 ++------ install-pkgs.R | 45 +++++++++++++++++++++------------------------ 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/global.R b/global.R index 21534dee..830adcf2 100644 --- a/global.R +++ b/global.R @@ -3,7 +3,7 @@ suppressPackageStartupMessages({ library(reticulate) }) -oauth_client <- yaml::yaml.load_file("config.yaml") +oauth_client <- yaml.load_file("config.yaml") client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) @@ -31,7 +31,6 @@ reticulate::use_virtualenv(file.path(getwd(), ".venv")) suppressPackageStartupMessages({ library(shiny) library(httr) - library(rjson) library(shinyjs) library(dplyr) library(tidyr) @@ -40,9 +39,6 @@ suppressPackageStartupMessages({ library(stringr) library(DT) library(jsonlite) - library(ggplot2) - library(purrr) - library(plotly) library(shinypop) library(waiter) library(readr) @@ -99,4 +95,4 @@ sapply(source_files, FUN = source) # Global variables datatypes <- c("project", "folder", "template") -options(sass.cache = FALSE) +options(sass.cache = FALSE) \ No newline at end of file diff --git a/install-pkgs.R b/install-pkgs.R index d22d41fe..d8a72650 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -1,27 +1,24 @@ cran <- c( -"ellipsis", -"shiny", -"httr", -"rjson", -"yaml", -"shinyjs", -"dplyr", -"shinythemes", -"shinydashboard", -"stringr", -"DT", -"jsonlite", -"reticulate", -"ggplot2", -"purrr", -"plotly", -"shinydashboardPlus", -"waiter", -"readr", -"sass", -"remotes", -"rsconnect", -"png") + "ellipsis", + "shiny", + "httr", + "yaml", + "shinyjs", + "dplyr", + "shinythemes", + "shinydashboard", + "stringr", + "DT", + "jsonlite", + "reticulate", + "shinydashboardPlus", + "waiter", + "readr", + "sass", + "remotes", + "rsconnect", + "png" +) gh <- "dreamRs/shinypop" @@ -30,4 +27,4 @@ gh <- "dreamRs/shinypop" # For Ubuntu 20.04 (Focal) it's https://packagemanager.rstudio.com/all/__linux__/focal/latest options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) install.packages(cran) -remotes::install_github(gh) +remotes::install_github(gh) \ No newline at end of file From 8f1c0061b0fec0aa1c1b845c3ad2ad46ecc1470b Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 21:18:40 +0000 Subject: [PATCH 213/260] fix icon to match latest shiny --- ui.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui.R b/ui.R index 46ec9d30..0b5c09c8 100644 --- a/ui.R +++ b/ui.R @@ -21,7 +21,7 @@ ui <- shinydashboardPlus::dashboardPage( dropdownBlock( id = "header_selection_dropdown", title = "Selection", - icon = icon("sliders"), + icon = icon("sliders-h"), badgeStatus = "info", fluidRow( lapply(datatypes, function(x) { @@ -241,4 +241,4 @@ uiFunc <- function(req) { } else { ui } -} +} \ No newline at end of file From e37edcb805c355ff50023ef8c73857e6cf5e0945 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 7 Jan 2022 21:51:19 +0000 Subject: [PATCH 214/260] remove renv and conda env setup files --- environment.yml | 89 ------ renv.lock | 713 ---------------------------------------------- renv/.gitignore | 3 - renv/activate.R | 349 ----------------------- renv/settings.dcf | 6 - requirements.txt | 61 ---- 6 files changed, 1221 deletions(-) delete mode 100644 environment.yml delete mode 100644 renv.lock delete mode 100644 renv/.gitignore delete mode 100644 renv/activate.R delete mode 100644 renv/settings.dcf delete mode 100644 requirements.txt diff --git a/environment.yml b/environment.yml deleted file mode 100644 index f9d46597..00000000 --- a/environment.yml +++ /dev/null @@ -1,89 +0,0 @@ -channels: - - defaults -dependencies: - - _libgcc_mutex=0.1 - - ca-certificates=2020.6.24=0 - - cairo=1.14.12 - - certifi=2020.6.20=py37_0 - - expat=2.2.9 - - fontconfig=2.12.6 - - freetype=2.8 - - fribidi=1.0.9 - - glib=2.65.0 - - graphite2=1.3.14 - - graphviz=2.40.1 - - harfbuzz=1.7.6 - - icu=58.2 - - jpeg=9b - - libedit=3.1.20191231 - - libffi=3.3 - - libpng=1.6.37 - - libtiff=4.1.0 - - libtool=2.4.6 - - libxml2=2.9.10 - - lz4-c=1.9.2 - - ncurses=6.2 - - openssl=1.1.1g - - pango=1.42.0 - - pcre=8.44 - - pip=20.1.1=py37_1 - - pixman=0.40.0 - - python=3.7.7 - - python-graphviz=0.8.4=py37_1 - - readline=8.0 - - setuptools=47.3.1=py37_0 - - sqlite=3.32.3 - - tk=8.6.10 - - wheel=0.34.2=py37_0 - - xz=5.2.5 - - zlib=1.2.11 - - zstd=1.4.5 - - pip: - - attrs==19.3.0 - - cachetools==4.1.1 - - cffi==1.14.0 - - chardet==3.0.4 - - cryptography==2.9.2 - - decorator==4.4.2 - - deprecated==1.2.4 - - entrypoints==0.3 - - fastjsonschema==2.14.4 - - google-api-python-client==1.7.9 - - google-auth==1.19.1 - - google-auth-httplib2==0.0.3 - - google-auth-oauthlib==0.4.0 - - httplib2==0.18.1 - - idna==2.10 - - importlib-metadata==1.7.0 - - inflection==0.3.1 - - isodate==0.6.0 - - jsonschema==3.2.0 - - keyring==12.0.2 - - keyrings-alt==3.1 - - networkx==2.4 - - numpy==1.19.0 - - oauth2client==4.1.3 - - oauthlib==3.1.0 - - orderedset==2.0.1 - - pandas==1.0.5 - - pyasn1==0.4.8 - - pyasn1-modules==0.2.8 - - pycparser==2.20 - - pygsheets==2.0.3.1 - - pyparsing==2.4.7 - - pyrsistent==0.16.0 - - python-dateutil==2.8.1 - - pytz==2020.1 - - rdflib==4.2.2 - - requests==2.24.0 - - requests-oauthlib==1.3.0 - - rsa==4.6 - - secretstorage==2.3.1 - - six==1.15.0 - - synapseclient==2.1.0 - - tabletext==0.1 - - uritemplate==3.0.1 - - urllib3==1.25.9 - - wrapt==1.12.1 - - zipp==3.1.0 - - pyyaml==5.3.1 diff --git a/renv.lock b/renv.lock deleted file mode 100644 index abd0fcd5..00000000 --- a/renv.lock +++ /dev/null @@ -1,713 +0,0 @@ -{ - "R": { - "Version": "3.6.3", - "Repositories": [ - { - "Name": "CRAN", - "URL": "https://cran.rstudio.com" - }, - { - "Name": "Sage", - "URL": "http://ran.synapse.org" - } - ] - }, - "Packages": { - "BH": { - "Package": "BH", - "Version": "1.72.0-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f9ce74c6417d61f0782cbae5fd2b7b0" - }, - "DT": { - "Package": "DT", - "Version": "0.18", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a7d6660c869d4f41f856504828af4645" - }, - "MASS": { - "Package": "MASS", - "Version": "7.3-51.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1dad32ac9dbd8057167b2979fb932ff7" - }, - "Matrix": { - "Package": "Matrix", - "Version": "1.2-18", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08588806cba69f04797dab50627428ed" - }, - "R6": { - "Package": "R6", - "Version": "2.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "292b54f8f4b94669b08f94e5acce6be2" - }, - "RColorBrewer": { - "Package": "RColorBrewer", - "Version": "1.1-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e031418365a7f7a766181ab5a41a5716" - }, - "Rcpp": { - "Package": "Rcpp", - "Version": "1.0.5", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "125dc7a0ed375eb68c0ce533b48d291f" - }, - "askpass": { - "Package": "askpass", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e8a22846fff485f0be3770c2da758713" - }, - "assertthat": { - "Package": "assertthat", - "Version": "0.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "50c838a310445e954bc13f26f26a6ecf" - }, - "backports": { - "Package": "backports", - "Version": "1.1.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3ef0eac19317fd03c0c854aed581d473" - }, - "base64enc": { - "Package": "base64enc", - "Version": "0.1-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "543776ae6848fde2f48ff3816d0628bc" - }, - "bslib": { - "Package": "bslib", - "Version": "0.2.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4830a372b241d78ed6f53731ee3023ac" - }, - "cachem": { - "Package": "cachem", - "Version": "1.0.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2703a46dcabfb902f10060b2bca9f708" - }, - "callr": { - "Package": "callr", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "643163a00cb536454c624883a10ae0bc" - }, - "cli": { - "Package": "cli", - "Version": "2.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ff0becff7bfdfe3f75d29aff8f3172dd" - }, - "clipr": { - "Package": "clipr", - "Version": "0.7.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08cf4045c149a0f0eaf405324c7495bd" - }, - "colorspace": { - "Package": "colorspace", - "Version": "1.4-1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6b436e95723d1f0e861224dd9b094dfb" - }, - "commonmark": { - "Package": "commonmark", - "Version": "1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0f22be39ec1d141fd03683c06f3a6e67" - }, - "crayon": { - "Package": "crayon", - "Version": "1.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0d57bc8e27b7ba9e45dba825ebc0de6b" - }, - "crosstalk": { - "Package": "crosstalk", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ae55f5d7c02f0ab43c58dd050694f2b4" - }, - "curl": { - "Package": "curl", - "Version": "4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2b7d10581cc730804e9ed178c8374bd6" - }, - "data.table": { - "Package": "data.table", - "Version": "1.12.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "cd711af60c47207a776213a368626369" - }, - "desc": { - "Package": "desc", - "Version": "1.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6c8fe8fa26a23b79949375d372c7b395" - }, - "digest": { - "Package": "digest", - "Version": "0.6.25", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f697db7d92b7028c4b3436e9603fb636" - }, - "dplyr": { - "Package": "dplyr", - "Version": "1.0.5", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d0d76c11ec807eb3f000eba4e3eb0f68" - }, - "ellipsis": { - "Package": "ellipsis", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" - }, - "evaluate": { - "Package": "evaluate", - "Version": "0.14", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" - }, - "fansi": { - "Package": "fansi", - "Version": "0.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7fce217eaaf8016e72065e85c73027b5" - }, - "farver": { - "Package": "farver", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "dad6793a5a1f73c8e91f1a1e3e834b05" - }, - "fastmap": { - "Package": "fastmap", - "Version": "1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "83ab58a0518afe3d17e41da01af13b60" - }, - "fresh": { - "Package": "fresh", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fa54367040deb4537da49b7ac0ee5770" - }, - "fs": { - "Package": "fs", - "Version": "1.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "44594a07a42e5f91fac9f93fda6d0109" - }, - "generics": { - "Package": "generics", - "Version": "0.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8cff1d1391fd1ad8b65877f4c7f2e53" - }, - "ggplot2": { - "Package": "ggplot2", - "Version": "3.3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3eb6477d01eb5bbdc03f7d5f70f2733e" - }, - "glue": { - "Package": "glue", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f43e0d5e85ccb0a4045670c0607ee504" - }, - "gtable": { - "Package": "gtable", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ac5c6baf7822ce8732b343f14c072c4d" - }, - "hms": { - "Package": "hms", - "Version": "0.5.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "726671f634529d470545f9fd1a9d1869" - }, - "htmltools": { - "Package": "htmltools", - "Version": "0.5.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "af2c2531e55df5cf230c4b5444fc973c" - }, - "htmlwidgets": { - "Package": "htmlwidgets", - "Version": "1.5.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6fdaa86d0700f8b3e92ee3c445a5a10d" - }, - "httpuv": { - "Package": "httpuv", - "Version": "1.5.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4e6dabb220b006ccdc3b3b5ff993b205" - }, - "httr": { - "Package": "httr", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7146fea4685b4252ebf478978c75f597" - }, - "isoband": { - "Package": "isoband", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" - }, - "jquerylib": { - "Package": "jquerylib", - "Version": "0.1.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5aab57a3bd297eee1c1d862735972182" - }, - "jsonlite": { - "Package": "jsonlite", - "Version": "1.7.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "98138e0994d41508c7a6b84a0600cfcb" - }, - "labeling": { - "Package": "labeling", - "Version": "0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "73832978c1de350df58108c745ed0e3e" - }, - "later": { - "Package": "later", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d0a62b247165aabf397fded504660d8a" - }, - "lattice": { - "Package": "lattice", - "Version": "0.20-41", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fbd9285028b0263d76d18c95ae51a53d" - }, - "lazyeval": { - "Package": "lazyeval", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d908914ae53b04d4c0c0fd72ecc35370" - }, - "lifecycle": { - "Package": "lifecycle", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3471fb65971f1a7b2d4ae7848cf2db8d" - }, - "magrittr": { - "Package": "magrittr", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "41287f1ac7d28a92f0a286ed507928d3" - }, - "mgcv": { - "Package": "mgcv", - "Version": "1.8-31", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bb7e0c4f3557583e1e8d3c9ffb8ba5c" - }, - "mime": { - "Package": "mime", - "Version": "0.9", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e87a35ec73b157552814869f45a63aa3" - }, - "munsell": { - "Package": "munsell", - "Version": "0.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6dfe8bf774944bd5595785e3229d8771" - }, - "nlme": { - "Package": "nlme", - "Version": "3.1-148", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "662f52871983ff3e3ef042c62de126df" - }, - "openssl": { - "Package": "openssl", - "Version": "1.4.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b3209c62052922b6c629544d94c8fa8a" - }, - "pillar": { - "Package": "pillar", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "bdf26e55ccb7df3e49a490150277f002" - }, - "pkgbuild": { - "Package": "pkgbuild", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "404684bc4e3685007f9720adf13b06c1" - }, - "pkgconfig": { - "Package": "pkgconfig", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "01f28d4278f15c76cddbea05899c5d6f" - }, - "pkgload": { - "Package": "pkgload", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b6b150cd4709e0c0c9b5d51ac4376282" - }, - "plotly": { - "Package": "plotly", - "Version": "4.9.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f6b85d9e4ed88074ea0ede1aa74bb00e" - }, - "png": { - "Package": "png", - "Version": "0.1-7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "03b7076c234cb3331288919983326c55" - }, - "praise": { - "Package": "praise", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a555924add98c99d2f411e37e7d25e9f" - }, - "prettyunits": { - "Package": "prettyunits", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" - }, - "processx": { - "Package": "processx", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f4f13345fcb00c51ace12f65dd18749f" - }, - "promises": { - "Package": "promises", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a8730dcbdd19f9047774909f0ec214a4" - }, - "ps": { - "Package": "ps", - "Version": "1.3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "425d938eb9c02906a8ac98c0c2a306b5" - }, - "purrr": { - "Package": "purrr", - "Version": "0.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "97def703420c8ab10d8f0e6c72101e02" - }, - "rappdirs": { - "Package": "rappdirs", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8c8298583adbbe76f3c2220eef71bebc" - }, - "readr": { - "Package": "readr", - "Version": "1.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "af8ab99cd936773a148963905736907b" - }, - "renv": { - "Package": "renv", - "Version": "0.11.0-3", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "renv", - "RemoteUsername": "rstudio", - "RemoteRef": "master", - "RemoteSha": "caf0b39c883168cdd5ebd55a547f6d8689ab8712", - "Hash": "094b6d0b0fe28b14a6780dad836f6356" - }, - "reticulate": { - "Package": "reticulate", - "Version": "1.19", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a793719f1b17126b503feef01ce63410" - }, - "rjson": { - "Package": "rjson", - "Version": "0.2.20", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7d597f982ee6263716b6a2f28efd29fa" - }, - "rlang": { - "Package": "rlang", - "Version": "0.4.10", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "599df23c40a4fce9c7b4764f28c37857" - }, - "rprojroot": { - "Package": "rprojroot", - "Version": "1.3-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f6a407ae5dd21f6f80a6708bbb6eb3ae" - }, - "rstudioapi": { - "Package": "rstudioapi", - "Version": "0.11", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "33a5b27a03da82ac4b1d43268f80088a" - }, - "sass": { - "Package": "sass", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3ef1adfe46b7b144b970d74ce33ab0d6" - }, - "scales": { - "Package": "scales", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6f76f71042411426ec8df6c54f34e6dd" - }, - "shiny": { - "Package": "shiny", - "Version": "1.6.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6e3b6ae7fe02b5859e4bb277f218b8ae" - }, - "shinydashboard": { - "Package": "shinydashboard", - "Version": "0.7.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "133639dc106955eee4ffb8ec73edac37" - }, - "shinydashboardPlus": { - "Package": "shinydashboardPlus", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1abe63cd90fe33d3ca211525a0b39af9" - }, - "shinyjs": { - "Package": "shinyjs", - "Version": "2.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "9ddfc91d4280eaa34c2103951538976f" - }, - "shinypop": { - "Package": "shinypop", - "Version": "0.0.1.920", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "shinypop", - "RemoteUsername": "dreamRs", - "RemoteRef": "master", - "RemoteSha": "e3be83f99e85401c59ec7a1dfafa5c92c4f7367b", - "Hash": "095c2c667d27cd2f5829967a48e14229" - }, - "shinythemes": { - "Package": "shinythemes", - "Version": "1.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "30f0ebc41feba25691073626ff5e2cf4" - }, - "sourcetools": { - "Package": "sourcetools", - "Version": "0.1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "947e4e02a79effa5d512473e10f41797" - }, - "stringi": { - "Package": "stringi", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e99d8d656980d2dd416a962ae55aec90" - }, - "stringr": { - "Package": "stringr", - "Version": "1.4.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0759e6b6c0957edb1311028a49a35e76" - }, - "sys": { - "Package": "sys", - "Version": "3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "507f3116a38d37ad330a038b3be07b66" - }, - "testthat": { - "Package": "testthat", - "Version": "2.3.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0829b987b8961fb07f3b1b64a2fbc495" - }, - "tibble": { - "Package": "tibble", - "Version": "3.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08bd36bd34b20d4f7971d49e81deaab0" - }, - "tidyr": { - "Package": "tidyr", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7395a05640bf91502dd475a84008d87e" - }, - "tidyselect": { - "Package": "tidyselect", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6ea435c354e8448819627cf686f66e0a" - }, - "utf8": { - "Package": "utf8", - "Version": "1.1.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" - }, - "vctrs": { - "Package": "vctrs", - "Version": "0.3.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5cf1957f93076c19fdc81d01409d240b" - }, - "viridisLite": { - "Package": "viridisLite", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ce4f6271baa94776db692f1cb2055bee" - }, - "waiter": { - "Package": "waiter", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "58bd688fb765cf778b633df0e2502003" - }, - "withr": { - "Package": "withr", - "Version": "2.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ecd17882a0b4419545691e095b74ee89" - }, - "xtable": { - "Package": "xtable", - "Version": "1.8-4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" - }, - "yaml": { - "Package": "yaml", - "Version": "2.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2826c5d9efb0a88f657c7a679c7106db" - } - } -} diff --git a/renv/.gitignore b/renv/.gitignore deleted file mode 100644 index 82740ba9..00000000 --- a/renv/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -library/ -python/ -staging/ diff --git a/renv/activate.R b/renv/activate.R deleted file mode 100644 index 4184f5ff..00000000 --- a/renv/activate.R +++ /dev/null @@ -1,349 +0,0 @@ - -local({ - - # the requested version of renv - version <- "0.11.0-3" - - # the project directory - project <- getwd() - - # avoid recursion - if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) - return(invisible(TRUE)) - - # signal that we're loading renv during R startup - Sys.setenv("RENV_R_INITIALIZING" = "true") - on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) - - # signal that we've consented to use renv - options(renv.consent = TRUE) - - # load the 'utils' package eagerly -- this ensures that renv shims, which - # mask 'utils' packages, will come first on the search path - library(utils, lib.loc = .Library) - - # check to see if renv has already been loaded - if ("renv" %in% loadedNamespaces()) { - - # if renv has already been loaded, and it's the requested version of renv, - # nothing to do - spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") - if (identical(spec[["version"]], version)) - return(invisible(TRUE)) - - # otherwise, unload and attempt to load the correct version of renv - unloadNamespace("renv") - - } - - # load bootstrap tools - bootstrap <- function(version, library) { - - # read repos (respecting override if set) - repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (is.na(repos)) - repos <- getOption("repos") - - # fix up repos - on.exit(options(repos = repos), add = TRUE) - repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" - options(repos = repos) - - # attempt to download renv - tarball <- tryCatch(renv_bootstrap_download(version), error = identity) - if (inherits(tarball, "error")) - stop("failed to download renv ", version) - - # now attempt to install - status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) - if (inherits(status, "error")) - stop("failed to install renv ", version) - - } - - renv_bootstrap_download_impl <- function(url, destfile) { - - mode <- "wb" - - # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715 - fixup <- - Sys.info()[["sysname"]] == "Windows" && - substring(url, 1L, 5L) == "file:" - - if (fixup) - mode <- "w+b" - - download.file( - url = url, - destfile = destfile, - mode = mode, - quiet = TRUE - ) - - } - - renv_bootstrap_download <- function(version) { - - methods <- list( - renv_bootstrap_download_cran_latest, - renv_bootstrap_download_cran_archive, - renv_bootstrap_download_github - ) - - for (method in methods) { - path <- tryCatch(method(version), error = identity) - if (is.character(path) && file.exists(path)) - return(path) - } - - stop("failed to download renv ", version) - - } - - renv_bootstrap_download_cran_latest <- function(version) { - - # check for renv on CRAN matching this version - db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) - - entry <- db[db$Package %in% "renv" & db$Version %in% version, ] - if (nrow(entry) == 0) { - fmt <- "renv %s is not available from your declared package repositories" - stop(sprintf(fmt, version)) - } - - message("* Downloading renv ", version, " from CRAN ... ", appendLF = FALSE) - - info <- tryCatch( - download.packages("renv", destdir = tempdir()), - condition = identity - ) - - if (inherits(info, "condition")) { - message("FAILED") - return(FALSE) - } - - message("OK") - info[1, 2] - - } - - renv_bootstrap_download_cran_archive <- function(version) { - - name <- sprintf("renv_%s.tar.gz", version) - repos <- getOption("repos") - urls <- file.path(repos, "src/contrib/Archive/renv", name) - destfile <- file.path(tempdir(), name) - - message("* Downloading renv ", version, " from CRAN archive ... ", appendLF = FALSE) - - for (url in urls) { - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (identical(status, 0L)) { - message("OK") - return(destfile) - } - - } - - message("FAILED") - return(FALSE) - - } - - renv_bootstrap_download_github <- function(version) { - - enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE") - if (!identical(enabled, "TRUE")) - return(FALSE) - - # prepare download options - pat <- Sys.getenv("GITHUB_PAT") - if (nzchar(Sys.which("curl")) && nzchar(pat)) { - fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "curl", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { - fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "wget", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } - - message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) - - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) - name <- sprintf("renv_%s.tar.gz", version) - destfile <- file.path(tempdir(), name) - - status <- tryCatch( - renv_bootstrap_download_impl(url, destfile), - condition = identity - ) - - if (!identical(status, 0L)) { - message("FAILED") - return(FALSE) - } - - message("Done!") - return(destfile) - - } - - renv_bootstrap_install <- function(version, tarball, library) { - - # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(library, showWarnings = FALSE, recursive = TRUE) - - # invoke using system2 so we can capture and report output - bin <- R.home("bin") - exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) - args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball)) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - header <- "Error installing renv:" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- c(header, lines, output) - writeLines(text, con = stderr()) - } - - status - - } - - renv_bootstrap_prefix <- function() { - - # construct version prefix - version <- paste(R.version$major, R.version$minor, sep = ".") - prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - # build list of path components - components <- c(prefix, R.version$platform) - - # include prefix if provided by user - prefix <- Sys.getenv("RENV_PATHS_PREFIX") - if (nzchar(prefix)) - components <- c(prefix, components) - - # build prefix - paste(components, collapse = "/") - - } - - renv_bootstrap_library_root <- function(project) { - - path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA) - if (!is.na(path)) - return(path) - - path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA) - if (!is.na(path)) - return(file.path(path, basename(project))) - - file.path(project, "renv/library") - - } - - renv_bootstrap_validate_version <- function(version) { - - loadedversion <- utils::packageDescription("renv", fields = "Version") - if (version == loadedversion) - return(TRUE) - - # assume four-component versions are from GitHub; three-component - # versions are from CRAN - components <- strsplit(loadedversion, "[.-]")[[1]] - remote <- if (length(components) == 4L) - paste("rstudio/renv", loadedversion, sep = "@") - else - paste("renv", loadedversion, sep = "@") - - fmt <- paste( - "renv %1$s was loaded from project library, but renv %2$s is recorded in lockfile.", - "Use `renv::record(\"%3$s\")` to record this version in the lockfile.", - "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", - sep = "\n" - ) - - msg <- sprintf(fmt, loadedversion, version, remote) - warning(msg, call. = FALSE) - - FALSE - - } - - renv_bootstrap_load <- function(project, libpath, version) { - - # try to load renv from the project library - if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(FALSE) - - # warn if the version of renv loaded does not match - renv_bootstrap_validate_version(version) - - # load the project - renv::load(project) - - TRUE - - } - - # construct path to library root - root <- renv_bootstrap_library_root(project) - - # construct library prefix for platform - prefix <- renv_bootstrap_prefix() - - # construct full libpath - libpath <- file.path(root, prefix) - - # attempt to load - if (renv_bootstrap_load(project, libpath, version)) - return(TRUE) - - # load failed; attempt to bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) - -}) diff --git a/renv/settings.dcf b/renv/settings.dcf deleted file mode 100644 index 11a53eaf..00000000 --- a/renv/settings.dcf +++ /dev/null @@ -1,6 +0,0 @@ -external.libraries: -ignored.packages: -package.dependency.fields: Imports, Depends, LinkingTo -snapshot.type: implicit -use.cache: TRUE -vcs.ignore.library: TRUE diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 58929685..00000000 --- a/requirements.txt +++ /dev/null @@ -1,61 +0,0 @@ -attrs==19.3.0 -cachetools==4.1.1 -certifi==2020.6.20 -cffi==1.14.0 -chardet==3.0.4 -click>=7.1.2 -click-log>=0.3.2 -cryptography==3.3.2 -decorator==4.4.2 -Deprecated==1.2.4 -entrypoints==0.3 -fastjsonschema==2.14.4 -google-api-core==1.26.3 -google-api-python-client>=1.12.8 -google-auth>=1.19.1 -google-auth-httplib2>=0.0.4 -google-auth-oauthlib>=0.4.4 -googleapis-common-protos==1.53.0 -graphviz>=0.16 -httplib2==0.19.0 -idna==2.10 -importlib-metadata==1.7.0 -inflection==0.5.1 -isodate==0.6.0 -jsonschema==3.2.0 -keyring==12.0.2 -keyrings.alt==3.1 -networkx==2.5.1 -numpy==1.19.0 -oauth2client==3.0.0 -oauthlib==3.1.0 -orderedset==2.0.1 -packaging==20.9 -pandas==1.2.3 -pip==21.1 -protobuf==3.15.7 -pyasn1==0.4.8 -pyasn1-modules==0.2.8 -pycparser==2.20 -pygsheets==2.0.5 -pyparsing==2.4.7 -pyrsistent==0.16.0 -python-dateutil==2.8.1 -pytz==2020.1 -PyYAML==5.4.1 -rdflib==5.0.0 -requests>=2.24.0 -requests-oauthlib>=1.3.0 -rsa==4.7 -schematicpy==1.0.0 -SecretStorage==2.3.1 -setuptools==52.0.0 -six==1.15.0 -synapseclient==2.5.1 -tabletext==0.1 -toml==0.10.2 -uritemplate==3.0.1 -urllib3==1.26.5 -wheel==0.34.2 -wrapt==1.12.1 -zipp==3.1.0 From a7b9ace28c24205686573fd72069101dac1609b7 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 18 Jan 2022 17:50:25 +0000 Subject: [PATCH 215/260] add back requirements.txt --- requirements.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..e69de29b From 5c1c72473b2fe3534ad0d3b2f9c4a9ca149e1580 Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 18 Jan 2022 18:15:05 +0000 Subject: [PATCH 216/260] setup requirements.txt --- .gitignore | 3 ++- README.md | 16 ++++++++----- requirements.txt | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index fe60551d..46f09e4b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ schematic/ **/__pycache__ config.yaml .project -.settings/** \ No newline at end of file +.settings/** +.venv \ No newline at end of file diff --git a/README.md b/README.md index 0c86c121..323e752f 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor git clone --single-branch --branch shiny-server-main https://github.com/Sage-Bionetworks/data_curator.git -2. Create and modify the configuration file: - -- `CLIENT_ID` and `CLIENT_SECRET`: [how to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication) -- `APP_URL`: the redirection url to your app +2. Create and modify the configuration file ([How to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication)): cp example_config.yaml config.yaml chmod 400 config.yaml @@ -29,7 +26,11 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor python -m venv .venv source .venv/bin/activate -4. Install required R pacakges dependencies. +4. Install required Python pacakges dependencies: + + pip install -r requirements.txt + +5. Install required R pacakges dependencies: R -f install-pkgs.R @@ -66,7 +67,10 @@ Use the app configuration file `www/config.json` to adapt this app to your DCC. ## Authentication -This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the `CLIENT_ID` and `CLIENT_SECRET` make sure to add it to the configuration yaml file. +This utilizes a Synapse Authentication (OAuth) client (code motivated by [ShinyOAuthExample](https://github.com/brucehoff/ShinyOAuthExample) and [app.R](https://gist.github.com/jcheng5/44bd750764713b5a1df7d9daf5538aea). Each application is required to have its own OAuth client as these clients cannot be shared between one another. View instructions [here](https://docs.synapse.org/articles/using_synapse_as_an_oauth_server.html) to learn how to request a client. Once you obtain the client, make sure to add it to the configuration yaml file: + +- `CLIENT_ID` and `CLIENT_SECRET` +- `APP_URL`: the redirection url to your app --- diff --git a/requirements.txt b/requirements.txt index e69de29b..0d51e105 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,61 @@ +attrs==19.3.0 +cachetools==4.1.1 +certifi==2020.6.20 +cffi==1.14.0 +chardet==3.0.4 +click>=7.1.2 +click-log>=0.3.2 +cryptography==3.3.2 +decorator==4.4.2 +Deprecated==1.2.4 +entrypoints==0.3 +fastjsonschema==2.14.4 +google-api-core==1.26.3 +google-api-python-client>=1.12.8 +google-auth>=1.19.1 +google-auth-httplib2>=0.0.4 +google-auth-oauthlib>=0.4.4 +googleapis-common-protos==1.53.0 +graphviz>=0.16 +httplib2==0.19.0 +idna==2.10 +importlib-metadata==1.7.0 +inflection==0.5.1 +isodate==0.6.0 +jsonschema==3.2.0 +keyring==12.0.2 +keyrings.alt==3.1 +networkx==2.5.1 +numpy==1.19.0 +oauth2client==3.0.0 +oauthlib==3.1.0 +orderedset==2.0.1 +packaging==20.9 +pandas==1.2.3 +pip==21.1 +protobuf==3.15.7 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycparser==2.20 +pygsheets==2.0.5 +pyparsing==2.4.7 +pyrsistent==0.16.0 +python-dateutil==2.8.1 +pytz==2020.1 +PyYAML==5.4.1 +rdflib==5.0.0 +requests>=2.24.0 +requests-oauthlib>=1.3.0 +rsa==4.7 +schematicpy==1.0.0 +SecretStorage==2.3.1 +setuptools==52.0.0 +six==1.15.0 +synapseclient==2.5.1 +tabletext==0.1 +toml==0.10.2 +uritemplate==3.0.1 +urllib3==1.26.5 +wheel==0.34.2 +wrapt==1.12.1 +zipp==3.1.0 \ No newline at end of file From 5e4e1c1ccffd0ed58eb443333270336ca9bf2cdf Mon Sep 17 00:00:00 2001 From: rrchai Date: Tue, 18 Jan 2022 23:13:56 +0000 Subject: [PATCH 217/260] add r package versions --- install-pkgs.R | 52 +++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/install-pkgs.R b/install-pkgs.R index d8a72650..c6e41054 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -1,30 +1,38 @@ + cran <- c( - "ellipsis", - "shiny", - "httr", - "yaml", - "shinyjs", - "dplyr", - "shinythemes", - "shinydashboard", - "stringr", - "DT", - "jsonlite", - "reticulate", - "shinydashboardPlus", - "waiter", - "readr", - "sass", - "remotes", - "rsconnect", - "png" + "ellipsis==0.3.2", + "shiny==1.7.1", + "httr==1.4.2", + "yaml==2.2.1", + "shinyjs==2.1.0", + "dplyr==1.0.7", + "shinythemes==1.2.0", + "shinydashboard==0.7.2", + "stringr==1.4.0", + "DT==0.20", + "jsonlite==1.7.3", + "reticulate==1.23", + "shinydashboardPlus==2.0.3", + "waiter==0.2.5", + "readr==2.1.1", + "sass==0.4.0", + "remotes==2.4.2", + "rsconnect==0.8.25", + "png==0.1.7" +) +gh <- c( + "dreamRs/shinypop" ) - -gh <- "dreamRs/shinypop" # The binary package distributions from R Studio dramatically speed up installation time # For Ubuntu 18.04 (Bionic) it's https://packagemanager.rstudio.com/all/__linux__/bionic/latest # For Ubuntu 20.04 (Focal) it's https://packagemanager.rstudio.com/all/__linux__/focal/latest options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) -install.packages(cran) + +install.packages("remotes") +invisible( + lapply(strsplit(cran, "=="), function(cran_pkg) { + remotes::install_version(cran_pkg[1], version = cran_pkg[2]) + }) +) remotes::install_github(gh) \ No newline at end of file From a03b96aa9f47c979bcecc91bccf6d83824feb4cf Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 19 Jan 2022 16:35:24 +0000 Subject: [PATCH 218/260] link poetry repo in readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 323e752f..21256eb4 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor python -m pip install schematicpy - For development and test with the latest update from `schematic`, install the `schematic` via `poetry`: + For development and test with the latest update from `schematic`, install the `schematic` via [poetry]: cd schematic poetry build @@ -88,3 +88,4 @@ Main contributors and developers: [schematic]: https://github.com/Sage-Bionetworks/schematic/tree/develop +[poetry]: https://github.com/python-poetry/poetry From 927ae17230c7c9a7b082ef20f726201d7c2fd068 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 19 Jan 2022 18:14:43 +0000 Subject: [PATCH 219/260] add tidyr package --- install-pkgs.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install-pkgs.R b/install-pkgs.R index c6e41054..731f802d 100644 --- a/install-pkgs.R +++ b/install-pkgs.R @@ -18,7 +18,8 @@ cran <- c( "sass==0.4.0", "remotes==2.4.2", "rsconnect==0.8.25", - "png==0.1.7" + "png==0.1.7", + "tidyr==1.1.4" ) gh <- c( "dreamRs/shinypop" From 853fc2c6bbe552929118d393343b5186625caee2 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 11:31:40 +0000 Subject: [PATCH 220/260] add config file for schematic in the app repo --- .gitignore | 5 +-- ...le_config.yaml => example_oauth_config.yml | 0 schematic_config.yml | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) rename example_config.yaml => example_oauth_config.yml (100%) create mode 100644 schematic_config.yml diff --git a/.gitignore b/.gitignore index 46f09e4b..dab873e6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,8 @@ schematic/ **/schematic_service_account_creds.json **/token.pickle **/__pycache__ -config.yaml +oauth_config.yml .project .settings/** -.venv \ No newline at end of file +.venv +data-models/ diff --git a/example_config.yaml b/example_oauth_config.yml similarity index 100% rename from example_config.yaml rename to example_oauth_config.yml diff --git a/schematic_config.yml b/schematic_config.yml new file mode 100644 index 00000000..b397d755 --- /dev/null +++ b/schematic_config.yml @@ -0,0 +1,35 @@ +# Do not change the 'definitions' section unless you know what you're doing +definitions: + synapse_config: '.synapseConfig' + creds_path: 'credentials.json' + token_pickle: 'token.pickle' + service_acct_creds: 'schematic_service_account_creds.json' + +synapse: + master_fileview: 'syn23643253' # fileview of project with datasets on Synapse + manifest_folder: 'manifests' # manifests will be downloaded to this folder + manifest_filename: 'synapse_storage_manifest.csv' # name of the manifest file in the project dataset + token_creds: 'syn23643259' # synapse ID of credentials.json file + service_acct_creds: 'syn25171627' # synapse ID of service_account_creds.json file + +manifest: + title: 'Patient Manifest' # title of metadata manifest file + data_type: 'Patient' # component or data type from the data model + +model: + input: + location: 'data-models/example.model.jsonld' # path to JSON-LD data model + file_type: 'local' # only type "local" is supported currently + +style: + google_manifest: + req_bg_color: + red: 0.9215 + green: 0.9725 + blue: 0.9803 + opt_bg_color: + red: 1.0 + green: 1.0 + blue: 0.9019 + master_template_id: '1LYS5qE4nV9jzcYw5sXwCza25slDfRA1CIg3cs-hCdpU' + strict_validation: true From 8cade727907077a875641e78d27ab3c9ca936161 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 11:34:19 +0000 Subject: [PATCH 221/260] update global.R to use right config file name --- global.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/global.R b/global.R index 830adcf2..8d76f7d7 100644 --- a/global.R +++ b/global.R @@ -3,15 +3,15 @@ suppressPackageStartupMessages({ library(reticulate) }) -oauth_client <- yaml.load_file("config.yaml") +oauth_client <- yaml.load_file("oauth_config.yml") client_id <- toString(oauth_client$CLIENT_ID) client_secret <- toString(oauth_client$CLIENT_SECRET) app_url <- toString(oauth_client$APP_URL) -if (is.null(client_id) || nchar(client_id) == 0) stop("config.yaml is missing CLIENT_ID") -if (is.null(client_secret) || nchar(client_secret) == 0) stop("config.yaml is missing CLIENT_SECRET") -if (is.null(app_url) || nchar(app_url) == 0) stop("config.yaml is missing APP_URL") +if (is.null(client_id) || nchar(client_id) == 0) stop("oauth_config.yml is missing CLIENT_ID") +if (is.null(client_secret) || nchar(client_secret) == 0) stop("oauth_config.yml is missing CLIENT_SECRET") +if (is.null(app_url) || nchar(app_url) == 0) stop("oauth_config.yml is missing APP_URL") # ShinyAppys has a limit of 7000 files which this app' grossly exceeds # due to its Python dependencies. To get around the limit we zip up From da8c1aa2bd2d70358893bf5ddbc127c6226c3bed Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 11:45:50 +0000 Subject: [PATCH 222/260] mv schematic config to .github --- schematic_config.yml => .github/schematic_config.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) rename schematic_config.yml => .github/schematic_config.yml (80%) diff --git a/schematic_config.yml b/.github/schematic_config.yml similarity index 80% rename from schematic_config.yml rename to .github/schematic_config.yml index b397d755..4ff1e260 100644 --- a/schematic_config.yml +++ b/.github/schematic_config.yml @@ -1,3 +1,8 @@ +# During the github workflow to auto deploy the app +# This config file will be used to overwrite the config.yml in the schematic folder +# +# Please modify the configuration values based on your project + # Do not change the 'definitions' section unless you know what you're doing definitions: synapse_config: '.synapseConfig' @@ -18,7 +23,7 @@ manifest: model: input: - location: 'data-models/example.model.jsonld' # path to JSON-LD data model + location: 'data-models/HTAN.model.jsonld' # path to JSON-LD data model file_type: 'local' # only type "local" is supported currently style: From c5adfc58951d92ffe30c1a7f564ee648630a41f7 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:03:51 +0000 Subject: [PATCH 223/260] download data model in workflow --- .github/schematic_config.yml | 1 + .github/workflows/shinyapps_deploy.yml | 37 ++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index 4ff1e260..6bcdbf1c 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -23,6 +23,7 @@ manifest: model: input: + gh_repo: 'https://github.com/ncihtan/data-models' # path to github repo where stores JSON-LD data model location: 'data-models/HTAN.model.jsonld' # path to JSON-LD data model file_type: 'local' # only type "local" is supported currently diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 764d2d84..20399646 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -7,8 +7,8 @@ on: push: branches: - shiny-server-main - - switch-python-venv - - poetry + - switch-python-venv # tmp + - update-workflow-for-schematic-config # tmp - release* jobs: @@ -37,27 +37,36 @@ jobs: chmod 755 .venv/bin/activate source .venv/bin/activate - - name: Install Python Dependencies + - name: Install R Packages Dependencies + run: | + R -f install-pkgs.R + + - name: Install Python Packages Dependencies shell: bash run: | - source .venv/bin/activate - # install 'poetry' and then use it to install 'schematic' + pip3 install -r requirements.txt + + - name: Install Schematic + shell: bash + run: | + # use 'poetry' to install schematic from the develop branch pip3 install poetry git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git cd schematic poetry build pip3 install dist/schematicpy-1.0.0-py3-none-any.whl - # This was the old way: pip3 install -r requirements.txt - # However, per Anthony Williams, "poetry will install all of the dependencies necessary for the app to run" - # - # This is to fix the error we otherwise see when the app starts up: - # No such file or directory: 'tests/data/example.model.jsonld' - mkdir -p ../tests/data/ - cp -R tests/data/ ../tests/ - - name: Install R packages + - name: Set Configurations for Schematic + shell: bash run: | - R -f install-pkgs.R + # download data model to the correct location + R -e ' + config <- yaml::yaml.load_file(".github/schematic_config.yml"); + url <- config$model$input$gh_repo; + path <- config$model$input$location; + system(sprintf("mkdir -p %s", dirname(path))); + system(sprintf("wget %s -O %s", url, path)) + ' - name: zip virtual env # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies From 2561e678a366acf797146bd9dd16971fd6abe29d Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:14:14 +0000 Subject: [PATCH 224/260] set up configuration files for schematic in worlflow --- .github/workflows/shinyapps_deploy.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 20399646..1607159d 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -19,6 +19,10 @@ jobs: env: # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. GITHUB_PAT: ${{ secrets.REPO_PAT }} + # Add configuration values to env variables for schematic + SCHEMATIC_SYNAPSE_CONFIG: ${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }} + SCHEMATIC_SERVICE_ACCOUNT_CREDS: ${{ secrets.SCHEMATIC_SERVICE_ACCOUNT_CREDS }} + SCHEMATIC_TOKEN_PICKLE: ${{ secrets.SCHEMATIC_TOKEN_PICKLE }} steps: - name: Install System Dependencies @@ -65,8 +69,14 @@ jobs: url <- config$model$input$gh_repo; path <- config$model$input$location; system(sprintf("mkdir -p %s", dirname(path))); - system(sprintf("wget %s -O %s", url, path)) + system(sprintf("wget %s -O %s", url, path)); ' + # overwrite the config.yml in schematic + mv -f .github/schematic_config.yml schematic/config.yml + # write out configuration files using github secrets + echo $SCHEMATIC_SYNAPSE_CONFIG > schematic/.synapseConfig + echo $SCHEMATIC_SERVICE_ACCOUNT_CREDS > schematic/schematic_service_account_creds.json + echo $SCHEMATIC_TOKEN_PICKLE > schematic/token.pickle - name: zip virtual env # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies @@ -95,7 +105,7 @@ jobs: appUrl <- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) config <- c(config, sprintf("APP_URL: %s", appUrl)) - configFileConn <- file("config.yaml") + configFileConn <- file("oauth_config.yml") tryCatch( writeLines(config, configFileConn), finally=close(configFileConn) From 45cdf516c30867794c000f0368b7e6ee7303611b Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:16:20 +0000 Subject: [PATCH 225/260] clean up workflow --- .github/workflows/shinyapps_deploy.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 1607159d..4891e58d 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -35,7 +35,6 @@ jobs: - uses: r-lib/actions/setup-pandoc@v1 - name: Create and Activate Python Virtual Environment - shell: bash run: | python3 -m venv .venv chmod 755 .venv/bin/activate @@ -46,12 +45,10 @@ jobs: R -f install-pkgs.R - name: Install Python Packages Dependencies - shell: bash run: | pip3 install -r requirements.txt - name: Install Schematic - shell: bash run: | # use 'poetry' to install schematic from the develop branch pip3 install poetry @@ -61,7 +58,6 @@ jobs: pip3 install dist/schematicpy-1.0.0-py3-none-any.whl - name: Set Configurations for Schematic - shell: bash run: | # download data model to the correct location R -e ' @@ -82,7 +78,6 @@ jobs: # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies # that this app' has. As a workaround we zip the virtual environment and later # unzip it in 'global.R' - shell: bash run: | zip -rm .venv.zip .venv @@ -93,7 +88,7 @@ jobs: repo <- Sys.getenv("GITHUB_REPOSITORY") appName <- strsplit(repo, "/")[[1]][2] if (!startsWith(branch, "release")) { - appName <- paste(appName, "staging", sep="-") + appName <- paste(appName, "staging", sep = "-") } rsConnectUser <- "${{ secrets.RSCONNECT_USER }}" rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" @@ -107,8 +102,8 @@ jobs: configFileConn <- file("oauth_config.yml") tryCatch( - writeLines(config, configFileConn), - finally=close(configFileConn) + writeLines(config, configFileConn), + finally=close(configFileConn) ) rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) rsconnect::deployApp(appName = appName) From 2c0b4ea4e301b0ec024a87d862078c2d41224dfa Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:20:24 +0000 Subject: [PATCH 226/260] change to use url to download data model for now --- .github/schematic_config.yml | 2 +- .github/workflows/shinyapps_deploy.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index 6bcdbf1c..cba4c300 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -23,7 +23,7 @@ manifest: model: input: - gh_repo: 'https://github.com/ncihtan/data-models' # path to github repo where stores JSON-LD data model + download_url: 'https://raw.githubusercontent.com/ncihtan/data-models/main/HTAN.model.jsonld' # url to download JSON-LD data model location: 'data-models/HTAN.model.jsonld' # path to JSON-LD data model file_type: 'local' # only type "local" is supported currently diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 4891e58d..90215994 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -62,7 +62,7 @@ jobs: # download data model to the correct location R -e ' config <- yaml::yaml.load_file(".github/schematic_config.yml"); - url <- config$model$input$gh_repo; + url <- config$model$input$download_url; path <- config$model$input$location; system(sprintf("mkdir -p %s", dirname(path))); system(sprintf("wget %s -O %s", url, path)); From 585e39e96412caeff4935eb2ffcb82d439a3660b Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:31:24 +0000 Subject: [PATCH 227/260] add back shell:bash to steps --- .github/workflows/shinyapps_deploy.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 90215994..f9a085fc 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -35,6 +35,7 @@ jobs: - uses: r-lib/actions/setup-pandoc@v1 - name: Create and Activate Python Virtual Environment + shell: bash run: | python3 -m venv .venv chmod 755 .venv/bin/activate @@ -45,10 +46,12 @@ jobs: R -f install-pkgs.R - name: Install Python Packages Dependencies + shell: bash run: | pip3 install -r requirements.txt - name: Install Schematic + shell: bash run: | # use 'poetry' to install schematic from the develop branch pip3 install poetry @@ -58,6 +61,7 @@ jobs: pip3 install dist/schematicpy-1.0.0-py3-none-any.whl - name: Set Configurations for Schematic + shell: bash run: | # download data model to the correct location R -e ' @@ -75,6 +79,7 @@ jobs: echo $SCHEMATIC_TOKEN_PICKLE > schematic/token.pickle - name: zip virtual env + shell: bash # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies # that this app' has. As a workaround we zip the virtual environment and later # unzip it in 'global.R' From 033f246a738c2a9917db1e02e08e8fac8f52d9cb Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 12:53:19 +0000 Subject: [PATCH 228/260] activate .venv every steps --- .github/workflows/shinyapps_deploy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index f9a085fc..881f425a 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -48,11 +48,13 @@ jobs: - name: Install Python Packages Dependencies shell: bash run: | + source .venv/bin/activate pip3 install -r requirements.txt - name: Install Schematic shell: bash run: | + source .venv/bin/activate # use 'poetry' to install schematic from the develop branch pip3 install poetry git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git @@ -63,6 +65,7 @@ jobs: - name: Set Configurations for Schematic shell: bash run: | + source .venv/bin/activate # download data model to the correct location R -e ' config <- yaml::yaml.load_file(".github/schematic_config.yml"); From 812d55cc2aad8b0aac3be332d0f825b39ea194b4 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 20:16:39 +0000 Subject: [PATCH 229/260] enable to add token.pick from env variable via secret --- .github/set_gh_secrets.R | 26 ++++++++++++++++++++++++++ .github/workflows/shinyapps_deploy.yml | 11 ++++------- 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 .github/set_gh_secrets.R diff --git a/.github/set_gh_secrets.R b/.github/set_gh_secrets.R new file mode 100644 index 00000000..c83fe82f --- /dev/null +++ b/.github/set_gh_secrets.R @@ -0,0 +1,26 @@ +# require github cli package - 'gh': https://cli.github.com/manual/ + +args <- commandArgs(trailingOnly = TRUE) + +secret_lists <- yaml::yaml.load_file(toString(args[1]))$definitions + +for (f in c("synapse_config", "creds_path", "service_acct_creds")) { + system( + sprintf( + "gh secret set %s < %s", + toupper(paste0("schematic_", f)), secret_lists[f] + ) + ) +} + +# token.pickle is a binary file +# If you want to manually add to the secret: +# 1. copy below code snippet and run it in the terminal +# 2. copy content from 'token.pickle.b64' to your github secret +system( + " + less token.pickle | base64 --wrap=0 > token.pickle.b64; + gh secret set SCHEMATIC_TOKEN_PICKLE < token.pickle.b64; + " +) +unlink("token.pickle.b64") \ No newline at end of file diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 881f425a..aac4d05b 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -19,10 +19,6 @@ jobs: env: # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. GITHUB_PAT: ${{ secrets.REPO_PAT }} - # Add configuration values to env variables for schematic - SCHEMATIC_SYNAPSE_CONFIG: ${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }} - SCHEMATIC_SERVICE_ACCOUNT_CREDS: ${{ secrets.SCHEMATIC_SERVICE_ACCOUNT_CREDS }} - SCHEMATIC_TOKEN_PICKLE: ${{ secrets.SCHEMATIC_TOKEN_PICKLE }} steps: - name: Install System Dependencies @@ -77,9 +73,10 @@ jobs: # overwrite the config.yml in schematic mv -f .github/schematic_config.yml schematic/config.yml # write out configuration files using github secrets - echo $SCHEMATIC_SYNAPSE_CONFIG > schematic/.synapseConfig - echo $SCHEMATIC_SERVICE_ACCOUNT_CREDS > schematic/schematic_service_account_creds.json - echo $SCHEMATIC_TOKEN_PICKLE > schematic/token.pickle + echo "${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }}" > schematic/.synapseConfig + echo "${{ secrets.SCHEMATIC_SERVICE_ACCT_CREDS }}" > schematic/schematic_service_account_creds.json + echo "${{ secrets.SCHEMATIC_CREDS_PATH }}" > schematic/credentials.json + echo "${{ secrets.SCHEMATIC_TOKEN_PICKLE }}" | base64 -d > schematic/token.pickle - name: zip virtual env shell: bash From ebc46087e3649b8b2755e6ef9c842155494f7206 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 20:48:16 +0000 Subject: [PATCH 230/260] add validation to avoid setting secret to wrong repo --- .github/set_gh_secrets.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/set_gh_secrets.R b/.github/set_gh_secrets.R index c83fe82f..df72ff74 100644 --- a/.github/set_gh_secrets.R +++ b/.github/set_gh_secrets.R @@ -2,13 +2,18 @@ args <- commandArgs(trailingOnly = TRUE) +repo <- basename(Sys.getenv("PWD")) + +if (repo %in% c("schematic", "data-models")) stop("You are not in the data curator folder !!!") + secret_lists <- yaml::yaml.load_file(toString(args[1]))$definitions +message("Assuming all definition files are stored in the schematic folder ...") for (f in c("synapse_config", "creds_path", "service_acct_creds")) { system( sprintf( "gh secret set %s < %s", - toupper(paste0("schematic_", f)), secret_lists[f] + toupper(paste0("schematic_", f)), file.path("schematic", secret_lists[f]) ) ) } @@ -19,8 +24,8 @@ for (f in c("synapse_config", "creds_path", "service_acct_creds")) { # 2. copy content from 'token.pickle.b64' to your github secret system( " - less token.pickle | base64 --wrap=0 > token.pickle.b64; - gh secret set SCHEMATIC_TOKEN_PICKLE < token.pickle.b64; + less schematic/token.pickle | base64 --wrap=0 > schematic/token.pickle.b64; + gh secret set SCHEMATIC_TOKEN_PICKLE < schematic/token.pickle.b64; " ) -unlink("token.pickle.b64") \ No newline at end of file +unlink("schematic/token.pickle.b64") \ No newline at end of file From dbdda6c5c53653430f0377f18aa3ef2f86383780 Mon Sep 17 00:00:00 2001 From: rrchai Date: Thu, 20 Jan 2022 21:40:37 +0000 Subject: [PATCH 231/260] update fileview to htan --- .github/schematic_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index cba4c300..e8c23666 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -11,7 +11,7 @@ definitions: service_acct_creds: 'schematic_service_account_creds.json' synapse: - master_fileview: 'syn23643253' # fileview of project with datasets on Synapse + master_fileview: 'syn20446927' # fileview of project with datasets on Synapse manifest_folder: 'manifests' # manifests will be downloaded to this folder manifest_filename: 'synapse_storage_manifest.csv' # name of the manifest file in the project dataset token_creds: 'syn23643259' # synapse ID of credentials.json file From bba34032a5f574497d22c8c73fae6558cb21a259 Mon Sep 17 00:00:00 2001 From: Milen Nikolov Date: Tue, 8 Feb 2022 18:35:08 -0800 Subject: [PATCH 232/260] added imaging level 3 component to config --- www/config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/www/config.json b/www/config.json index cf30aea7..39853b65 100644 --- a/www/config.json +++ b/www/config.json @@ -13,6 +13,7 @@ {"display_name": "Bulk WES Level 2", "schema_name": "BulkWESLevel2", "type": "assay"}, {"display_name": "Bulk WES Level 3", "schema_name": "BulkWESLevel3", "type": "assay"}, {"display_name": "Imaging Level 2", "schema_name": "ImagingLevel2", "type": "assay"}, + {"display_name": "Imaging Level 3", "schema_name": "ImagingLevel3", "type": "assay"}, {"display_name": "Clinical Tier 1: Demographics", "schema_name": "Demographics", "type": "clinical"}, {"display_name": "Clinical Tier 1: Diagnosis", "schema_name": "Diagnosis", "type": "clinical"}, {"display_name": "Clinical Tier 1: FamilyHistory", "schema_name": "FamilyHistory", "type": "clinical"}, From c0bd30ae1aaf68c892995d67ffa0863f227aec51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Feb 2022 16:30:44 +0000 Subject: [PATCH 233/260] Bump numpy from 1.19.0 to 1.21.0 Bumps [numpy](https://github.com/numpy/numpy) from 1.19.0 to 1.21.0. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt) - [Commits](https://github.com/numpy/numpy/compare/v1.19.0...v1.21.0) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0d51e105..ceddb075 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ jsonschema==3.2.0 keyring==12.0.2 keyrings.alt==3.1 networkx==2.5.1 -numpy==1.19.0 +numpy==1.21.0 oauth2client==3.0.0 oauthlib==3.1.0 orderedset==2.0.1 From c97d6b913e46e3dcb4a3290be1c75a8d76594025 Mon Sep 17 00:00:00 2001 From: rrchai Date: Fri, 11 Feb 2022 16:58:04 +0000 Subject: [PATCH 234/260] fix oauth_config.yml name in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21256eb4..abe759f6 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ Follow the steps below to make sure the _Data Curator App_ is fully setup to wor 2. Create and modify the configuration file ([How to obtain OAuth Credential](https://github.com/Sage-Bionetworks/data_curator#Authentication)): - cp example_config.yaml config.yaml - chmod 400 config.yaml + cp example_oauth_config.yml oauth_config.yml + chmod 400 oauth_config.yml 3. Create and activate a virtual environment within which you can install the package: From e180d04287fc7ad814e5bbef4c4592f5c106191a Mon Sep 17 00:00:00 2001 From: Yooree Chae Date: Tue, 15 Feb 2022 15:28:55 -0800 Subject: [PATCH 235/260] Update issue templates Added feature request template and added priority to bug template --- .github/ISSUE_TEMPLATE/bug-bash-report.md | 24 ------------------- .github/ISSUE_TEMPLATE/feature_request.md | 29 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 24 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug-bash-report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug-bash-report.md b/.github/ISSUE_TEMPLATE/bug-bash-report.md deleted file mode 100644 index cd7df885..00000000 --- a/.github/ISSUE_TEMPLATE/bug-bash-report.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: Bug Bash Report -about: Bugs found in the Nov 10 2021 DCA Bug Bash -title: '' -labels: Bug Bash v1 -assignees: '' - ---- - -**Describe the bug** -- [ ] Server disconnect -- [ ] Wrong manifest -- [ ] Wrong values in manifest columns -- [ ] Other (please describe) - -**To Reproduce** -Center: -Template: - -**Screenshots (optional)** -If applicable, add screenshots to help explain your problem. - -**Additional context (optional)** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..3576a039 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,29 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**How important is this feature?** Select from the options below: +• Low - it's an enhancement but not crucial for work +• Medium - can do work without it; but it's important (e.g. to save time or for convenience) +• Important - it's a blocker and can't do work without it + +**When will use cases depending on this become relevant?** Select from the options below: +• Short-term - 2-4 weeks +• Mid-term - 2-4 months +• Long-term - 6 months - 1 year + +**Additional context** +Add any other context or screenshots about the feature request here. +**Additional context** +Add any other context or screenshots about the feature request here. From 316523c657511df3d30920093340144bb482f7a4 Mon Sep 17 00:00:00 2001 From: Yooree Chae Date: Tue, 15 Feb 2022 15:32:15 -0800 Subject: [PATCH 236/260] Update bug_report.md added priority to bug tempate --- .github/ISSUE_TEMPLATE/bug_report.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5aeec088..f40079e0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,6 +20,11 @@ Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. +**Priority** (select one) +- [ ] Minor ⬇️ +- [ ] Major 📢 +- [ ] Critical 🆘 + **Screenshots** If applicable, add screenshots to help explain your problem. From 0db828c9a28cd84bf6993d811ea1cd0d0649f1df Mon Sep 17 00:00:00 2001 From: Yooree Chae Date: Tue, 15 Feb 2022 15:33:06 -0800 Subject: [PATCH 237/260] added emojis to feature template --- .github/ISSUE_TEMPLATE/feature_request.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3576a039..890c4c00 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -14,9 +14,9 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate A clear and concise description of what you want to happen. **How important is this feature?** Select from the options below: -• Low - it's an enhancement but not crucial for work -• Medium - can do work without it; but it's important (e.g. to save time or for convenience) -• Important - it's a blocker and can't do work without it +• 🏝 Low - it's an enhancement but not crucial for work +• 🌗 Medium - can do work without it; but it's important (e.g. to save time or for convenience) +• 🌋 Important - it's a blocker and can't do work without it **When will use cases depending on this become relevant?** Select from the options below: • Short-term - 2-4 weeks From 4b509999453ab33ffbee18104ffb91d3e415cf5e Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 16 Feb 2022 00:07:01 +0000 Subject: [PATCH 238/260] ignore template updates --- .github/workflows/shinyapps_deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index aac4d05b..42fb96b4 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -7,9 +7,9 @@ on: push: branches: - shiny-server-main - - switch-python-venv # tmp - - update-workflow-for-schematic-config # tmp - release* + paths-ignore: + - .github/ISSUE_TEMPLATE/** jobs: shiny-deploy: From b722a3e51c29a6c814b585925c6e58cbbebdf1b7 Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 16 Feb 2022 00:10:51 +0000 Subject: [PATCH 239/260] add develop branch for now --- .github/workflows/shinyapps_deploy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 42fb96b4..4e720be0 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -3,10 +3,13 @@ name: shiny-deploy +# TODO: remove `shiny-server-develop` when we use shinyapps.io as production site +# also consider to change shiny-server-main to main since we will not host in shinyServer on: push: branches: - shiny-server-main + - shiny-server-develop # add develop for testing for now - release* paths-ignore: - .github/ISSUE_TEMPLATE/** From 76936ba6ea16caae386b071cf9ae45491128217a Mon Sep 17 00:00:00 2001 From: rrchai Date: Wed, 16 Feb 2022 00:17:06 +0000 Subject: [PATCH 240/260] test whether triger CI check --- .github/ISSUE_TEMPLATE/feature_request.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 890c4c00..b571f835 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -27,3 +27,4 @@ A clear and concise description of what you want to happen. Add any other context or screenshots about the feature request here. **Additional context** Add any other context or screenshots about the feature request here. + From 27bce2b16c75edb710aaf76e6ac43b384e018cc2 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:00:06 -0800 Subject: [PATCH 241/260] Create deploy.yml --- .github/workflows/deploy.yml | 108 +++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..50f1f4b8 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,108 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help + +name: shiny-deploy + +# TODO: remove `shiny-server-develop` when we use shinyapps.io as production site +# also consider to change shiny-server-main to main since we will not host in shinyServer +on: + push: + branches: + - shiny-server-main + - shiny-server-develop # add develop for testing for now + - release* + paths-ignore: + - .github/ISSUE_TEMPLATE/** + +jobs: + shiny-deploy: + runs-on: ubuntu-latest + # This image seems to be based on rocker/r-ver which in turn is based on debian + container: rocker/rstudio + env: + # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. + GITHUB_PAT: ${{ secrets.REPO_PAT }} + + steps: + - name: Install System Dependencies + run: | + sudo apt-get update + sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev + - uses: actions/checkout@v2 + + - uses: r-lib/actions/setup-pandoc@v1 + + - name: Create and Activate Python Virtual Environment + shell: bash + run: | + python3 -m venv .venv + chmod 755 .venv/bin/activate + source .venv/bin/activate + - name: Install R Packages Dependencies + run: | + R -f install-pkgs.R + - name: Install Python Packages Dependencies + shell: bash + run: | + source .venv/bin/activate + pip3 install -r requirements.txt + - name: Install Schematic + shell: bash + run: | + source .venv/bin/activate + # use 'poetry' to install schematic from the develop branch + pip3 install poetry + git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git + cd schematic + poetry build + pip3 install dist/schematicpy-1.0.0-py3-none-any.whl + - name: Set Configurations for Schematic + shell: bash + run: | + source .venv/bin/activate + # download data model to the correct location + R -e ' + config <- yaml::yaml.load_file(".github/schematic_config.yml"); + url <- config$model$input$download_url; + path <- config$model$input$location; + system(sprintf("mkdir -p %s", dirname(path))); + system(sprintf("wget %s -O %s", url, path)); + ' + # overwrite the config.yml in schematic + mv -f .github/schematic_config.yml schematic/config.yml + # write out configuration files using github secrets + echo "${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }}" > schematic/.synapseConfig + echo "${{ secrets.SCHEMATIC_SERVICE_ACCT_CREDS }}" > schematic/schematic_service_account_creds.json + echo "${{ secrets.SCHEMATIC_CREDS_PATH }}" > schematic/credentials.json + echo "${{ secrets.SCHEMATIC_TOKEN_PICKLE }}" | base64 -d > schematic/token.pickle + - name: zip virtual env + shell: bash + # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies + # that this app' has. As a workaround we zip the virtual environment and later + # unzip it in 'global.R' + run: | + zip -rm .venv.zip .venv + - name: Authorize and deploy app + shell: Rscript {0} + run: | + branch <- Sys.getenv("GITHUB_REF_NAME") + repo <- Sys.getenv("GITHUB_REPOSITORY") + appName <- strsplit(repo, "/")[[1]][2] + if (!startsWith(branch, "release")) { + appName <- paste(appName, "staging", sep = "-") + } + rsConnectUser <- "${{ secrets.RSCONNECT_USER }}" + rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" + rsConnectSecret <- "${{ secrets.RSCONNECT_SECRET }}" + # create config file + config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" + config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") + appUrl <- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) + config <- c(config, sprintf("APP_URL: %s", appUrl)) + configFileConn <- file("oauth_config.yml") + tryCatch( + writeLines(config, configFileConn), + finally=close(configFileConn) + ) + rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) + rsconnect::deployApp(appName = appName) From 3bd76f9c8970835758a3cce41a8622a17ab27626 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:00:49 -0800 Subject: [PATCH 242/260] Update deploy.yml --- .github/workflows/deploy.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 50f1f4b8..7758df72 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,8 +8,7 @@ name: shiny-deploy on: push: branches: - - shiny-server-main - - shiny-server-develop # add develop for testing for now + - develop # add develop for testing for now - release* paths-ignore: - .github/ISSUE_TEMPLATE/** From d068e9593ef74f7101c0cb7f08a462c7db3fe3c7 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:02:49 -0800 Subject: [PATCH 243/260] Create install-pkgs.R --- install-pkgs.R | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 install-pkgs.R diff --git a/install-pkgs.R b/install-pkgs.R new file mode 100644 index 00000000..42b52897 --- /dev/null +++ b/install-pkgs.R @@ -0,0 +1,39 @@ + +cran <- c( + "ellipsis==0.3.2", + "shiny==1.7.1", + "httr==1.4.2", + "yaml==2.2.1", + "shinyjs==2.1.0", + "dplyr==1.0.7", + "shinythemes==1.2.0", + "shinydashboard==0.7.2", + "stringr==1.4.0", + "DT==0.20", + "jsonlite==1.7.3", + "reticulate==1.23", + "shinydashboardPlus==2.0.3", + "waiter==0.2.5", + "readr==2.1.1", + "sass==0.4.0", + "remotes==2.4.2", + "rsconnect==0.8.25", + "png==0.1.7", + "tidyr==1.1.4" +) +gh <- c( + "dreamRs/shinypop" +) + +# The binary package distributions from R Studio dramatically speed up installation time +# For Ubuntu 18.04 (Bionic) it's https://packagemanager.rstudio.com/all/__linux__/bionic/latest +# For Ubuntu 20.04 (Focal) it's https://packagemanager.rstudio.com/all/__linux__/focal/latest +options(repos = c(REPO_NAME = "https://packagemanager.rstudio.com/all/__linux__/bionic/latest", getOption("repos"))) + +install.packages("remotes") +invisible( + lapply(strsplit(cran, "=="), function(cran_pkg) { + remotes::install_version(cran_pkg[1], version = cran_pkg[2]) + }) +) +remotes::install_github(gh) From c867db5c783fc1635af36ccb61b53c047702e764 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:10:28 -0800 Subject: [PATCH 244/260] Delete renv.lock --- renv.lock | 759 ------------------------------------------------------ 1 file changed, 759 deletions(-) delete mode 100644 renv.lock diff --git a/renv.lock b/renv.lock deleted file mode 100644 index 9804e4f4..00000000 --- a/renv.lock +++ /dev/null @@ -1,759 +0,0 @@ -{ - "R": { - "Version": "3.6.3", - "Repositories": [ - { - "Name": "CRAN", - "URL": "https://cran.rstudio.com" - }, - { - "Name": "Sage", - "URL": "http://ran.synapse.org" - } - ] - }, - "Packages": { - "BH": { - "Package": "BH", - "Version": "1.72.0-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f9ce74c6417d61f0782cbae5fd2b7b0" - }, - "DT": { - "Package": "DT", - "Version": "0.14", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a3580ce0309c94d061c23b0afb4accbd" - }, - "MASS": { - "Package": "MASS", - "Version": "7.3-51.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1dad32ac9dbd8057167b2979fb932ff7" - }, - "Matrix": { - "Package": "Matrix", - "Version": "1.2-18", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08588806cba69f04797dab50627428ed" - }, - "R.cache": { - "Package": "R.cache", - "Version": "0.15.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e92a8ea8388c47c82ed8aa435ed3be50" - }, - "R.methodsS3": { - "Package": "R.methodsS3", - "Version": "1.8.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bf6453323755202d5909697b6f7c109" - }, - "R.oo": { - "Package": "R.oo", - "Version": "1.24.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5709328352717e2f0a9c012be8a97554" - }, - "R.utils": { - "Package": "R.utils", - "Version": "2.10.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a9e316277ff12a43997266f2f6567780" - }, - "R6": { - "Package": "R6", - "Version": "2.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "292b54f8f4b94669b08f94e5acce6be2" - }, - "RColorBrewer": { - "Package": "RColorBrewer", - "Version": "1.1-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e031418365a7f7a766181ab5a41a5716" - }, - "Rcpp": { - "Package": "Rcpp", - "Version": "1.0.5", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "125dc7a0ed375eb68c0ce533b48d291f" - }, - "askpass": { - "Package": "askpass", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e8a22846fff485f0be3770c2da758713" - }, - "assertthat": { - "Package": "assertthat", - "Version": "0.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "50c838a310445e954bc13f26f26a6ecf" - }, - "backports": { - "Package": "backports", - "Version": "1.1.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3ef0eac19317fd03c0c854aed581d473" - }, - "base64enc": { - "Package": "base64enc", - "Version": "0.1-3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "543776ae6848fde2f48ff3816d0628bc" - }, - "callr": { - "Package": "callr", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "643163a00cb536454c624883a10ae0bc" - }, - "cli": { - "Package": "cli", - "Version": "2.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ff0becff7bfdfe3f75d29aff8f3172dd" - }, - "clipr": { - "Package": "clipr", - "Version": "0.7.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08cf4045c149a0f0eaf405324c7495bd" - }, - "colorspace": { - "Package": "colorspace", - "Version": "1.4-1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6b436e95723d1f0e861224dd9b094dfb" - }, - "commonmark": { - "Package": "commonmark", - "Version": "1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0f22be39ec1d141fd03683c06f3a6e67" - }, - "cpp11": { - "Package": "cpp11", - "Version": "0.2.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "730eebcc741a5c36761f7d4d0f5e37b8" - }, - "crayon": { - "Package": "crayon", - "Version": "1.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0d57bc8e27b7ba9e45dba825ebc0de6b" - }, - "crosstalk": { - "Package": "crosstalk", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ae55f5d7c02f0ab43c58dd050694f2b4" - }, - "curl": { - "Package": "curl", - "Version": "4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2b7d10581cc730804e9ed178c8374bd6" - }, - "data.table": { - "Package": "data.table", - "Version": "1.12.8", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "cd711af60c47207a776213a368626369" - }, - "desc": { - "Package": "desc", - "Version": "1.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6c8fe8fa26a23b79949375d372c7b395" - }, - "digest": { - "Package": "digest", - "Version": "0.6.25", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f697db7d92b7028c4b3436e9603fb636" - }, - "dplyr": { - "Package": "dplyr", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4011f62581a34080e44105d4aa05a97f" - }, - "ellipsis": { - "Package": "ellipsis", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fd2844b3a43ae2d27e70ece2df1b4e2a" - }, - "evaluate": { - "Package": "evaluate", - "Version": "0.14", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" - }, - "fansi": { - "Package": "fansi", - "Version": "0.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7fce217eaaf8016e72065e85c73027b5" - }, - "farver": { - "Package": "farver", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "dad6793a5a1f73c8e91f1a1e3e834b05" - }, - "fastmap": { - "Package": "fastmap", - "Version": "1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "83ab58a0518afe3d17e41da01af13b60" - }, - "fresh": { - "Package": "fresh", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fa54367040deb4537da49b7ac0ee5770" - }, - "fs": { - "Package": "fs", - "Version": "1.4.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8c04112383ca1988e96f429255f95675" - }, - "generics": { - "Package": "generics", - "Version": "0.0.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8cff1d1391fd1ad8b65877f4c7f2e53" - }, - "ggplot2": { - "Package": "ggplot2", - "Version": "3.3.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4ded8b439797f7b1693bd3d238d0106b" - }, - "glue": { - "Package": "glue", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f43e0d5e85ccb0a4045670c0607ee504" - }, - "gtable": { - "Package": "gtable", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ac5c6baf7822ce8732b343f14c072c4d" - }, - "hexbin": { - "Package": "hexbin", - "Version": "1.28.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "3d59212f2814d65dff517e6899813c58" - }, - "hms": { - "Package": "hms", - "Version": "0.5.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "726671f634529d470545f9fd1a9d1869" - }, - "htmltools": { - "Package": "htmltools", - "Version": "0.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7d651b7131794fe007b1ad6f21aaa401" - }, - "htmlwidgets": { - "Package": "htmlwidgets", - "Version": "1.5.1.9001", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "htmlwidgets", - "RemoteUsername": "ramnathv", - "RemoteRef": "master", - "RemoteSha": "6fcc4b03ed3fc42be76d4e43d863db3d85c8babb", - "Hash": "43198daf611c2422a3969bf1f02213b4" - }, - "httpuv": { - "Package": "httpuv", - "Version": "1.5.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4e6dabb220b006ccdc3b3b5ff993b205" - }, - "httr": { - "Package": "httr", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7146fea4685b4252ebf478978c75f597" - }, - "isoband": { - "Package": "isoband", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6e58bd3d6b3dd82a944cd6f05ade228f" - }, - "jsonlite": { - "Package": "jsonlite", - "Version": "1.7.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2657f20b9a74c996c602e74ebe540b06" - }, - "labeling": { - "Package": "labeling", - "Version": "0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "73832978c1de350df58108c745ed0e3e" - }, - "later": { - "Package": "later", - "Version": "1.1.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d0a62b247165aabf397fded504660d8a" - }, - "lattice": { - "Package": "lattice", - "Version": "0.20-41", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "fbd9285028b0263d76d18c95ae51a53d" - }, - "lazyeval": { - "Package": "lazyeval", - "Version": "0.2.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "d908914ae53b04d4c0c0fd72ecc35370" - }, - "lifecycle": { - "Package": "lifecycle", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "361811f31f71f8a617a9a68bf63f1f42" - }, - "magrittr": { - "Package": "magrittr", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "41287f1ac7d28a92f0a286ed507928d3" - }, - "mgcv": { - "Package": "mgcv", - "Version": "1.8-31", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4bb7e0c4f3557583e1e8d3c9ffb8ba5c" - }, - "mime": { - "Package": "mime", - "Version": "0.9", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e87a35ec73b157552814869f45a63aa3" - }, - "munsell": { - "Package": "munsell", - "Version": "0.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6dfe8bf774944bd5595785e3229d8771" - }, - "nlme": { - "Package": "nlme", - "Version": "3.1-148", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "662f52871983ff3e3ef042c62de126df" - }, - "openssl": { - "Package": "openssl", - "Version": "1.4.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b3209c62052922b6c629544d94c8fa8a" - }, - "pillar": { - "Package": "pillar", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "bdf26e55ccb7df3e49a490150277f002" - }, - "pkgbuild": { - "Package": "pkgbuild", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "404684bc4e3685007f9720adf13b06c1" - }, - "pkgconfig": { - "Package": "pkgconfig", - "Version": "2.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "01f28d4278f15c76cddbea05899c5d6f" - }, - "pkgload": { - "Package": "pkgload", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b6b150cd4709e0c0c9b5d51ac4376282" - }, - "plotly": { - "Package": "plotly", - "Version": "4.9.2.9000", - "Source": "GitHub", - "RemoteType": "github", - "Remotes": "rstudio/thematic, ramnathv/htmlwidgets", - "RemoteHost": "api.github.com", - "RemoteRepo": "plotly", - "RemoteUsername": "ropensci", - "RemoteRef": "master", - "RemoteSha": "1d1eddda377685cf900ed4a7b16e7796a24b8fe4", - "Hash": "d2858de9ced9d164806a7aa2eebb8b2c" - }, - "praise": { - "Package": "praise", - "Version": "1.0.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a555924add98c99d2f411e37e7d25e9f" - }, - "prettyunits": { - "Package": "prettyunits", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" - }, - "processx": { - "Package": "processx", - "Version": "3.4.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f4f13345fcb00c51ace12f65dd18749f" - }, - "promises": { - "Package": "promises", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "a8730dcbdd19f9047774909f0ec214a4" - }, - "ps": { - "Package": "ps", - "Version": "1.3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "425d938eb9c02906a8ac98c0c2a306b5" - }, - "purrr": { - "Package": "purrr", - "Version": "0.3.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "97def703420c8ab10d8f0e6c72101e02" - }, - "rappdirs": { - "Package": "rappdirs", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8c8298583adbbe76f3c2220eef71bebc" - }, - "readr": { - "Package": "readr", - "Version": "1.4.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2639976851f71f330264a9c9c3d43a61" - }, - "rematch2": { - "Package": "rematch2", - "Version": "2.1.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "76c9e04c712a05848ae7a23d2f170a40" - }, - "renv": { - "Package": "renv", - "Version": "0.11.0-3", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "renv", - "RemoteUsername": "rstudio", - "RemoteRef": "master", - "RemoteSha": "caf0b39c883168cdd5ebd55a547f6d8689ab8712", - "Hash": "094b6d0b0fe28b14a6780dad836f6356" - }, - "reticulate": { - "Package": "reticulate", - "Version": "1.16", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "5db95d35ae4605b46cea66b6e3bcab3e" - }, - "rjson": { - "Package": "rjson", - "Version": "0.2.20", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7d597f982ee6263716b6a2f28efd29fa" - }, - "rlang": { - "Package": "rlang", - "Version": "0.4.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "c06d2a6887f4b414f8e927afd9ee976a" - }, - "rprojroot": { - "Package": "rprojroot", - "Version": "1.3-2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "f6a407ae5dd21f6f80a6708bbb6eb3ae" - }, - "rstudioapi": { - "Package": "rstudioapi", - "Version": "0.11", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "33a5b27a03da82ac4b1d43268f80088a" - }, - "sass": { - "Package": "sass", - "Version": "0.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "441417bbd40d5bbd07561cc40fb182ed" - }, - "scales": { - "Package": "scales", - "Version": "1.1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6f76f71042411426ec8df6c54f34e6dd" - }, - "shiny": { - "Package": "shiny", - "Version": "1.5.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ee4ed72d7a5047d9e73cf922ad66e9c9" - }, - "shinydashboard": { - "Package": "shinydashboard", - "Version": "0.7.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "133639dc106955eee4ffb8ec73edac37" - }, - "shinydashboardPlus": { - "Package": "shinydashboardPlus", - "Version": "2.0.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1abe63cd90fe33d3ca211525a0b39af9" - }, - "shinyjs": { - "Package": "shinyjs", - "Version": "1.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b40a5207b6624f6e2b8cdb50689cdb69" - }, - "shinypop": { - "Package": "shinypop", - "Version": "0.0.1.920", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteRepo": "shinypop", - "RemoteUsername": "dreamRs", - "RemoteRef": "master", - "RemoteSha": "e3be83f99e85401c59ec7a1dfafa5c92c4f7367b", - "Hash": "095c2c667d27cd2f5829967a48e14229" - }, - "shinythemes": { - "Package": "shinythemes", - "Version": "1.1.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "8f047210d7d68ea4860a3c0d8cced272" - }, - "sourcetools": { - "Package": "sourcetools", - "Version": "0.1.7", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "947e4e02a79effa5d512473e10f41797" - }, - "stringi": { - "Package": "stringi", - "Version": "1.4.6", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "e99d8d656980d2dd416a962ae55aec90" - }, - "stringr": { - "Package": "stringr", - "Version": "1.4.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0759e6b6c0957edb1311028a49a35e76" - }, - "styler": { - "Package": "styler", - "Version": "1.4.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2ec6308547ffe73208cef3ef3766fc33" - }, - "sys": { - "Package": "sys", - "Version": "3.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "507f3116a38d37ad330a038b3be07b66" - }, - "testthat": { - "Package": "testthat", - "Version": "2.3.2", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "0829b987b8961fb07f3b1b64a2fbc495" - }, - "tibble": { - "Package": "tibble", - "Version": "3.0.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "08bd36bd34b20d4f7971d49e81deaab0" - }, - "tidyr": { - "Package": "tidyr", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7395a05640bf91502dd475a84008d87e" - }, - "tidyselect": { - "Package": "tidyselect", - "Version": "1.1.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "6ea435c354e8448819627cf686f66e0a" - }, - "utf8": { - "Package": "utf8", - "Version": "1.1.4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "4a5081acfb7b81a572e4384a7aaf2af1" - }, - "vctrs": { - "Package": "vctrs", - "Version": "0.3.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "1739235995f08583db4095a28c357207" - }, - "viridisLite": { - "Package": "viridisLite", - "Version": "0.3.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ce4f6271baa94776db692f1cb2055bee" - }, - "waiter": { - "Package": "waiter", - "Version": "0.1.3", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "7bfebcea9f02aa9b2821fb4f529031e6" - }, - "withr": { - "Package": "withr", - "Version": "2.2.0", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ecd17882a0b4419545691e095b74ee89" - }, - "xfun": { - "Package": "xfun", - "Version": "0.15", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "ddeca7650052ff9131ac7c41a9a77b3b" - }, - "xtable": { - "Package": "xtable", - "Version": "1.8-4", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" - }, - "yaml": { - "Package": "yaml", - "Version": "2.2.1", - "Source": "Repository", - "Repository": "CRAN", - "Hash": "2826c5d9efb0a88f657c7a679c7106db" - } - } -} From 551ef0896c9e5d39e32e528cf1de62ce87c32556 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:10:43 -0800 Subject: [PATCH 245/260] Delete renv directory --- renv/.gitignore | 3 - renv/activate.R | 157 ---------------------------------------------- renv/settings.dcf | 5 -- 3 files changed, 165 deletions(-) delete mode 100644 renv/.gitignore delete mode 100644 renv/activate.R delete mode 100644 renv/settings.dcf diff --git a/renv/.gitignore b/renv/.gitignore deleted file mode 100644 index 82740ba9..00000000 --- a/renv/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -library/ -python/ -staging/ diff --git a/renv/activate.R b/renv/activate.R deleted file mode 100644 index 924c2d38..00000000 --- a/renv/activate.R +++ /dev/null @@ -1,157 +0,0 @@ - -local({ - - # the requested version of renv - version <- "0.8.2" - - # avoid recursion - if (!is.na(Sys.getenv("RENV_R_INITIALIZING", unset = NA))) - return(invisible(TRUE)) - - # signal that we're loading renv during R startup - Sys.setenv("RENV_R_INITIALIZING" = "true") - on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE) - - # signal that we've consented to use renv - options(renv.consent = TRUE) - - # load the 'utils' package eagerly -- this ensures that renv shims, which - # mask 'utils' packages, will come first on the search path - library(utils, lib.loc = .Library) - - # check to see if renv has already been loaded - if ("renv" %in% loadedNamespaces()) { - - # if renv has already been loaded, and it's the requested version of renv, - # nothing to do - spec <- .getNamespaceInfo(.getNamespace("renv"), "spec") - if (identical(spec[["version"]], version)) - return(invisible(TRUE)) - - # otherwise, unload and attempt to load the correct version of renv - unloadNamespace("renv") - - } - - # construct path to renv in library - libpath <- local({ - - root <- Sys.getenv("RENV_PATHS_LIBRARY", unset = "renv/library") - prefix <- paste("R", getRversion()[1, 1:2], sep = "-") - - # include SVN revision for development versions of R - # (to avoid sharing platform-specific artefacts with released versions of R) - devel <- - identical(R.version[["status"]], "Under development (unstable)") || - identical(R.version[["nickname"]], "Unsuffered Consequences") - - if (devel) - prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r") - - file.path(root, prefix, R.version$platform) - - }) - - # try to load renv from the project library - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) - return(renv::load()) - - # failed to find renv locally; we'll try to install from GitHub. - # first, set up download options as appropriate (try to use GITHUB_PAT) - install_renv <- function() { - - message("Failed to find installation of renv -- attempting to bootstrap...") - - # ensure .Rprofile doesn't get executed - rpu <- Sys.getenv("R_PROFILE_USER", unset = NA) - Sys.setenv(R_PROFILE_USER = "") - on.exit({ - if (is.na(rpu)) - Sys.unsetenv("R_PROFILE_USER") - else - Sys.setenv(R_PROFILE_USER = rpu) - }, add = TRUE) - - # prepare download options - pat <- Sys.getenv("GITHUB_PAT") - if (nzchar(Sys.which("curl")) && nzchar(pat)) { - fmt <- "--location --fail --header \"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "curl", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } else if (nzchar(Sys.which("wget")) && nzchar(pat)) { - fmt <- "--header=\"Authorization: token %s\"" - extra <- sprintf(fmt, pat) - saved <- options("download.file.method", "download.file.extra") - options(download.file.method = "wget", download.file.extra = extra) - on.exit(do.call(base::options, saved), add = TRUE) - } - - # fix up repos - repos <- getOption("repos") - on.exit(options(repos = repos), add = TRUE) - repos[repos == "@CRAN@"] <- "https://cloud.r-project.org" - options(repos = repos) - - # check for renv on CRAN matching this version - db <- as.data.frame(available.packages(), stringsAsFactors = FALSE) - if ("renv" %in% rownames(db)) { - entry <- db["renv", ] - if (identical(entry$Version, version)) { - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - utils::install.packages("renv", lib = libpath, quiet = TRUE) - message("Done!") - return(TRUE) - } - } - - # try to download renv - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - prefix <- "https://api.github.com" - url <- file.path(prefix, "repos/rstudio/renv/tarball", version) - destfile <- tempfile("renv-", fileext = ".tar.gz") - on.exit(unlink(destfile), add = TRUE) - utils::download.file(url, destfile = destfile, mode = "wb", quiet = TRUE) - message("Done!") - - # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) - dir.create(libpath, showWarnings = FALSE, recursive = TRUE) - - # invoke using system2 so we can capture and report output - bin <- R.home("bin") - exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) - args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(libpath), shQuote(destfile)) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - text <- c("Error installing renv", "=====================", output) - writeLines(text, con = stderr()) - } - - - } - - try(install_renv()) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) - -}) diff --git a/renv/settings.dcf b/renv/settings.dcf deleted file mode 100644 index d04fb5e1..00000000 --- a/renv/settings.dcf +++ /dev/null @@ -1,5 +0,0 @@ -external.libraries: -ignored.packages: -snapshot.type: packrat -use.cache: TRUE -vcs.ignore.library: TRUE From 7573e52fabd710384f7935826affceaac7aae7b3 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:10:58 -0800 Subject: [PATCH 246/260] Update .Rprofile --- .Rprofile | 1 - 1 file changed, 1 deletion(-) diff --git a/.Rprofile b/.Rprofile index 407da0f4..4d0e2079 100644 --- a/.Rprofile +++ b/.Rprofile @@ -8,4 +8,3 @@ } options(stringsAsFactors = FALSE) -source("renv/activate.R") From c24196badf4e44d2bd0437439554e3c111e0fdad Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:21:12 -0800 Subject: [PATCH 247/260] Create schematic_config.yml --- .github/schematic_config.yml | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/schematic_config.yml diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml new file mode 100644 index 00000000..d266b752 --- /dev/null +++ b/.github/schematic_config.yml @@ -0,0 +1,42 @@ +# During the github workflow to auto deploy the app +# This config file will be used to overwrite the config.yml in the schematic folder +# +# Please modify the configuration values based on your project + +# Do not change the 'definitions' section unless you know what you're doing +definitions: + synapse_config: ".synapseConfig" + creds_path: "credentials.json" + token_pickle: "token.pickle" + service_acct_creds: "schematic_service_account_creds.json" + +synapse: + master_fileview: 'syn16858331' + manifest_folder: 'manifests' + manifest_filename: 'data/manifests/synapse_storage_manifest.csv' + token_creds: 'syn21088684' + service_acct_creds: 'syn25171627' + +manifest: + title: 'NF' + data_type: 'NF' + +model: + input: + location: 'NF.jsonld' + file_type: 'local' + validation_schema: 'data/validation_schemas/example_validation_schema.json' + log_location: 'data/json_schema_logs/json_schema_log.json' + +style: + google_manifest: + req_bg_color: + red: 0.9215 + green: 0.9725 + blue: 0.9803 + opt_bg_color: + red: 1.0 + green: 1.0 + blue: 0.9019 + master_template_id: '1LYS5qE4nV9jzcYw5sXwCza25slDfRA1CIg3cs-hCdpU' + strict_validation: false From 354d4b269186dc79084b3e42b4971f7f37c8431c Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 11:41:32 -0800 Subject: [PATCH 248/260] Update schematic_config.yml --- .github/schematic_config.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index d266b752..0007f60b 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -23,11 +23,9 @@ manifest: model: input: - location: 'NF.jsonld' - file_type: 'local' - validation_schema: 'data/validation_schemas/example_validation_schema.json' - log_location: 'data/json_schema_logs/json_schema_log.json' - + download_url: 'https://raw.githubusercontent.com/nf-osi/nf-metadata-dictionary/v3.0.2/NF.jsonld' # url to download JSON-LD data model + location: 'NF.jsonld' # path to JSON-LD data model + file_type: 'local' # only type "local" is supported currently style: google_manifest: req_bg_color: From 087051f231082e1493148125aa6d52daf618cf69 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 12:14:21 -0800 Subject: [PATCH 249/260] Update global.R --- global.R | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/global.R b/global.R index 88bfb1eb..49c2b375 100644 --- a/global.R +++ b/global.R @@ -1,19 +1,44 @@ +suppressPackageStartupMessages({ + library(yaml) + library(reticulate) +}) + +oauth_client <- yaml.load_file("oauth_config.yml") + +client_id <- toString(oauth_client$CLIENT_ID) +client_secret <- toString(oauth_client$CLIENT_SECRET) +app_url <- toString(oauth_client$APP_URL) + +if (is.null(client_id) || nchar(client_id) == 0) stop("oauth_config.yml is missing CLIENT_ID") +if (is.null(client_secret) || nchar(client_secret) == 0) stop("oauth_config.yml is missing CLIENT_SECRET") +if (is.null(app_url) || nchar(app_url) == 0) stop("oauth_config.yml is missing APP_URL") + +# ShinyAppys has a limit of 7000 files which this app' grossly exceeds +# due to its Python dependencies. To get around the limit we zip up +# the virtual environment before deployment and unzip it here. +# +# unzip virtual environment, named as ".venv.zip" +if (!file.exists(".venv")) utils::unzip(".venv.zip") + +# We get a '126' error (non-executable) if we don't do this: +system("chmod -R +x .venv") + +# Activate virtual env +# Don't necessarily have to set `RETICULATE_PYTHON` env variable +Sys.unsetenv("RETICULATE_PYTHON") +reticulate::use_virtualenv(file.path(getwd(), ".venv")) + suppressPackageStartupMessages({ library(shiny) library(httr) - library(rjson) - library(yaml) library(shinyjs) library(dplyr) + library(tidyr) library(shinythemes) library(shinydashboard) library(stringr) library(DT) library(jsonlite) - library(reticulate) - library(ggplot2) - library(purrr) - library(plotly) library(shinypop) library(waiter) library(readr) @@ -21,8 +46,6 @@ suppressPackageStartupMessages({ library(shinydashboardPlus) }) -# APP_URL <- "https://shinypro.synapse.org/users/spatil/HTAN-oauth/" - has_auth_code <- function(params) { # params is a list object containing the parsed URL parameters. Return TRUE if # based on these parameters, it looks like auth code is present that we can @@ -31,19 +54,10 @@ has_auth_code <- function(params) { return(!is.null(params$code)) } -oauth_client <- yaml.load_file("config.yaml") - -client_id <- toString(oauth_client$client_id) -client_secret <- oauth_client$client_secret -APP_URL <- oauth_client$APP_URL -if (is.null(client_id)) stop("config.yaml is missing client_id") -if (is.null(client_secret)) stop("config.yaml is missing client_secret") -if (is.null(APP_URL)) stop("config.yaml is missing client_secret") - app <- oauth_app("shinysynapse", key = client_id, secret = client_secret, - redirect_uri = APP_URL + redirect_uri = app_url ) # These are the user info details ('claims') requested from Synapse: @@ -75,10 +89,6 @@ api <- oauth_endpoint( # The 'openid' scope is required by the protocol for retrieving user information. scope <- "openid view download modify" -# Activate conda env -# Don't necessarily have to set `RETICULATE_PYTHON` env variable -reticulate::use_condaenv("data_curator_env_oauth") - # Import functions/modules source_files <- list.files(c("functions", "modules"), pattern = "*\\.R$", recursive = TRUE, full.names = TRUE) sapply(source_files, FUN = source) From c44217731c34081d933da94f16e78d4ff251aa1e Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 13:58:32 -0800 Subject: [PATCH 250/260] Update server.R --- server.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.R b/server.R index 62e032f3..7034950a 100644 --- a/server.R +++ b/server.R @@ -10,7 +10,7 @@ shinyServer(function(input, output, session) { return() } redirect_url <- paste0( - api$access, "?", "redirect_uri=", APP_URL, "&grant_type=", + api$access, "?", "redirect_uri=", app_url, "&grant_type=", "authorization_code", "&code=", params$code ) # get the access_token and userinfo token From ca5afb1f1dd392ea2bce5360e324a592c004dd07 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 15:08:35 -0800 Subject: [PATCH 251/260] Bringing server.R up to fork --- server.R | 82 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/server.R b/server.R index 7034950a..cfc0972f 100644 --- a/server.R +++ b/server.R @@ -22,6 +22,8 @@ shinyServer(function(input, output, session) { token_response <- content(req, type = NULL) access_token <- token_response$access_token + session$userData$access_token <- access_token + ######## session global variables ######## source_python("functions/synapse_func_alias.py") source_python("functions/metadata_model.py") @@ -36,13 +38,15 @@ shinyServer(function(input, output, session) { synStore_obj <- NULL # gets list of projects they have access to project_synID <- NULL # selected project synapse ID - folder_synID <- NULL # selected foler synapse ID - template_schema_name <- NULL # selected template schema name + folder_synID <- reactiveVal("") # selected foler synapse ID + template_schema_name <- reactiveVal(NULL) # selected template schema name + template_type <- NULL # type of selected template + isUpdateFolder <- reactiveVal(FALSE) datatype_list <- list(projects = NULL, folders = NULL, manifests = template_namedList, files = NULL) tabs_list <- c("tab_instructions", "tab_data", "tab_template", "tab_upload") - clean_tags <- c("div_download", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") + clean_tags <- c("div_template", "div_validate", NS("tbl_validate", "table"), "btn_val_gsheet", "btn_submit") # add box effects boxEffect(zoom = TRUE, float = TRUE) @@ -51,42 +55,52 @@ shinyServer(function(input, output, session) { # synapse cookies session$sendCustomMessage(type = "readCookie", message = list()) - # login page + # initial loading page + # + # TODO: If we don't use cookies, then what event should trigger this? + # observeEvent(input$cookie, { - # login and update session; otherwise, notify to login to Synapse first - tryCatch( - { - syn_login(sessionToken = input$cookie, rememberMe = FALSE) - - # welcome message - # output$title <- renderUI({ - # titlePanel(h4(sprintf("Welcome, %s", syn_getUserProfile()$userName))) - # }) - - # updating global vars with values for projects - synStore_obj <<- synapse_driver(token = input$cookie) - - # get_projects_list(synStore_obj) - projects_list <- synapse_driver$getStorageProjects(synStore_obj) - datatype_list$projects <<- list2Vector(projects_list) - - # updates project dropdown - lapply(c("header_dropdown_", "dropdown_"), function(x) { - lapply(c(1, 3), function(i) { - updateSelectInput(session, paste0(x, datatypes[i]), - choices = sort(names(datatype_list[[i]])) - ) - }) + # login and update session + # + # The original code pulled the auth token from a cookie, but it + # should actually come from session$userData. The former is + # the Synapse login, only works when the Shiny app' is hosted + # in the synapse.org domain, and is unscoped. The latter will + # work in any domain and is scoped to the access required by the + # Shiny app' + # + access_token <- session$userData$access_token + + syn_login(authToken = access_token, rememberMe = FALSE) + + # updating syn storage + tryCatch(synStore_obj <<- synapse_driver(access_token = access_token), error = function(e) NULL) + + if (is.null(synStore_obj)) { + message("'synapse_driver' fails, run 'synapse_driver' to see detailed error") + dcWaiter("update", landing = TRUE, isPermission = FALSE) + } else { + projects_list <- synapse_driver$getStorageProjects(synStore_obj) + datatype_list$projects <<- list2Vector(projects_list) + + # updates project dropdown + lapply(c("header_dropdown_", "dropdown_"), function(x) { + lapply(c(1, 3), function(i) { + updateSelectInput(session, paste0(x, datatypes[i]), + choices = sort(names(datatype_list[[i]])) + ) }) + }) + user_name <- syn_getUserProfile()$userName + + if (!syn_is_certified(user_name)) { + dcWaiter("update", landing = TRUE, isCertified = FALSE) + } else { # update waiter loading screen once login successful - dcWaiter("update", isLogin = TRUE, isPass = TRUE, usrName = syn_getUserProfile()$userName) - }, - error = function(err) { - message(err) # write log error - dcWaiter("update", isLogin = TRUE, isPass = FALSE) + dcWaiter("update", landing = TRUE, userName = user_name) } - ) + } }) From a1e44b4d7a1872b507a17b618e4b3c536928ab68 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:20:46 -0800 Subject: [PATCH 252/260] NF customizations Adding back in NF custom parameters. --- server.R | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server.R b/server.R index 12feaa1a..b4dc58e8 100644 --- a/server.R +++ b/server.R @@ -155,7 +155,9 @@ shinyServer(function(input, output, session) { projectID <- datatype_list$projects[[input[[paste0(x, "project")]]]] # gets folders per project - folder_list <- synapse_driver$getStorageDatasetsInProject(synStore_obj, projectID) %>% list2Vector() + folder_df <- syn_tableQuery(sprintf("select name, id from %s where type = 'folder' and projectId = '%s'", config$main_fileview, projectID))$asDataFrame() + + folder_list <- setNames(as.list(folder_df$id), folder_df$name) # updates foldernames updateSelectInput(session, paste0(x, "folder"), choices = sort(names(folder_list))) @@ -237,7 +239,8 @@ shinyServer(function(input, output, session) { NULL, as.list(names(datatype_list$files)) ), - datasetId = folder_synID() + datasetId = folder_synID(), + useAnnotations = T ) # generate link From 8a33b0eddaad9c86078d1353e7f27c37d7eaa90d Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:51:41 -0800 Subject: [PATCH 253/260] Delete config.yml --- config.yml | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 config.yml diff --git a/config.yml b/config.yml deleted file mode 100644 index c07f30c9..00000000 --- a/config.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Do not change the 'definitions' section unless you know what you're doing -definitions: - synapse_config: ".synapseConfig" - creds_path: "credentials.json" - token_pickle: "token.pickle" - service_acct_creds: "schematic_service_account_creds.json" - -synapse: - master_fileview: 'syn16858331' - manifest_folder: 'manifests' - manifest_filename: 'data/manifests/synapse_storage_manifest.csv' - token_creds: 'syn21088684' - service_acct_creds: 'syn25171627' - -manifest: - title: 'NF' - data_type: 'NF' - -model: - input: - location: 'NF.jsonld' - file_type: 'local' - validation_schema: 'data/validation_schemas/example_validation_schema.json' - log_location: 'data/json_schema_logs/json_schema_log.json' - -style: - google_manifest: - req_bg_color: - red: 0.9215 - green: 0.9725 - blue: 0.9803 - opt_bg_color: - red: 1.0 - green: 1.0 - blue: 0.9019 - master_template_id: '1LYS5qE4nV9jzcYw5sXwCza25slDfRA1CIg3cs-hCdpU' - strict_validation: false From d5f720a2d2a0df3373268b4bb7bd733014245af2 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:52:13 -0800 Subject: [PATCH 254/260] Rename deploy.yml to shiny_deploy.yml --- .github/workflows/{deploy.yml => shiny_deploy.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{deploy.yml => shiny_deploy.yml} (100%) diff --git a/.github/workflows/deploy.yml b/.github/workflows/shiny_deploy.yml similarity index 100% rename from .github/workflows/deploy.yml rename to .github/workflows/shiny_deploy.yml From da5693ba7470a0b430da8ab7043059cdbd3c1709 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:54:53 -0800 Subject: [PATCH 255/260] Delete shinyapps_deploy.yml --- .github/workflows/shinyapps_deploy.yml | 117 ------------------------- 1 file changed, 117 deletions(-) delete mode 100644 .github/workflows/shinyapps_deploy.yml diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml deleted file mode 100644 index 4e720be0..00000000 --- a/.github/workflows/shinyapps_deploy.yml +++ /dev/null @@ -1,117 +0,0 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help - -name: shiny-deploy - -# TODO: remove `shiny-server-develop` when we use shinyapps.io as production site -# also consider to change shiny-server-main to main since we will not host in shinyServer -on: - push: - branches: - - shiny-server-main - - shiny-server-develop # add develop for testing for now - - release* - paths-ignore: - - .github/ISSUE_TEMPLATE/** - -jobs: - shiny-deploy: - runs-on: ubuntu-latest - # This image seems to be based on rocker/r-ver which in turn is based on debian - container: rocker/rstudio - env: - # This should not be necessary for installing from public repo's however remotes::install_github() fails without it. - GITHUB_PAT: ${{ secrets.REPO_PAT }} - - steps: - - name: Install System Dependencies - run: | - sudo apt-get update - sudo apt-get install -y pip python3.8-venv libcurl4-openssl-dev - - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Create and Activate Python Virtual Environment - shell: bash - run: | - python3 -m venv .venv - chmod 755 .venv/bin/activate - source .venv/bin/activate - - - name: Install R Packages Dependencies - run: | - R -f install-pkgs.R - - - name: Install Python Packages Dependencies - shell: bash - run: | - source .venv/bin/activate - pip3 install -r requirements.txt - - - name: Install Schematic - shell: bash - run: | - source .venv/bin/activate - # use 'poetry' to install schematic from the develop branch - pip3 install poetry - git clone --single-branch --branch develop https://github.com/Sage-Bionetworks/schematic.git - cd schematic - poetry build - pip3 install dist/schematicpy-1.0.0-py3-none-any.whl - - - name: Set Configurations for Schematic - shell: bash - run: | - source .venv/bin/activate - # download data model to the correct location - R -e ' - config <- yaml::yaml.load_file(".github/schematic_config.yml"); - url <- config$model$input$download_url; - path <- config$model$input$location; - system(sprintf("mkdir -p %s", dirname(path))); - system(sprintf("wget %s -O %s", url, path)); - ' - # overwrite the config.yml in schematic - mv -f .github/schematic_config.yml schematic/config.yml - # write out configuration files using github secrets - echo "${{ secrets.SCHEMATIC_SYNAPSE_CONFIG }}" > schematic/.synapseConfig - echo "${{ secrets.SCHEMATIC_SERVICE_ACCT_CREDS }}" > schematic/schematic_service_account_creds.json - echo "${{ secrets.SCHEMATIC_CREDS_PATH }}" > schematic/credentials.json - echo "${{ secrets.SCHEMATIC_TOKEN_PICKLE }}" | base64 -d > schematic/token.pickle - - - name: zip virtual env - shell: bash - # ShinyApps has a limit of 7000 files, far exceeded by the many Python dependencies - # that this app' has. As a workaround we zip the virtual environment and later - # unzip it in 'global.R' - run: | - zip -rm .venv.zip .venv - - - name: Authorize and deploy app - shell: Rscript {0} - run: | - branch <- Sys.getenv("GITHUB_REF_NAME") - repo <- Sys.getenv("GITHUB_REPOSITORY") - appName <- strsplit(repo, "/")[[1]][2] - if (!startsWith(branch, "release")) { - appName <- paste(appName, "staging", sep = "-") - } - rsConnectUser <- "${{ secrets.RSCONNECT_USER }}" - rsConnectToken <- "${{ secrets.RSCONNECT_TOKEN }}" - rsConnectSecret <- "${{ secrets.RSCONNECT_SECRET }}" - - # create config file - config <- "CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}" - config <- c(config, "CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}") - appUrl <- sprintf("https://%s.shinyapps.io/%s", rsConnectUser, appName) - config <- c(config, sprintf("APP_URL: %s", appUrl)) - - configFileConn <- file("oauth_config.yml") - tryCatch( - writeLines(config, configFileConn), - finally=close(configFileConn) - ) - rsconnect::setAccountInfo(rsConnectUser, rsConnectToken, rsConnectSecret) - rsconnect::deployApp(appName = appName) From e34aaf265bf4894ad3ce0d8a12a36bb2c030f39f Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:55:18 -0800 Subject: [PATCH 256/260] Rename shiny_deploy.yml to shinyapps_deploy.yml --- .github/workflows/{shiny_deploy.yml => shinyapps_deploy.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{shiny_deploy.yml => shinyapps_deploy.yml} (100%) diff --git a/.github/workflows/shiny_deploy.yml b/.github/workflows/shinyapps_deploy.yml similarity index 100% rename from .github/workflows/shiny_deploy.yml rename to .github/workflows/shinyapps_deploy.yml From c87d75df9154602fb6939e6ac544f27a31b56b42 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 16:57:55 -0800 Subject: [PATCH 257/260] Delete bug-report--app--.md --- .github/ISSUE_TEMPLATE/bug-report--app--.md | 32 --------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug-report--app--.md diff --git a/.github/ISSUE_TEMPLATE/bug-report--app--.md b/.github/ISSUE_TEMPLATE/bug-report--app--.md deleted file mode 100644 index f17e6797..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report--app--.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: 'Bug report (app) ' -about: 'Create a report to help us improve the app. ' -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. From 38e46060cfbbe69d45b472fe9680010bf1f44ea7 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Tue, 22 Feb 2022 17:12:54 -0800 Subject: [PATCH 258/260] Diffclean (#112) * Update schematic_config.yml * Update schematic_config.yml * Update .gitignore * Update install-pkgs.R * Update _message.scss * Update _variables.scss * Update _header.scss * Delete _navigation.scss --- .github/schematic_config.yml | 22 +++++++++++----------- .gitignore | 2 +- www/scss/section/_navigation.scss | 3 --- 3 files changed, 12 insertions(+), 15 deletions(-) delete mode 100644 www/scss/section/_navigation.scss diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index 412ad033..17e06be8 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -5,18 +5,18 @@ # Do not change the 'definitions' section unless you know what you're doing definitions: - synapse_config: ".synapseConfig" - creds_path: "credentials.json" - token_pickle: "token.pickle" - service_acct_creds: "schematic_service_account_creds.json" + synapse_config: '.synapseConfig' + creds_path: 'credentials.json' + token_pickle: 'token.pickle' + service_acct_creds: 'schematic_service_account_creds.json' synapse: - master_fileview: 'syn16858331' - manifest_folder: 'manifests' - manifest_filename: 'data/manifests/synapse_storage_manifest.csv' - token_creds: 'syn21088684' - service_acct_creds: 'syn25171627' - + master_fileview: 'syn16858331' # fileview of project with datasets on Synapse + manifest_folder: 'manifests' # manifests will be downloaded to this folder + manifest_filename: 'synapse_storage_manifest.csv' # name of the manifest file in the project dataset + token_creds: 'syn21088684' # synapse ID of credentials.json file + service_acct_creds: 'syn25171627' # synapse ID of service_account_creds.json file + manifest: title: 'NF' data_type: 'NF' @@ -24,7 +24,7 @@ manifest: model: input: download_url: 'https://raw.githubusercontent.com/nf-osi/nf-metadata-dictionary/v3.0.2/NF.jsonld' # url to download JSON-LD data model - location: 'NF.jsonld' # path to JSON-LD data model + location: 'data-models/NF.jsonld' # path to JSON-LD data model file_type: 'local' # only type "local" is supported currently style: diff --git a/.gitignore b/.gitignore index 7206e965..dab873e6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,4 @@ oauth_config.yml .project .settings/** .venv -data-models/ \ No newline at end of file +data-models/ diff --git a/www/scss/section/_navigation.scss b/www/scss/section/_navigation.scss deleted file mode 100644 index c06cdc59..00000000 --- a/www/scss/section/_navigation.scss +++ /dev/null @@ -1,3 +0,0 @@ -.navbar { - min-height: 50px !important -} \ No newline at end of file From a4af5088d7518d557b1db94e10250a8bc4585586 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Wed, 23 Feb 2022 15:47:00 -0800 Subject: [PATCH 259/260] update data type to list --- .github/schematic_config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/schematic_config.yml b/.github/schematic_config.yml index 17e06be8..d9ca1a7f 100644 --- a/.github/schematic_config.yml +++ b/.github/schematic_config.yml @@ -19,7 +19,8 @@ synapse: manifest: title: 'NF' - data_type: 'NF' + data_type: + - 'NF' model: input: From 11ecdc27d75089aa516ee94458390bcb8ce9be50 Mon Sep 17 00:00:00 2001 From: Robert Allaway Date: Thu, 24 Feb 2022 10:07:32 -0800 Subject: [PATCH 260/260] Update shinyapps_deploy.yml --- .github/workflows/shinyapps_deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shinyapps_deploy.yml b/.github/workflows/shinyapps_deploy.yml index 7758df72..b609cbb8 100644 --- a/.github/workflows/shinyapps_deploy.yml +++ b/.github/workflows/shinyapps_deploy.yml @@ -9,6 +9,7 @@ on: push: branches: - develop # add develop for testing for now + tags: - release* paths-ignore: - .github/ISSUE_TEMPLATE/**