From 2d0d7044b3d2e2ff06b28efda75632f096f58779 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:44:37 -0500 Subject: [PATCH 01/49] Add very basic checkbox column to tables --- R/fct_tables.R | 12 ++++++++++++ R/mod_common_forms.R | 38 +++++++++++++++++++++++++++++++++----- R/mod_study_forms.R | 16 +++++++++++++++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/R/fct_tables.R b/R/fct_tables.R index 6d9337a1..cbe45ddf 100644 --- a/R/fct_tables.R +++ b/R/fct_tables.R @@ -51,6 +51,17 @@ create_table.default <- function( stopifnot(is.character(keep_vars)) stopifnot(is.character(name_column)) stopifnot(is.character(value_column)) + if ("reviewed" %in% names(data)) { + data <- dplyr::mutate( + data, + o_reviewed = dplyr::case_when( + any(reviewed == "No") & any(reviewed == "Yes") ~ NA, + any(reviewed == "Yes") ~ TRUE, + .default = FALSE + ), + .by = keep_vars) + keep_vars <- c("o_reviewed", keep_vars) + } df <- data[c(keep_vars, name_column, value_column)] |> tidyr::pivot_wider( names_from = {{name_column}}, @@ -298,6 +309,7 @@ create_table.medication <- function( ) |> dplyr::arrange(dplyr::desc(in_use), dplyr::desc(`Start Date`)) |> dplyr::select( + dplyr::any_of("o_reviewed"), dplyr::all_of(c(keep_vars, "Name")), dplyr::everything(), -dplyr::all_of(c("in_use", "Active Ingredient", "Trade Name", diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 09f0f833..ed46e279 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -125,15 +125,29 @@ mod_common_forms_server <- function( SAE_data <- data_active() |> dplyr::filter(grepl("Yes", `Serious Adverse Event`)) |> dplyr::select(dplyr::any_of( - c("subject_id","form_repeat", "Name", "AESI", "SAE Start date", + c("o_reviewed", "subject_id","form_repeat", "Name", "AESI", "SAE Start date", "SAE End date", "CTCAE severity", "Treatment related", "Treatment action", "Other action", "SAE Category", "SAE Awareness date", "SAE Date of death", "SAE Death reason") )) |> adjust_colnames("^SAE ") if(!input$show_all_data) SAE_data$subject_id <- NULL - datatable_custom(SAE_data, rename_vars = table_names, rownames= FALSE, - title = "Serious Adverse Events", escape = FALSE) + datatable_custom( + SAE_data, + rename_vars = table_names, + rownames= FALSE, + title = "Serious Adverse Events", + escape = FALSE, + options = list( + columnDefs = list(list( + targets = 0, + render = DT::JS( + "function(data, type, row, meta) {", + "return ``;", + "}" + ) + )) + )) }) output[["common_form_table"]] <- DT::renderDT({ @@ -145,8 +159,22 @@ mod_common_forms_server <- function( dplyr::select(-dplyr::starts_with("SAE")) } if(!input$show_all_data) df$subject_id <- NULL - datatable_custom(df, rename_vars = table_names, rownames= FALSE, - title = form, escape = FALSE) + datatable_custom( + df, + rename_vars = table_names, + rownames= FALSE, + title = form, + escape = FALSE, + options = list( + columnDefs = list(list( + targets = 0, + render = DT::JS( + "function(data, type, row, meta) {", + "return ``;", + "}" + ) + )) + )) }) }) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index bbf45905..8bfef958 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -223,7 +223,21 @@ mod_study_forms_server <- function( output[["table"]] <- DT::renderDT({ req(table_data_active()) - datatable_custom(table_data_active(), table_names, escape = FALSE) + datatable_custom( + table_data_active(), + table_names, + rownames= FALSE, + escape = FALSE, + options = list( + columnDefs = list(list( + targets = 0, + render = DT::JS( + "function(data, type, row, meta) {", + "return ``;", + "}" + ) + )) + )) }) if(form %in% c("Vital signs", "Vitals adjusted")){ From 67d817f7fc37ed362ce3c3bd6e78dc846646c87d Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:20:21 -0500 Subject: [PATCH 02/49] "Highlight" rows when check status changed --- R/mod_common_forms.R | 12 ++++++++++-- R/mod_study_forms.R | 12 ++++++++++-- inst/app/www/custom.css | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index ed46e279..5bff4e79 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -170,10 +170,18 @@ mod_common_forms_server <- function( targets = 0, render = DT::JS( "function(data, type, row, meta) {", - "return ``;", + "return ``;", "}" ) - )) + )), + createdRow = DT::JS( + "function(row, data, dataIndex) {", + "if (data[0] == null) {", + "let cb = row.cells[0].getElementsByTagName('input')[0]", + "cb.indeterminate = cb.readOnly = true;", + "}", + "}" + ) )) }) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 8bfef958..78998f97 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -233,10 +233,18 @@ mod_study_forms_server <- function( targets = 0, render = DT::JS( "function(data, type, row, meta) {", - "return ``;", + "return ``;", "}" ) - )) + )), + createdRow = DT::JS( + "function(row, data, dataIndex) {", + "if (data[0] == null) {", + "let cb = row.cells[0].getElementsByTagName('input')[0]", + "cb.indeterminate = cb.readOnly = true;", + "}", + "}" + ) )) }) diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index 5232a222..d1125951 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -61,3 +61,17 @@ div.datatables div.header { font-weight: bold; } +tr:has(td input[type="checkbox"].checked:not(:checked))>td { + background-color: aquamarine; + border-color: aquamarine; +} + +tr:has(td input[type="checkbox"].unchecked:checked)>td { + background-color: aquamarine; + border-color: aquamarine; +} + +tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate))>td { + background-color: aquamarine; + border-color: aquamarine; +} From 7939b3ca6016d28af5931750a2c74d27b1d771e7 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:44:54 -0500 Subject: [PATCH 03/49] Grab id's for `o_reviewed` --- R/fct_tables.R | 6 +++--- R/mod_common_forms.R | 3 ++- R/mod_study_forms.R | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/R/fct_tables.R b/R/fct_tables.R index cbe45ddf..8a31bafe 100644 --- a/R/fct_tables.R +++ b/R/fct_tables.R @@ -55,9 +55,9 @@ create_table.default <- function( data <- dplyr::mutate( data, o_reviewed = dplyr::case_when( - any(reviewed == "No") & any(reviewed == "Yes") ~ NA, - any(reviewed == "Yes") ~ TRUE, - .default = FALSE + any(reviewed == "No") & any(reviewed == "Yes") ~ list(list(reviewed = NA, ids = id)), + any(reviewed == "Yes") ~ list(list(reviewed = TRUE, ids = id)), + .default = list(list(reviewed = FALSE, ids = id)) ), .by = keep_vars) keep_vars <- c("o_reviewed", keep_vars) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 5bff4e79..58dc179b 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -170,7 +170,8 @@ mod_common_forms_server <- function( targets = 0, render = DT::JS( "function(data, type, row, meta) {", - "return ``;", + "var reviewed = data.reviewed;", + "return ``;", "}" ) )), diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 78998f97..ee9c8568 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -233,7 +233,8 @@ mod_study_forms_server <- function( targets = 0, render = DT::JS( "function(data, type, row, meta) {", - "return ``;", + "var reviewed = data.reviewed;", + "return ``;", "}" ) )), From e3bb3ed5fa33ac5c6be9588342a839e92e6d8437 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:27:55 -0500 Subject: [PATCH 04/49] Add input handler --- R/mod_common_forms.R | 10 ++++++++++ R/mod_study_forms.R | 10 ++++++++++ R/shiny.R | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 R/shiny.R diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 58dc179b..e2f36b1a 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -165,6 +165,16 @@ mod_common_forms_server <- function( rownames= FALSE, title = form, escape = FALSE, + callback = DT::JS( + "table.on('click', 'input[type=\"checkbox\"]', function(){", + "var id = $(this).closest('.datatables').attr('id');", + "var cell = table.cell($(this).closest('td'));", + "var ids = cell.data().ids;", + "var review = $(this).is(':checked');", + "var info = {review: review, ids: ids};", + "Shiny.setInputValue(id + '_review_selection:CS.reviewInfo', info);", + "})" + ), options = list( columnDefs = list(list( targets = 0, diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index ee9c8568..5450ab7f 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -228,6 +228,16 @@ mod_study_forms_server <- function( table_names, rownames= FALSE, escape = FALSE, + callback = DT::JS( + "table.on('click', 'input[type=\"checkbox\"]', function(){", + "var id = $(this).closest('.datatables').attr('id');", + "var cell = table.cell($(this).closest('td'));", + "var ids = cell.data().ids;", + "var review = $(this).is(':checked');", + "var info = {review: review, ids: ids};", + "Shiny.setInputValue(id + '_review_selection:CS.reviewInfo', info);", + "})" + ), options = list( columnDefs = list(list( targets = 0, diff --git a/R/shiny.R b/R/shiny.R new file mode 100644 index 00000000..43964b72 --- /dev/null +++ b/R/shiny.R @@ -0,0 +1,4 @@ +shiny::registerInputHandler('CS.reviewInfo', function(val, ...) { + val[["ids"]] <- unlist(val[["ids"]]) + val +}, TRUE) \ No newline at end of file From 6e258a21a17efbc7c1f82fca99e071aba886fdb3 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 09:45:14 -0500 Subject: [PATCH 05/49] Capture row index info --- R/app_server.R | 2 ++ R/mod_common_forms.R | 22 +++++++++++++++++++--- R/shiny.R | 9 ++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/R/app_server.R b/R/app_server.R index 0135aacb..af0d25bb 100644 --- a/R/app_server.R +++ b/R/app_server.R @@ -30,6 +30,8 @@ app_server <- function( }) check_appdata(app_data, meta) + session$userData$review_records <- reactiveValues() + res_auth <- authenticate_server( all_sites = app_vars$Sites$site_code, credentials_db = credentials_db, diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index e2f36b1a..c25deb33 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -94,6 +94,7 @@ mod_common_forms_server <- function( ns <- session$ns data_active <- reactive({ + req(!is.null(input$show_all_data)) shiny::validate(need( !is.null(r$filtered_data[[form]]), paste0("Warning: no data found in the database for the form '", form, "'.") @@ -150,6 +151,20 @@ mod_common_forms_server <- function( )) }) + observeEvent(data_active(), { + session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character(), row_index = character()) + }) + + observeEvent(input$common_form_table_review_selection, { + session$userData$review_records[[form]] <- + dplyr::rows_upsert( + session$userData$review_records[[form]], + input$common_form_table_review_selection, + by = "id" + ) |> + dplyr::arrange(id) + }) + output[["common_form_table"]] <- DT::renderDT({ df <- data_active() if(form == "Adverse events") { @@ -167,12 +182,13 @@ mod_common_forms_server <- function( escape = FALSE, callback = DT::JS( "table.on('click', 'input[type=\"checkbox\"]', function(){", - "var id = $(this).closest('.datatables').attr('id');", + "var tblId = $(this).closest('.datatables').attr('id');", "var cell = table.cell($(this).closest('td'));", + "var rowIdx = table.row($(this).closest('tr')).index();", "var ids = cell.data().ids;", "var review = $(this).is(':checked');", - "var info = {review: review, ids: ids};", - "Shiny.setInputValue(id + '_review_selection:CS.reviewInfo', info);", + "var info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};", + "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", "})" ), options = list( diff --git a/R/shiny.R b/R/shiny.R index 43964b72..4189c23e 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -1,4 +1,7 @@ shiny::registerInputHandler('CS.reviewInfo', function(val, ...) { - val[["ids"]] <- unlist(val[["ids"]]) - val -}, TRUE) \ No newline at end of file + with(val, data.frame( + id = unlist(ids), + reviewed = ifelse(review, "Yes", "No"), + row_index = row + )) +}, TRUE) From a42049b6a41f4e95fa4a71dcf7b8e3c5b0fe747e Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 09:52:17 -0500 Subject: [PATCH 06/49] Standardize callbacks and renders --- R/mod_common_forms.R | 13 +++++++------ R/mod_study_forms.R | 27 +++------------------------ R/shiny.R | 28 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index c25deb33..12ad93c2 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -139,15 +139,13 @@ mod_common_forms_server <- function( rownames= FALSE, title = "Serious Adverse Events", escape = FALSE, + callback = checkbox_callback, options = list( columnDefs = list(list( targets = 0, - render = DT::JS( - "function(data, type, row, meta) {", - "return ``;", - "}" - ) - )) + render = checkbox_render + )), + createdRow = checkbox_create_callback )) }) @@ -191,6 +189,7 @@ mod_common_forms_server <- function( "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", "})" ), + callback = checkbox_callback, options = list( columnDefs = list(list( targets = 0, @@ -200,6 +199,7 @@ mod_common_forms_server <- function( "return ``;", "}" ) + render = checkbox_render )), createdRow = DT::JS( "function(row, data, dataIndex) {", @@ -209,6 +209,7 @@ mod_common_forms_server <- function( "}", "}" ) + createdRow = checkbox_create_callback )) }) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 5450ab7f..aa60f058 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -228,34 +228,13 @@ mod_study_forms_server <- function( table_names, rownames= FALSE, escape = FALSE, - callback = DT::JS( - "table.on('click', 'input[type=\"checkbox\"]', function(){", - "var id = $(this).closest('.datatables').attr('id');", - "var cell = table.cell($(this).closest('td'));", - "var ids = cell.data().ids;", - "var review = $(this).is(':checked');", - "var info = {review: review, ids: ids};", - "Shiny.setInputValue(id + '_review_selection:CS.reviewInfo', info);", - "})" - ), + callback = checkbox_callback, options = list( columnDefs = list(list( targets = 0, - render = DT::JS( - "function(data, type, row, meta) {", - "var reviewed = data.reviewed;", - "return ``;", - "}" - ) + render = checkbox_render )), - createdRow = DT::JS( - "function(row, data, dataIndex) {", - "if (data[0] == null) {", - "let cb = row.cells[0].getElementsByTagName('input')[0]", - "cb.indeterminate = cb.readOnly = true;", - "}", - "}" - ) + createdRow = checkbox_create_callback )) }) diff --git a/R/shiny.R b/R/shiny.R index 4189c23e..500b1acf 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -5,3 +5,31 @@ shiny::registerInputHandler('CS.reviewInfo', function(val, ...) { row_index = row )) }, TRUE) + +checkbox_callback <- DT::JS( + "table.on('click', 'input[type=\"checkbox\"]', function(){", + "var tblId = $(this).closest('.datatables').attr('id');", + "var cell = table.cell($(this).closest('td'));", + "var rowIdx = table.row($(this).closest('tr')).index();", + "var ids = cell.data().ids;", + "var review = $(this).is(':checked');", + "var info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};", + "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", + "})" +) + +checkbox_render <- DT::JS( + "function(data, type, row, meta) {", + "var reviewed = data.reviewed;", + "return ``;", + "}" +) + +checkbox_create_callback <- DT::JS( + "function(row, data, dataIndex) {", + "if (data[0] == null) {", + "let cb = row.cells[0].getElementsByTagName('input')[0]", + "cb.indeterminate = cb.readOnly = true;", + "}", + "}" +) From 7ba17d9f3837b541940d7c0779c7d003670a0517 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:45:09 -0500 Subject: [PATCH 07/49] Add missing observers --- R/mod_common_forms.R | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 12ad93c2..3343f761 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -163,6 +163,16 @@ mod_common_forms_server <- function( dplyr::arrange(id) }) + observeEvent(input$SAE_table_review_selection, { + session$userData$review_records[[form]] <- + dplyr::rows_upsert( + session$userData$review_records[[form]], + input$SAE_table_review_selection, + by = "id" + ) |> + dplyr::arrange(id) + }) + output[["common_form_table"]] <- DT::renderDT({ df <- data_active() if(form == "Adverse events") { @@ -178,37 +188,12 @@ mod_common_forms_server <- function( rownames= FALSE, title = form, escape = FALSE, - callback = DT::JS( - "table.on('click', 'input[type=\"checkbox\"]', function(){", - "var tblId = $(this).closest('.datatables').attr('id');", - "var cell = table.cell($(this).closest('td'));", - "var rowIdx = table.row($(this).closest('tr')).index();", - "var ids = cell.data().ids;", - "var review = $(this).is(':checked');", - "var info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};", - "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", - "})" - ), callback = checkbox_callback, options = list( columnDefs = list(list( targets = 0, - render = DT::JS( - "function(data, type, row, meta) {", - "var reviewed = data.reviewed;", - "return ``;", - "}" - ) render = checkbox_render )), - createdRow = DT::JS( - "function(row, data, dataIndex) {", - "if (data[0] == null) {", - "let cb = row.cells[0].getElementsByTagName('input')[0]", - "cb.indeterminate = cb.readOnly = true;", - "}", - "}" - ) createdRow = checkbox_create_callback )) }) From f0dfcc31588a6a6deccc523ff3eb53221d7d2ef5 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:46:48 -0500 Subject: [PATCH 08/49] Add study form observers --- R/mod_study_forms.R | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index aa60f058..56e5eea2 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -163,6 +163,7 @@ mod_study_forms_server <- function( }) table_data_active <- reactive({ + req(!is.null(input$show_all_data)) validate(need( r$filtered_data[[form]], paste0("Warning: no data found in database for the form '", form, "'") @@ -193,6 +194,20 @@ mod_study_forms_server <- function( lapply(add_missing_columns(item_info, cols)[1, cols], isTRUE) }) + observeEvent(table_data_active(), { + session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character(), row_index = character()) + }) + + observeEvent(input$table_review_selection, { + session$userData$review_records[[form]] <- + dplyr::rows_upsert( + session$userData$review_records[[form]], + input$table_review_selection, + by = "id" + ) |> + dplyr::arrange(id) + }) + ############################### Outputs: ################################### dynamic_figure <- reactive({ req(nrow(fig_data()) > 0, scaling_data()) From 9f0e4de79e76aa3cc3ffd137a0bdcf2f4ca6030e Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:54:01 -0500 Subject: [PATCH 09/49] Add `anti_join()`s back --- R/mod_common_forms.R | 8 ++++++++ R/mod_study_forms.R | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 3343f761..06ff5890 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -160,6 +160,10 @@ mod_common_forms_server <- function( input$common_form_table_review_selection, by = "id" ) |> + dplyr::anti_join( + subset(r$review_data, item_group == form), + by = c("id", "reviewed") + ) |> dplyr::arrange(id) }) @@ -170,6 +174,10 @@ mod_common_forms_server <- function( input$SAE_table_review_selection, by = "id" ) |> + dplyr::anti_join( + subset(r$review_data, item_group == form), + by = c("id", "reviewed") + ) |> dplyr::arrange(id) }) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 56e5eea2..676cc84f 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -205,6 +205,10 @@ mod_study_forms_server <- function( input$table_review_selection, by = "id" ) |> + dplyr::anti_join( + subset(r$review_data, item_group == form), + by = c("id", "reviewed") + ) |> dplyr::arrange(id) }) From b703beca663dcf5bef46e64816ad471afc5db40b Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:54:25 -0500 Subject: [PATCH 10/49] First pass at integration in review module --- R/mod_review_forms.R | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index ac31f7dd..ad921b42 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -180,15 +180,13 @@ mod_review_forms_server <- function( enable_save_review <- reactive({ req( - review_data_active(), + active_form(), + session$userData$review_records[[active_form()]], is.logical(input$form_reviewed), is.logical(enable_any_review()) ) if(!enable_any_review()) return(FALSE) - any(c( - unique(with(review_data_active(), reviewed[edit_date_time == max(as.POSIXct(edit_date_time))])) == "No" & input$form_reviewed, - unique(with(review_data_active(), reviewed[edit_date_time == max(as.POSIXct(edit_date_time))])) == "Yes" & !input$form_reviewed - )) + nrow(session$userData$review_records[[active_form()]]) != 0 }) observeEvent(c(enable_any_review(), enable_save_review()), { @@ -226,9 +224,9 @@ mod_review_forms_server <- function( review_save_error(FALSE) golem::cat_dev("Save review status reviewed:", input$form_reviewed, "\n") - review_records <- review_data_active()["id"] |> + review_records <- session$userData$review_records[[active_form()]][c("id", "reviewed")] |> dplyr::mutate( - reviewed = if(input$form_reviewed) "Yes" else "No", + # reviewed = if(input$form_reviewed) "Yes" else "No", comment = ifelse(is.null(input$review_comment), "", input$review_comment), reviewer = paste0(r$user_name, " (", r$user_role, ")"), timestamp = time_stamp(), From 5fd57472efb6e0282d26f1ea466c2fbb5874a8f0 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:26:29 -0500 Subject: [PATCH 11/49] Fix couple of issues --- R/mod_review_forms.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index ad921b42..3e576d18 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -226,11 +226,10 @@ mod_review_forms_server <- function( review_records <- session$userData$review_records[[active_form()]][c("id", "reviewed")] |> dplyr::mutate( - # reviewed = if(input$form_reviewed) "Yes" else "No", comment = ifelse(is.null(input$review_comment), "", input$review_comment), reviewer = paste0(r$user_name, " (", r$user_role, ")"), timestamp = time_stamp(), - status = if(input$form_reviewed) "old" else "new" + status = ifelse(reviewed == "Yes", "old", "new") ) golem::cat_dev("review records to add:\n") @@ -266,7 +265,7 @@ mod_review_forms_server <- function( review_save_error(any( !isTRUE(all.equal(review_records_db, review_records, check.attributes = FALSE)), - !isTRUE(all.equal(updated_items_memory, review_records_db, check.attributes = FALSE)) + !isTRUE(all.equal(updated_items_memory[,names(review_records_db)], review_records_db, check.attributes = FALSE)) )) if(review_save_error()){ From 59562699c6eaaf45e6405edb6a021d18148b545a Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:27:58 -0500 Subject: [PATCH 12/49] Remove row selection --- R/mod_common_forms.R | 2 ++ R/mod_study_forms.R | 1 + 2 files changed, 3 insertions(+) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 06ff5890..5a11dce3 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -139,6 +139,7 @@ mod_common_forms_server <- function( rownames= FALSE, title = "Serious Adverse Events", escape = FALSE, + selection = "none", callback = checkbox_callback, options = list( columnDefs = list(list( @@ -196,6 +197,7 @@ mod_common_forms_server <- function( rownames= FALSE, title = form, escape = FALSE, + selection = "none", callback = checkbox_callback, options = list( columnDefs = list(list( diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 676cc84f..2469c886 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -247,6 +247,7 @@ mod_study_forms_server <- function( table_names, rownames= FALSE, escape = FALSE, + selection = "none", callback = checkbox_callback, options = list( columnDefs = list(list( From d9f49e8afb5d31db75a0349b970edf0055294752 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:30:40 -0500 Subject: [PATCH 13/49] Fix bug on study forms --- R/mod_study_forms.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 2469c886..b007e2b7 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -163,7 +163,7 @@ mod_study_forms_server <- function( }) table_data_active <- reactive({ - req(!is.null(input$show_all_data)) + req(!is.null(input$show_all)) validate(need( r$filtered_data[[form]], paste0("Warning: no data found in database for the form '", form, "'") From 2493779ab2ee03b3da27764e85ff8054a39a03a4 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:17:57 -0500 Subject: [PATCH 14/49] Integrate "form_reviewed" checkbox --- R/mod_common_forms.R | 2 +- R/mod_review_forms.R | 49 +++++++++++++++++++++++++++++++++++++++----- R/shiny.R | 3 +-- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 5a11dce3..01f5e944 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -151,7 +151,7 @@ mod_common_forms_server <- function( }) observeEvent(data_active(), { - session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character(), row_index = character()) + session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character()) }) observeEvent(input$common_form_table_review_selection, { diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index 90b7ede1..fbcbf65c 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -113,13 +113,49 @@ mod_review_forms_server <- function( with(r$review_data, r$review_data[ subject_id == r$subject_id & item_group == active_form(), ]) - }) + }) + + review_indeterminate <- reactiveVal() + + observeEvent(review_indeterminate(), { + shinyjs::runjs(sprintf("$('#%s').prop('indeterminate', %s)", ns("form_reviewed"), tolower(review_indeterminate()))) + }) + + observe({ + req(session$userData$review_records[[active_form()]]) + review_status <- + review_data_active()[,c("id", "reviewed")] |> + dplyr::rows_update(session$userData$review_records[[active_form()]][,c("id", "reviewed")], by = "id") |> + dplyr::distinct(reviewed) |> + dplyr::pull() + + if (length(review_status) == 1) + updateCheckboxInput( + inputId = "form_reviewed", + value = identical(review_status, "Yes") + ) + review_indeterminate(length(review_status) > 1) + }) |> + bindEvent(active_form(), session$userData$review_records[[active_form()]]) + + observeEvent(input$form_reviewed, { + session$userData$review_records[[active_form()]] <- + review_data_active() |> + dplyr::mutate(reviewed = ifelse(input$form_reviewed, "Yes", "No")) |> + dplyr::select(id, reviewed) |> + dplyr::anti_join( + subset(r$review_data, item_group == active_form()), + by = c("id", "reviewed") + ) |> + dplyr::arrange(id) + }) observeEvent(c(active_form(), r$subject_id), { cat("Update confirm review button\n\n\n") req(r$review_data) golem::cat_dev("review_data_active:\n") golem::print_dev(review_data_active()) + review_indeterminate(FALSE) if(nrow(review_data_active()) == 0){ cat("No review data found for Subject id: ", r$subject_id, " and group: ", active_form(), "\n") @@ -131,16 +167,19 @@ mod_review_forms_server <- function( # it will give a warning. This would be rare since it would mean a datapoint with the same edit date-time was reviewed but another one was not. # probably better to use defensive coding here to ensure the app does not crash in that case. However we need to define which review status we need to select # in this case get the reviewed = "No" - review_status <- with(review_data_active(), reviewed[edit_date_time == max(as.POSIXct(edit_date_time))]) |> unique() - review_comment <- with(review_data_active(), comment[edit_date_time == max(as.POSIXct(edit_date_time))]) |> unique() - if(length(review_status) != 1) warning("multiple variables in review_status, namely: ", - review_status, "Verify data.") + review_status <- unique(review_data_active()[["reviewed"]]) + review_comment <- unique(review_data_active()[["comment"]]) + if(length(review_status) != 1) { + review_indeterminate(TRUE) + review_status <- "No" + } } updateCheckboxInput( inputId = "form_reviewed", value = identical(review_status, "Yes") ) + shinyjs::runjs(sprintf("$('#%s').prop('indeterminate', %s)", ns("form_reviewed"), tolower(review_indeterminate()))) shinyWidgets::updatePrettySwitch( session = session, diff --git a/R/shiny.R b/R/shiny.R index 500b1acf..90484d36 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -1,8 +1,7 @@ shiny::registerInputHandler('CS.reviewInfo', function(val, ...) { with(val, data.frame( id = unlist(ids), - reviewed = ifelse(review, "Yes", "No"), - row_index = row + reviewed = ifelse(review, "Yes", "No") )) }, TRUE) From 0cb8710b69c191beef7735133fc187c39325fcae Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:43:41 -0500 Subject: [PATCH 15/49] Update tables from overall checkbox --- R/app_server.R | 1 + R/mod_common_forms.R | 7 +++++++ R/mod_review_forms.R | 32 +++++++++++++++----------------- R/mod_study_forms.R | 6 ++++++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/R/app_server.R b/R/app_server.R index af0d25bb..3d0ff4f0 100644 --- a/R/app_server.R +++ b/R/app_server.R @@ -31,6 +31,7 @@ app_server <- function( check_appdata(app_data, meta) session$userData$review_records <- reactiveValues() + session$userData$update_checkboxes <- reactiveValues() res_auth <- authenticate_server( all_sites = app_vars$Sites$site_code, diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 01f5e944..ffaf57be 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -168,6 +168,13 @@ mod_common_forms_server <- function( dplyr::arrange(id) }) + observeEvent(session$userData$update_checkboxes[[form]], { + checked <- session$userData$update_checkboxes[[form]] + + shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("common_form_table"), tolower(checked))) + shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("SAE_table"), tolower(checked))) + }) + observeEvent(input$SAE_table_review_selection, { session$userData$review_records[[form]] <- dplyr::rows_upsert( diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index fbcbf65c..46c32d48 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -20,7 +20,8 @@ mod_review_forms_ui <- function(id){ inputId = ns("form_reviewed"), label = "Reviewed", value = FALSE - ), + ) |> + shiny::tagAppendAttributes(class = "cs_checkbox", .cssSelector = "input"), "Mark as reviewed", placement = "bottom" ), @@ -129,16 +130,19 @@ mod_review_forms_server <- function( dplyr::distinct(reviewed) |> dplyr::pull() - if (length(review_status) == 1) - updateCheckboxInput( - inputId = "form_reviewed", - value = identical(review_status, "Yes") - ) + shinyjs::runjs(sprintf("$('#%s').prop('checked', %s)", ns("form_reviewed"), tolower(identical(review_status, "Yes")))) review_indeterminate(length(review_status) > 1) }) |> bindEvent(active_form(), session$userData$review_records[[active_form()]]) + observeEvent(r$subject_id, { + session$userData$update_checkboxes[[active_form()]] <- NULL + session$userData$review_records[[active_form()]] <- NULL + }) + observeEvent(input$form_reviewed, { + session$userData$update_checkboxes[[active_form()]] <- input$form_reviewed + session$userData$review_records[[active_form()]] <- review_data_active() |> dplyr::mutate(reviewed = ifelse(input$form_reviewed, "Yes", "No")) |> @@ -148,7 +152,7 @@ mod_review_forms_server <- function( by = c("id", "reviewed") ) |> dplyr::arrange(id) - }) + }, ignoreInit = TRUE) observeEvent(c(active_form(), r$subject_id), { cat("Update confirm review button\n\n\n") @@ -169,16 +173,11 @@ mod_review_forms_server <- function( # in this case get the reviewed = "No" review_status <- unique(review_data_active()[["reviewed"]]) review_comment <- unique(review_data_active()[["comment"]]) - if(length(review_status) != 1) { + if(length(review_status) != 1) review_indeterminate(TRUE) - review_status <- "No" - } } - updateCheckboxInput( - inputId = "form_reviewed", - value = identical(review_status, "Yes") - ) + shinyjs::runjs(sprintf("$('#%s').prop('checked', %s)", ns("form_reviewed"), tolower(identical(review_status, "Yes")))) shinyjs::runjs(sprintf("$('#%s').prop('indeterminate', %s)", ns("form_reviewed"), tolower(review_indeterminate()))) shinyWidgets::updatePrettySwitch( @@ -221,7 +220,6 @@ mod_review_forms_server <- function( req( active_form(), session$userData$review_records[[active_form()]], - is.logical(input$form_reviewed), is.logical(enable_any_review()) ) if(!enable_any_review()) return(FALSE) @@ -258,10 +256,10 @@ mod_review_forms_server <- function( review_save_error <- reactiveVal(FALSE) observeEvent(input$save_review, { - req(is.logical(input$form_reviewed), review_data_active()) + req(review_data_active()) req(enable_save_review()) review_save_error(FALSE) - golem::cat_dev("Save review status reviewed:", input$form_reviewed, "\n") + # golem::cat_dev("Save review status reviewed:", input$form_reviewed, "\n") review_records <- session$userData$review_records[[active_form()]][c("id", "reviewed")] |> dplyr::mutate( diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index b007e2b7..a3a9830d 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -212,6 +212,12 @@ mod_study_forms_server <- function( dplyr::arrange(id) }) + observeEvent(session$userData$update_checkboxes[[form]], { + checked <- session$userData$update_checkboxes[[form]] + + shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("table"), tolower(checked))) + }) + ############################### Outputs: ################################### dynamic_figure <- reactive({ req(nrow(fig_data()) > 0, scaling_data()) From 28943513bde6415e18663c988922ffbda86da7a6 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:59:03 -0500 Subject: [PATCH 16/49] Update `app-feature-1` snapshots --- .../app_feature_01/app-feature-1-002.json | 92 +++++++++----- .../app_feature_01/app-feature-1-003.json | 92 +++++++++----- .../app_feature_01/app-feature-1-004.json | 113 +++++++++++------- .../app_feature_01/app-feature-1-005.json | 113 +++++++++++------- 4 files changed, 262 insertions(+), 148 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json index 2796a847..e02389e1 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -18,66 +18,75 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "Start date", - "targets": 3 + "targets": 4 }, { "name": "End date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Category", - "targets": 9 + "targets": 10 }, { "name": "Awareness date", - "targets": 10 + "targets": 11 }, { "name": "Date of death", - "targets": 11 + "targets": 12 }, { "name": "Death reason", - "targets": 12 + "targets": 13 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -90,16 +99,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -242,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -251,54 +264,63 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "start date", - "targets": 3 + "targets": 4 }, { "name": "end date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Serious Adverse Event", - "targets": 9 + "targets": 10 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -311,16 +333,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json index 76c45761..12f5431a 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -18,66 +18,75 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "Start date", - "targets": 3 + "targets": 4 }, { "name": "End date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Category", - "targets": 9 + "targets": 10 }, { "name": "Awareness date", - "targets": 10 + "targets": 11 }, { "name": "Date of death", - "targets": 11 + "targets": 12 }, { "name": "Death reason", - "targets": 12 + "targets": 13 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -90,16 +99,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -242,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -251,54 +264,63 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "start date", - "targets": 3 + "targets": 4 }, { "name": "end date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Serious Adverse Event", - "targets": 9 + "targets": 10 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -311,16 +333,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json index 76db2408..a0447bc5 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -18,66 +18,75 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "Start date", - "targets": 3 + "targets": 4 }, { "name": "End date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Category", - "targets": 9 + "targets": 10 }, { "name": "Awareness date", - "targets": 10 + "targets": 11 }, { "name": "Date of death", - "targets": 11 + "targets": 12 }, { "name": "Death reason", - "targets": 12 + "targets": 13 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -90,16 +99,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -242,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -251,54 +264,63 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "start date", - "targets": 3 + "targets": 4 }, { "name": "end date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Serious Adverse Event", - "targets": 9 + "targets": 10 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -311,16 +333,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -8270,7 +8296,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -8279,15 +8305,13 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ { - "orderable": false, - "targets": 0 + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": " ", + "name": "o_reviewed", "targets": 0 }, { @@ -8327,6 +8351,9 @@ "targets": 9 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -8339,16 +8366,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json index e683af83..df20d098 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -18,66 +18,75 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "Start date", - "targets": 3 + "targets": 4 }, { "name": "End date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Category", - "targets": 9 + "targets": 10 }, { "name": "Awareness date", - "targets": 10 + "targets": 11 }, { "name": "Date of death", - "targets": 11 + "targets": 12 }, { "name": "Death reason", - "targets": 12 + "targets": 13 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -90,16 +99,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -242,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -251,54 +264,63 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "start date", - "targets": 3 + "targets": 4 }, { "name": "end date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Serious Adverse Event", - "targets": 9 + "targets": 10 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -311,16 +333,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -8271,7 +8297,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -8280,15 +8306,13 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ { - "orderable": false, - "targets": 0 + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": " ", + "name": "o_reviewed", "targets": 0 }, { @@ -8328,6 +8352,9 @@ "targets": 9 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -8340,16 +8367,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ From b27d95dd1dbfd00c63de7f216f729b278460baa9 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:01:58 -0500 Subject: [PATCH 17/49] Update app-feature-3-002.json --- .../app_feature_03/app-feature-3-002.json | 116 ++++++++++++------ 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json index 3a9093e2..7a2a525a 100644 --- a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json +++ b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json @@ -146,6 +146,15 @@ "caseInsensitive": true } }, + { + "visible": true, + "search": { + "search": "", + "smart": true, + "regex": false, + "caseInsensitive": true + } + }, { "visible": true, "search": { @@ -169,7 +178,8 @@ 9, 10, 11, - 12 + 12, + 13 ], "scroller": { "topRow": 0, @@ -295,6 +305,15 @@ "caseInsensitive": true } }, + { + "visible": true, + "search": { + "search": "", + "smart": true, + "regex": false, + "caseInsensitive": true + } + }, { "visible": true, "search": { @@ -315,7 +334,8 @@ 6, 7, 8, - 9 + 9, + 10 ], "scroller": { "topRow": 0, @@ -463,7 +483,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -472,66 +492,75 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "Start date", - "targets": 3 + "targets": 4 }, { "name": "End date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Category", - "targets": 9 + "targets": 10 }, { "name": "Awareness date", - "targets": 10 + "targets": 11 }, { "name": "Date of death", - "targets": 11 + "targets": 12 }, { "name": "Death reason", - "targets": 12 + "targets": 13 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -544,16 +573,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -696,7 +729,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -705,54 +738,63 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ + { + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + }, { "className": "dt-right", + "targets": 1 + }, + { + "name": "o_reviewed", "targets": 0 }, { "name": "N", - "targets": 0 + "targets": 1 }, { "name": "Name", - "targets": 1 + "targets": 2 }, { "name": "AESI", - "targets": 2 + "targets": 3 }, { "name": "start date", - "targets": 3 + "targets": 4 }, { "name": "end date", - "targets": 4 + "targets": 5 }, { "name": "CTCAE severity", - "targets": 5 + "targets": 6 }, { "name": "Treatment related", - "targets": 6 + "targets": 7 }, { "name": "Treatment action", - "targets": 7 + "targets": 8 }, { "name": "Other action", - "targets": 8 + "targets": 9 }, { "name": "Serious Adverse Event", - "targets": 9 + "targets": 10 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -765,16 +807,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ From 36f843ab96d019d13a3e6938a4adfd023fc3218e Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:03:23 -0500 Subject: [PATCH 18/49] Update app_feature_04.md --- tests/testthat/_snaps/app_feature_04.md | 30 ++++++++++++++----------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_04.md b/tests/testthat/_snaps/app_feature_04.md index 5ecee994..65ed6907 100644 --- a/tests/testthat/_snaps/app_feature_04.md +++ b/tests/testthat/_snaps/app_feature_04.md @@ -25,17 +25,21 @@ Code print(table_data, width = Inf) Output - # A tibble: 2 x 9 - event_name `Systolic blood pressure` `Diastolic blood pressure` - - 1 Screening 99* mmHg 77* mmHg - 2 Visit 2 99* mmHg 77* mmHg - Pulse Resp Temperature - - 1 77* beats/min 9* breaths/min 37.5* °C - 2 77* beats/min 9* breaths/min 37.5* °C - `Weight change since screening` BMI Weight - - 1 22.09* kg/m2 70* kg - 2 + # A tibble: 2 x 10 + o_reviewed event_name `Systolic blood pressure` + + 1 Screening 99* mmHg + 2 Visit 2 99* mmHg + `Diastolic blood pressure` Pulse Resp + + 1 77* mmHg 77* beats/min 9* breaths/min + 2 77* mmHg 77* beats/min 9* breaths/min + Temperature `Weight change since screening` BMI + + 1 37.5* °C 22.09* kg/m2 + 2 37.5* °C + Weight + + 1 70* kg + 2 From e98afa047a8010daf05fb57fb01a85d5ba49a2c5 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:14:10 -0500 Subject: [PATCH 19/49] Create custom.js --- inst/app/www/custom.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 inst/app/www/custom.js diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js new file mode 100644 index 00000000..c810c0bc --- /dev/null +++ b/inst/app/www/custom.js @@ -0,0 +1,25 @@ +function ts(cb) { + if (cb.readOnly) cb.checked=cb.readOnly=false; + else if (!cb.checked) cb.readOnly=cb.indeterminate=true; +} + +var customCheckbox = new Shiny.InputBinding(); + +$.extend(customCheckbox, { + find: function(scope) { + return $(scope).find("input[type='checkbox'].cs_checkbox"); + }, + getValue: function(el) { + return el.checked; + }, + subscribe: function(el, callback) { + $(el).on("change.checkboxInputBinding", function() { + Shiny.onInputChange($(this).attr('id'), this.checked, {priority: 'event'}); + }); + }, + unsubscribe: function(el) { + $(el).off(".checkboxInputBinding"); + } +}); + +Shiny.inputBindings.register(customCheckbox); From a353f5d5062c3721a0cb947692558efafb185fc3 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:34:30 -0500 Subject: [PATCH 20/49] Fix warnings and errors in `mod_common_forms` test --- R/fct_tables.R | 2 +- tests/testthat/test-mod_common_forms.R | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/R/fct_tables.R b/R/fct_tables.R index 8a31bafe..e54a425b 100644 --- a/R/fct_tables.R +++ b/R/fct_tables.R @@ -59,7 +59,7 @@ create_table.default <- function( any(reviewed == "Yes") ~ list(list(reviewed = TRUE, ids = id)), .default = list(list(reviewed = FALSE, ids = id)) ), - .by = keep_vars) + .by = dplyr::all_of(keep_vars)) keep_vars <- c("o_reviewed", keep_vars) } df <- data[c(keep_vars, name_column, value_column)] |> diff --git a/tests/testthat/test-mod_common_forms.R b/tests/testthat/test-mod_common_forms.R index 3762094e..909a001e 100644 --- a/tests/testthat/test-mod_common_forms.R +++ b/tests/testthat/test-mod_common_forms.R @@ -52,6 +52,7 @@ describe( }) rev_data <- get_review_data(bind_rows_custom(appdata)) |> dplyr::mutate( + id = dplyr::row_number(), reviewed = sample(c("Yes", "No"), dplyr::n(), replace = TRUE), status = sample(c("new", "old", "updated"), dplyr::n(), replace = TRUE) ) From 579d80e370ce11a13671cdf5ecb2c7f35543c21b Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:01:43 -0500 Subject: [PATCH 21/49] Repair part of `mod_review_form` tests --- R/mod_review_forms.R | 6 +++--- tests/testthat/test-mod_review_forms.R | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index 46c32d48..fa3206bb 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -137,7 +137,7 @@ mod_review_forms_server <- function( observeEvent(r$subject_id, { session$userData$update_checkboxes[[active_form()]] <- NULL - session$userData$review_records[[active_form()]] <- NULL + session$userData$review_records[[active_form()]] <- data.frame(id = integer(), reviewed = character()) }) observeEvent(input$form_reviewed, { @@ -172,7 +172,7 @@ mod_review_forms_server <- function( # probably better to use defensive coding here to ensure the app does not crash in that case. However we need to define which review status we need to select # in this case get the reviewed = "No" review_status <- unique(review_data_active()[["reviewed"]]) - review_comment <- unique(review_data_active()[["comment"]]) + review_comment <- with(review_data_active(), comment[edit_date_time == max(as.POSIXct(edit_date_time))]) |> unique() |> paste(collapse = "; ") if(length(review_status) != 1) review_indeterminate(TRUE) } @@ -233,7 +233,7 @@ mod_review_forms_server <- function( shinyjs::enable("save_review") shinyjs::enable("add_comment") shinyjs::enable("review_comment") - } else{ + } else { shinyjs::disable("save_review") shinyjs::disable("add_comment") shinyjs::disable("review_comment") diff --git a/tests/testthat/test-mod_review_forms.R b/tests/testthat/test-mod_review_forms.R index 4ef10412..198d1a4e 100644 --- a/tests/testthat/test-mod_review_forms.R +++ b/tests/testthat/test-mod_review_forms.R @@ -79,6 +79,9 @@ describe( mod_review_forms_server, args = testargs, { ns <- session$ns + session$userData$review_records <- reactiveValues() + session$userData$update_checkboxes <- reactiveValues() + ## patient has two rows: AF and Cystitis. AF is already reviewed by someone else: expect_equal( data.frame( @@ -94,6 +97,7 @@ describe( }) ) + session$setInputs(form_reviewed = FALSE) # Needs to be initialized to work session$setInputs(form_reviewed = TRUE, save_review = 1) db_reviewdata <- db_get_table(db_path) db_reviewlogdata <- db_get_table(db_path, "all_review_data_log") @@ -183,6 +187,9 @@ describe( ) } test_server <- function(input, output, session){ + session$userData$review_records <- reactiveValues() + session$userData$update_checkboxes <- reactiveValues() + mod_review_forms_server( id = "test", r = reactiveValues( From a7fda2180d9f1633180bf815882326ba40db05e0 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:03:49 -0500 Subject: [PATCH 22/49] Properly handle partially reviewed rows --- R/mod_common_forms.R | 2 ++ R/mod_study_forms.R | 1 + R/shiny.R | 8 ++++---- inst/app/www/custom.js | 9 +++++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index ffaf57be..6fd8128b 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -161,6 +161,7 @@ mod_common_forms_server <- function( input$common_form_table_review_selection, by = "id" ) |> + dplyr::filter(!is.na(reviewed)) |> dplyr::anti_join( subset(r$review_data, item_group == form), by = c("id", "reviewed") @@ -182,6 +183,7 @@ mod_common_forms_server <- function( input$SAE_table_review_selection, by = "id" ) |> + dplyr::filter(!is.na(reviewed)) |> dplyr::anti_join( subset(r$review_data, item_group == form), by = c("id", "reviewed") diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index a3a9830d..f45d81d7 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -205,6 +205,7 @@ mod_study_forms_server <- function( input$table_review_selection, by = "id" ) |> + dplyr::filter(!is.na(reviewed)) |> dplyr::anti_join( subset(r$review_data, item_group == form), by = c("id", "reviewed") diff --git a/R/shiny.R b/R/shiny.R index 90484d36..22b673c8 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -1,7 +1,7 @@ shiny::registerInputHandler('CS.reviewInfo', function(val, ...) { with(val, data.frame( id = unlist(ids), - reviewed = ifelse(review, "Yes", "No") + reviewed = ifelse(isTRUE(review), "Yes", ifelse(isFALSE(review), "No", NA_character_)) )) }, TRUE) @@ -11,7 +11,7 @@ checkbox_callback <- DT::JS( "var cell = table.cell($(this).closest('td'));", "var rowIdx = table.row($(this).closest('tr')).index();", "var ids = cell.data().ids;", - "var review = $(this).is(':checked');", + "var review = $(this).is(':indeterminate') ? null : $(this).is(':checked');", "var info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};", "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", "})" @@ -26,9 +26,9 @@ checkbox_render <- DT::JS( checkbox_create_callback <- DT::JS( "function(row, data, dataIndex) {", - "if (data[0] == null) {", + "if (data[0].reviewed == null) {", "let cb = row.cells[0].getElementsByTagName('input')[0]", - "cb.indeterminate = cb.readOnly = true;", + "cb.indeterminate = true;", "}", "}" ) diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js index c810c0bc..bedc0976 100644 --- a/inst/app/www/custom.js +++ b/inst/app/www/custom.js @@ -1,6 +1,11 @@ function ts(cb) { - if (cb.readOnly) cb.checked=cb.readOnly=false; - else if (!cb.checked) cb.readOnly=cb.indeterminate=true; + if (cb.readOnly) { + cb.indeterminate=true; + cb.readOnly=cb.checked=false; + } else if (!cb.checked) { + cb.readOnly=true; + cb.indeterminate=false; + } } var customCheckbox = new Shiny.InputBinding(); From 310eff22cbccac5c92d437d77610a1adeb653d1c Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:13:22 -0500 Subject: [PATCH 23/49] Repair interactivity between overall checkbox and tables --- R/mod_common_forms.R | 9 +++++++-- R/mod_review_forms.R | 2 +- R/mod_study_forms.R | 5 ++++- R/shiny.R | 9 +++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 6fd8128b..83af3dc7 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -151,10 +151,13 @@ mod_common_forms_server <- function( }) observeEvent(data_active(), { + session$userData$update_checkboxes[[form]] <- NULL session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character()) }) observeEvent(input$common_form_table_review_selection, { + session$userData$update_checkboxes[[form]] <- NULL + session$userData$review_records[[form]] <- dplyr::rows_upsert( session$userData$review_records[[form]], @@ -172,11 +175,13 @@ mod_common_forms_server <- function( observeEvent(session$userData$update_checkboxes[[form]], { checked <- session$userData$update_checkboxes[[form]] - shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("common_form_table"), tolower(checked))) - shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("SAE_table"), tolower(checked))) + update_cbs(ns("common_form_table"), checked) + update_cbs(ns("SAE_table"), checked) }) observeEvent(input$SAE_table_review_selection, { + session$userData$update_checkboxes[[form]] <- NULL + session$userData$review_records[[form]] <- dplyr::rows_upsert( session$userData$review_records[[form]], diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index fa3206bb..801e937b 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -142,7 +142,7 @@ mod_review_forms_server <- function( observeEvent(input$form_reviewed, { session$userData$update_checkboxes[[active_form()]] <- input$form_reviewed - + session$userData$review_records[[active_form()]] <- review_data_active() |> dplyr::mutate(reviewed = ifelse(input$form_reviewed, "Yes", "No")) |> diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index f45d81d7..96313d30 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -195,10 +195,13 @@ mod_study_forms_server <- function( }) observeEvent(table_data_active(), { + session$userData$update_checkboxes[[form]] <- NULL session$userData$review_records[[form]] <- data.frame(id = integer(), reviewed = character(), row_index = character()) }) observeEvent(input$table_review_selection, { + session$userData$update_checkboxes[[form]] <- NULL + session$userData$review_records[[form]] <- dplyr::rows_upsert( session$userData$review_records[[form]], @@ -216,7 +219,7 @@ mod_study_forms_server <- function( observeEvent(session$userData$update_checkboxes[[form]], { checked <- session$userData$update_checkboxes[[form]] - shinyjs::runjs(sprintf("$(':checkbox', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)", ns("table"), tolower(checked))) + update_cbs(ns("table"), checked) }) ############################### Outputs: ################################### diff --git a/R/shiny.R b/R/shiny.R index 22b673c8..ad75318b 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -32,3 +32,12 @@ checkbox_create_callback <- DT::JS( "}", "}" ) + +update_cbs <- function(tblId, checked) { + "$(':checkbox:not(.indeterminate)', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s)" |> + sprintf(tblId, tolower(checked)) |> + shinyjs::runjs() + "$(':checkbox.indeterminate', $('#%s .table').DataTable().rows().nodes()).prop('checked', %s).prop('indeterminate', false).prop('readOnly', %s)" |> + sprintf(tblId, tolower(checked), tolower(!checked)) |> + shinyjs::runjs() +} From 5a78643a337e0172492e7cb08256b31e7da19a4b Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:28:01 -0500 Subject: [PATCH 24/49] Clean up table name --- R/mod_common_forms.R | 4 ++-- R/mod_study_forms.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 83af3dc7..e41428f2 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -135,7 +135,7 @@ mod_common_forms_server <- function( if(!input$show_all_data) SAE_data$subject_id <- NULL datatable_custom( SAE_data, - rename_vars = table_names, + rename_vars = c("Review Status" = "o_reviewed", table_names), rownames= FALSE, title = "Serious Adverse Events", escape = FALSE, @@ -207,7 +207,7 @@ mod_common_forms_server <- function( if(!input$show_all_data) df$subject_id <- NULL datatable_custom( df, - rename_vars = table_names, + rename_vars = c("Review Status" = "o_reviewed", table_names), rownames= FALSE, title = form, escape = FALSE, diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 96313d30..e1a4133f 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -254,7 +254,7 @@ mod_study_forms_server <- function( req(table_data_active()) datatable_custom( table_data_active(), - table_names, + rename_vars = c("Review Status" = "o_reviewed", table_names), rownames= FALSE, escape = FALSE, selection = "none", From 365206d7f84894471eead58a3f8ce8e45f8ac64d Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:34:47 -0500 Subject: [PATCH 25/49] Update `app_feature_01` JSONs --- .../app_feature_01/app-feature-1-002.json | 16 ++++++------- .../app_feature_01/app-feature-1-003.json | 16 ++++++------- .../app_feature_01/app-feature-1-004.json | 24 +++++++++---------- .../app_feature_01/app-feature-1-005.json | 24 +++++++++---------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json index e02389e1..8afc3e9c 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -28,7 +28,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -84,7 +84,7 @@ "targets": 13 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -99,7 +99,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -255,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -274,7 +274,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -318,7 +318,7 @@ "targets": 10 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -333,7 +333,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json index 12f5431a..9824f6b7 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -28,7 +28,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -84,7 +84,7 @@ "targets": 13 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -99,7 +99,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -255,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -274,7 +274,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -318,7 +318,7 @@ "targets": 10 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -333,7 +333,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json index a0447bc5..8e278c98 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -28,7 +28,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -84,7 +84,7 @@ "targets": 13 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -99,7 +99,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -255,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -274,7 +274,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -318,7 +318,7 @@ "targets": 10 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -333,7 +333,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -8296,7 +8296,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -8311,7 +8311,7 @@ "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -8351,7 +8351,7 @@ "targets": 9 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -8366,7 +8366,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json index df20d098..2468a1f6 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json @@ -9,7 +9,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -28,7 +28,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -84,7 +84,7 @@ "targets": 13 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -99,7 +99,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -255,7 +255,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -274,7 +274,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -318,7 +318,7 @@ "targets": 10 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -333,7 +333,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -8297,7 +8297,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -8312,7 +8312,7 @@ "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -8352,7 +8352,7 @@ "targets": 9 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -8367,7 +8367,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, From d10e475da272ea21f9940a77115787e1c4b41348 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:48:36 -0500 Subject: [PATCH 26/49] Fix issue with setting input for checkbox --- inst/app/www/custom.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js index bedc0976..2f26fac2 100644 --- a/inst/app/www/custom.js +++ b/inst/app/www/custom.js @@ -17,6 +17,9 @@ $.extend(customCheckbox, { getValue: function(el) { return el.checked; }, + setValue: function(el, value) { + el.checked = value; + }, subscribe: function(el, callback) { $(el).on("change.checkboxInputBinding", function() { Shiny.onInputChange($(this).attr('id'), this.checked, {priority: 'event'}); From 19826507c6e6f81f1e3317e3a3ef5bfff068d310 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:51:17 -0500 Subject: [PATCH 27/49] Update `app_feature_03` JSONs --- .../_snaps/app_feature_03/app-feature-3-002.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json index 7a2a525a..2ecd7042 100644 --- a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json +++ b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json @@ -483,7 +483,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -502,7 +502,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -558,7 +558,7 @@ "targets": 13 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Serious Adverse Events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -573,7 +573,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -729,7 +729,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
o_reviewed<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -748,7 +748,7 @@ "targets": 1 }, { - "name": "o_reviewed", + "name": "Review Status", "targets": 0 }, { @@ -792,7 +792,7 @@ "targets": 10 } ], - "createdRow": "function(row, data, dataIndex) {\nif (data[0] == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = cb.readOnly = true;\n}\n}", + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"Adverse events\")\n}", "dom": "f<\"header h5\">ti", "order": [ @@ -807,7 +807,7 @@ "serverSide": true, "processing": true }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, From 5d454316866a8fb8db348ff424030a2457c047ec Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:30:13 -0500 Subject: [PATCH 28/49] Reset review reactiveValues after save --- R/mod_review_forms.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index 801e937b..dce5a4a2 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -294,6 +294,9 @@ mod_review_forms_server <- function( names(review_records_db) ] + session$userData$update_checkboxes[[active_form()]] <- NULL + session$userData$review_records[[active_form()]] <- data.frame(id = integer(), reviewed = character()) + review_save_error(any( !isTRUE(all.equal(review_records_db, review_records, check.attributes = FALSE)), !isTRUE(all.equal(updated_records_memory, review_records_db, check.attributes = FALSE)) From 96e795efd8e3a8936505fe31a5e2c633eed56937 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:48:15 -0500 Subject: [PATCH 29/49] Repair study form test --- .../mod_study_forms/study_forms-001.json | 59 ++++++++++++++++--- .../mod_study_forms/study_forms-002.json | 59 ++++++++++++++++--- tests/testthat/test-mod_study_forms.R | 4 +- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json index c05b3cb7..65e613dd 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json @@ -1243,7 +1243,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -1252,15 +1252,13 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ { - "orderable": false, - "targets": 0 + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": " ", + "name": "Review Status", "targets": 0 }, { @@ -1300,6 +1298,9 @@ "targets": 9 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -1312,16 +1313,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -3490,6 +3495,44 @@ ] }, "test-table_data": { + "o_reviewed": [ + { + "reviewed": null, + "ids": [ + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 440 + ] + }, + { + "reviewed": null, + "ids": [ + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 441 + ] + }, + { + "reviewed": false, + "ids": [ + 92, + 93, + 94, + 95, + 96 + ] + } + ], "event_name": [ "Screening", "Visit 1", diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json index c05b3cb7..65e613dd 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json @@ -1243,7 +1243,7 @@ "Scroller", "ColReorder" ], - "container": "\n \n \n
<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "container": "\n \n \n
Review Status<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, "scrollX": true, @@ -1252,15 +1252,13 @@ "scrollResize": true, "scrollCollapse": true, "colReorder": true, - "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", - "dom": "f<\"header h5\">ti", "columnDefs": [ { - "orderable": false, - "targets": 0 + "targets": 0, + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { - "name": " ", + "name": "Review Status", "targets": 0 }, { @@ -1300,6 +1298,9 @@ "targets": 9 } ], + "createdRow": "function(row, data, dataIndex) {\nif (data[0].reviewed == null) {\nlet cb = row.cells[0].getElementsByTagName('input')[0]\ncb.indeterminate = true;\n}\n}", + "initComplete": "function() {\n$(this.api().table().container()).find('.header').html(\"\")\n}", + "dom": "f<\"header h5\">ti", "order": [ ], @@ -1312,16 +1313,20 @@ "serverSide": true, "processing": true }, + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { - "mode": "single", + "mode": "none", "selected": null, "target": "row", "selectable": null } }, "evals": [ + "options.columnDefs.0.render", + "options.createdRow", "options.initComplete", - "options.ajax.data" + "options.ajax.data", + "callback" ], "jsHooks": [ @@ -3490,6 +3495,44 @@ ] }, "test-table_data": { + "o_reviewed": [ + { + "reviewed": null, + "ids": [ + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 440 + ] + }, + { + "reviewed": null, + "ids": [ + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 441 + ] + }, + { + "reviewed": false, + "ids": [ + 92, + 93, + 94, + 95, + 96 + ] + } + ], "event_name": [ "Screening", "Visit 1", diff --git a/tests/testthat/test-mod_study_forms.R b/tests/testthat/test-mod_study_forms.R index c4b868f0..b2a715d7 100644 --- a/tests/testthat/test-mod_study_forms.R +++ b/tests/testthat/test-mod_study_forms.R @@ -45,6 +45,7 @@ describe( appdata <- get_appdata(clinsightful_data) rev_data <- get_review_data(appdata[["Vital signs"]]) |> dplyr::mutate( + id = dplyr::row_number(), reviewed = sample(c("Yes", "No"), dplyr::n(), replace = TRUE), status = sample(c("new", "old", "updated"), dplyr::n(), replace = TRUE) ) @@ -98,7 +99,7 @@ describe( # only difference between the the data frame is some html tags around # some not yet reviewed data. However, because of these tags, we cannot # compare expected with actual directly. - expect_equal(names(table_data_active()), names(df_expected) ) + expect_equal(names(table_data_active()), c("o_reviewed", names(df_expected)) ) expect_equal(table_data_active()$event_name, df_expected$event_name ) expect_true(is.data.frame(table_data_active())) @@ -142,6 +143,7 @@ describe( appdata <- get_appdata(clinsightful_data) rev_data <- get_review_data(appdata[["Vital signs"]]) |> dplyr::mutate( + id = dplyr::row_number(), reviewed = sample(c("Yes", "No"), dplyr::n(), replace = TRUE), status = sample(c("new", "old", "updated"), dplyr::n(), replace = TRUE) ) From f4a71ade0560a66120bde478f00d3ca80ebeb30e Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:55:39 -0500 Subject: [PATCH 30/49] Update test-mod_review_forms.R --- tests/testthat/test-mod_review_forms.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-mod_review_forms.R b/tests/testthat/test-mod_review_forms.R index 198d1a4e..e8c797ad 100644 --- a/tests/testthat/test-mod_review_forms.R +++ b/tests/testthat/test-mod_review_forms.R @@ -496,10 +496,15 @@ describe( testServer( mod_review_forms_server, args = testargs, { ns <- session$ns + + session$userData$review_records <- reactiveValues() + session$userData$update_checkboxes <- reactiveValues() + + session$setInputs(form_reviewed = NULL) db_before_saving <- db_get_table(db_path) session$setInputs(form_reviewed = TRUE, save_review = 1) db_after_saving <- db_get_table(db_path) - + expect_true(review_save_error()) expect_equal(r$review_data, rev_data) expect_equal(db_after_saving, db_before_saving) From 54f7f553870a69b3d9de8e0370d17d7fb0ba09ce Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Wed, 4 Dec 2024 09:15:58 -0500 Subject: [PATCH 31/49] Add rudimentary progress bar --- R/mod_review_forms.R | 16 ++++++++++++++++ R/shiny.R | 18 ++++++++++++++++++ inst/app/www/custom.css | 26 ++++++++++++++++++++++++++ inst/app/www/custom.js | 18 ++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index dce5a4a2..8e61766d 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -45,6 +45,7 @@ mod_review_forms_ui <- function(id){ label = NULL ) ), + progress_bar(ns("progress_bar")), bslib::layout_columns( col_widths = c(11, 12), shiny::actionButton( @@ -319,6 +320,21 @@ mod_review_forms_server <- function( showNotification("Input saved successfully", duration = 1, type = "message") }) + output[["progress_bar"]] <- render_progress_bar({ + req( + review_data_active(), + active_form(), + session$userData$review_records[[active_form()]] + ) + + list( + completed = sum(review_data_active()$reviewed == "Yes"), + unmarking = sum(session$userData$review_records[[active_form()]]$reviewed == "No"), + marking = sum(session$userData$review_records[[active_form()]]$reviewed == "Yes"), + total = nrow(review_data_active()) + ) + }) + output[["review_header"]] <- renderText({active_form()}) output[["save_review_error"]] <- renderPrint({ diff --git a/R/shiny.R b/R/shiny.R index ad75318b..b6dac821 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -41,3 +41,21 @@ update_cbs <- function(tblId, checked) { sprintf(tblId, tolower(checked), tolower(!checked)) |> shinyjs::runjs() } + +progress_bar <- function(outputId) { + div( + id = outputId, + class = "cs-progress-bar", + div(class = c("cs-progress", "completed")), + div(class = c("cs-progress", "unmarking")), + div(class = c("cs-progress", "marking")) + ) +} + +render_progress_bar <- function(expr, env = parent.frame(), quoted = FALSE) { + func <- exprToFunction(expr, env, quoted) + + function(){ + func() + } +} diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index d1125951..65b5ee8a 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -75,3 +75,29 @@ tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate))>td { background-color: aquamarine; border-color: aquamarine; } + +div.cs-progress-bar { + width: 100%; + background-color: #b3b3b3; + color: #ffffff; + border-radius: 10px; + height: 10px; + overflow: hidden; + display: flex; +} + +div.cs-progress-bar>div.cs-progress { + height: 100%; +} + +div.cs-progress-bar>div.cs-progress.completed { + background-color: green; +} + +div.cs-progress-bar>div.cs-progress.unmarking { + background-color: red; +} + +div.cs-progress-bar>div.cs-progress.marking { + background-color: blue; +} diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js index 2f26fac2..d51187d6 100644 --- a/inst/app/www/custom.js +++ b/inst/app/www/custom.js @@ -31,3 +31,21 @@ $.extend(customCheckbox, { }); Shiny.inputBindings.register(customCheckbox); + +var customProgressBar = new Shiny.OutputBinding(); + +$.extend(customProgressBar, { + find: function(scope) { + return $(scope).find("div.cs-progress-bar"); + }, + renderValue: function(el, data) { + let cmp_pct = (data.completed-data.unmarking)/data.total*100; + let um_pct = data.unmarking/data.total*100; + let m_pct = data.marking/data.total*100; + $('#' + el.id + " .cs-progress.completed").width(cmp_pct.toFixed(2) + "%") + $('#' + el.id + " .cs-progress.unmarking").width(um_pct.toFixed(2) + "%") + $('#' + el.id + " .cs-progress.marking").width(m_pct.toFixed(2) + "%") + } +}); + +Shiny.outputBindings.register(customProgressBar) From 2473133bbc9dae01080f1cb528601c929b11d866 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:51:44 -0500 Subject: [PATCH 32/49] Add transition to progress bar --- inst/app/www/custom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index 65b5ee8a..086ba87b 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -88,6 +88,7 @@ div.cs-progress-bar { div.cs-progress-bar>div.cs-progress { height: 100%; + transition: width 1s; } div.cs-progress-bar>div.cs-progress.completed { From 3123136739dcad39b8c13177bc0f31ac58105329 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 07:29:02 -0500 Subject: [PATCH 33/49] Wrap Shiny bindings --- inst/app/www/custom.js | 86 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js index d51187d6..b5f56bed 100644 --- a/inst/app/www/custom.js +++ b/inst/app/www/custom.js @@ -8,44 +8,52 @@ function ts(cb) { } } -var customCheckbox = new Shiny.InputBinding(); +$(document).ready(function() { + + /* Define custom Shiny input binding for overall review checkbox. + This is needed to assign an event priority to the checkbox.*/ + var customCheckbox = new Shiny.InputBinding(); + + $.extend(customCheckbox, { + find: function(scope) { + return $(scope).find("input[type='checkbox'].cs_checkbox"); + }, + getValue: function(el) { + return el.checked; + }, + setValue: function(el, value) { + el.checked = value; + }, + subscribe: function(el, callback) { + $(el).on("change.checkboxInputBinding", function() { + Shiny.onInputChange($(this).attr('id'), this.checked, {priority: 'event'}); + }); + }, + unsubscribe: function(el) { + $(el).off(".checkboxInputBinding"); + } + }); + + Shiny.inputBindings.register(customCheckbox); + + /* Define custom Shiny output binding for review progress bar. + It expects 4 values: completed, unmarking, marking, and total.*/ + var customProgressBar = new Shiny.OutputBinding(); + + $.extend(customProgressBar, { + find: function(scope) { + return $(scope).find("div.cs-progress-bar"); + }, + renderValue: function(el, data) { + let cmp_pct = (data.completed-data.unmarking)/data.total*100; + let um_pct = data.unmarking/data.total*100; + let m_pct = data.marking/data.total*100; + $('#' + el.id + " .cs-progress.completed").width(cmp_pct.toFixed(2) + "%") + $('#' + el.id + " .cs-progress.unmarking").width(um_pct.toFixed(2) + "%") + $('#' + el.id + " .cs-progress.marking").width(m_pct.toFixed(2) + "%") + } + }); + + Shiny.outputBindings.register(customProgressBar) -$.extend(customCheckbox, { - find: function(scope) { - return $(scope).find("input[type='checkbox'].cs_checkbox"); - }, - getValue: function(el) { - return el.checked; - }, - setValue: function(el, value) { - el.checked = value; - }, - subscribe: function(el, callback) { - $(el).on("change.checkboxInputBinding", function() { - Shiny.onInputChange($(this).attr('id'), this.checked, {priority: 'event'}); - }); - }, - unsubscribe: function(el) { - $(el).off(".checkboxInputBinding"); - } }); - -Shiny.inputBindings.register(customCheckbox); - -var customProgressBar = new Shiny.OutputBinding(); - -$.extend(customProgressBar, { - find: function(scope) { - return $(scope).find("div.cs-progress-bar"); - }, - renderValue: function(el, data) { - let cmp_pct = (data.completed-data.unmarking)/data.total*100; - let um_pct = data.unmarking/data.total*100; - let m_pct = data.marking/data.total*100; - $('#' + el.id + " .cs-progress.completed").width(cmp_pct.toFixed(2) + "%") - $('#' + el.id + " .cs-progress.unmarking").width(um_pct.toFixed(2) + "%") - $('#' + el.id + " .cs-progress.marking").width(m_pct.toFixed(2) + "%") - } -}); - -Shiny.outputBindings.register(customProgressBar) From b9877083fc9716790e5067faa60de34f25ab9411 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 07:56:52 -0500 Subject: [PATCH 34/49] Clean up readability of checkbox render function --- R/shiny.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/shiny.R b/R/shiny.R index b6dac821..28cd074f 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -20,7 +20,10 @@ checkbox_callback <- DT::JS( checkbox_render <- DT::JS( "function(data, type, row, meta) {", "var reviewed = data.reviewed;", - "return ``;", + "return ``;", "}" ) From f637dd061b7e5b1d4a9d7dd854e0a77e9efd545a Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:01:27 -0500 Subject: [PATCH 35/49] Update `app-feature-01` JSONs --- .../_snaps/app_feature_01/app-feature-1-002.json | 10 ++++++++-- .../_snaps/app_feature_01/app-feature-1-003.json | 10 ++++++++-- .../_snaps/app_feature_01/app-feature-1-004.json | 12 +++++++++--- .../_snaps/app_feature_01/app-feature-1-005.json | 12 +++++++++--- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json index 8afc3e9c..f0813be6 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json @@ -21,7 +21,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -267,7 +267,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -799,6 +799,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Adverse events<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 45 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json index 9824f6b7..cdbe742d 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json @@ -21,7 +21,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -267,7 +267,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -799,6 +799,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Vital signs<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 47 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json index 8e278c98..a11077a3 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json @@ -21,7 +21,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -267,7 +267,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -799,6 +799,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Vital signs<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 47 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", @@ -8308,7 +8314,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "name": "Review Status", diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json index 2468a1f6..3da1e3eb 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json @@ -21,7 +21,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -267,7 +267,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -799,6 +799,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Vital signs<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 15 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", @@ -8309,7 +8315,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "name": "Review Status", From 7144bd8b3482e8d5e6ad8563a077836e8f86dc97 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:03:01 -0500 Subject: [PATCH 36/49] Update `app-feature-02` JSON --- tests/testthat/_snaps/app_feature_02/app-feature-2-001.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testthat/_snaps/app_feature_02/app-feature-2-001.json b/tests/testthat/_snaps/app_feature_02/app-feature-2-001.json index b0c72096..b7c12cbd 100644 --- a/tests/testthat/_snaps/app_feature_02/app-feature-2-001.json +++ b/tests/testthat/_snaps/app_feature_02/app-feature-2-001.json @@ -83,6 +83,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Vital signs<\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 8, + "unmarking": 0, + "marking": 0, + "total": 8 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Form already reviewed", "call": "NULL", From e6fe7eeffdf71bdb11e1a0de3b79d786744ad2cd Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:04:21 -0500 Subject: [PATCH 37/49] Update `app-feature-03` JSONs --- .../_snaps/app_feature_03/app-feature-3-001.json | 6 ++++++ .../_snaps/app_feature_03/app-feature-3-002.json | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_03/app-feature-3-001.json b/tests/testthat/_snaps/app_feature_03/app-feature-3-001.json index b0f0134a..335abaa1 100644 --- a/tests/testthat/_snaps/app_feature_03/app-feature-3-001.json +++ b/tests/testthat/_snaps/app_feature_03/app-feature-3-001.json @@ -188,6 +188,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Vital signs<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 8 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", diff --git a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json index 2ecd7042..312fa8f8 100644 --- a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json +++ b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json @@ -495,7 +495,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -741,7 +741,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "className": "dt-right", @@ -1273,6 +1273,12 @@ ] }, "main_sidebar_1-navigate_forms_1-form_name": "
Adverse events<\/b><\/center>", + "main_sidebar_1-review_forms_1-progress_bar": { + "completed": 0, + "unmarking": 0, + "marking": 0, + "total": 45 + }, "main_sidebar_1-review_forms_1-save_review_error": { "message": "Requires review", "call": "NULL", From d6a2ff9d599ecc2ce3cf71f05c508e47561dd23b Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:14:20 -0500 Subject: [PATCH 38/49] Add bottom margin to progress bar --- inst/app/www/custom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index 086ba87b..c132f215 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -84,6 +84,7 @@ div.cs-progress-bar { height: 10px; overflow: hidden; display: flex; + margin-bottom: 1rem; } div.cs-progress-bar>div.cs-progress { From f0a19e7a8f7cd5f722edac7a06ff9ecc843220e2 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:15:44 -0500 Subject: [PATCH 39/49] Update `mod_study_forms` JSONs --- tests/testthat/_snaps/mod_study_forms/study_forms-001.json | 2 +- tests/testthat/_snaps/mod_study_forms/study_forms-002.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json index 65e613dd..3abdfbb7 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json @@ -1255,7 +1255,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "name": "Review Status", diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json index 65e613dd..3abdfbb7 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json @@ -1255,7 +1255,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" }, { "name": "Review Status", From bfc864f8684647b50aecfd0b1086d23bd6141428 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:40:54 -0500 Subject: [PATCH 40/49] Spruce up progress bar output object --- R/shiny.R | 14 ++++++++++---- inst/app/www/custom.css | 22 ++++++++++++++++------ inst/app/www/custom.js | 4 +++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/R/shiny.R b/R/shiny.R index 28cd074f..487b1501 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -48,10 +48,16 @@ update_cbs <- function(tblId, checked) { progress_bar <- function(outputId) { div( id = outputId, - class = "cs-progress-bar", - div(class = c("cs-progress", "completed")), - div(class = c("cs-progress", "unmarking")), - div(class = c("cs-progress", "marking")) + class = "cs-progress-container", + div( + class = "cs-progress-bar", + div(class = c("cs-progress", "completed")), + div(class = c("cs-progress", "unmarking")), + div(class = c("cs-progress", "marking")) + ), + div( + class = "cs-completed" + ) ) } diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index c132f215..0ccc5a83 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -76,7 +76,14 @@ tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate))>td { border-color: aquamarine; } -div.cs-progress-bar { +div.cs-progress-container { + display: flex; + margin-bottom: 1rem; + align-items: center; + gap: 5px; +} + +div.cs-progress-container>.cs-progress-bar { width: 100%; background-color: #b3b3b3; color: #ffffff; @@ -84,22 +91,25 @@ div.cs-progress-bar { height: 10px; overflow: hidden; display: flex; - margin-bottom: 1rem; } -div.cs-progress-bar>div.cs-progress { +div.cs-progress-container>.cs-completed { + cursor: default; +} + +div.cs-progress-container>.cs-progress-bar>.cs-progress { height: 100%; transition: width 1s; } -div.cs-progress-bar>div.cs-progress.completed { +div.cs-progress-container>.cs-progress-bar>.cs-progress.completed { background-color: green; } -div.cs-progress-bar>div.cs-progress.unmarking { +div.cs-progress-container>.cs-progress-bar>.cs-progress.unmarking { background-color: red; } -div.cs-progress-bar>div.cs-progress.marking { +div.cs-progress-container>.cs-progress-bar>.cs-progress.marking { background-color: blue; } diff --git a/inst/app/www/custom.js b/inst/app/www/custom.js index b5f56bed..c2a61bed 100644 --- a/inst/app/www/custom.js +++ b/inst/app/www/custom.js @@ -42,15 +42,17 @@ $(document).ready(function() { $.extend(customProgressBar, { find: function(scope) { - return $(scope).find("div.cs-progress-bar"); + return $(scope).find("div.cs-progress-container"); }, renderValue: function(el, data) { let cmp_pct = (data.completed-data.unmarking)/data.total*100; let um_pct = data.unmarking/data.total*100; let m_pct = data.marking/data.total*100; + let true_cmp_pct = data.completed/data.total*100; $('#' + el.id + " .cs-progress.completed").width(cmp_pct.toFixed(2) + "%") $('#' + el.id + " .cs-progress.unmarking").width(um_pct.toFixed(2) + "%") $('#' + el.id + " .cs-progress.marking").width(m_pct.toFixed(2) + "%") + $('#' + el.id + " .cs-completed").html(true_cmp_pct.toFixed(1) + "%") } }); From e9ab76d4353a6c5f0b00a050002432d3d5bcfab4 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:21:07 -0500 Subject: [PATCH 41/49] Update custom.css --- inst/app/www/custom.css | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/inst/app/www/custom.css b/inst/app/www/custom.css index 0ccc5a83..3ee6d67c 100644 --- a/inst/app/www/custom.css +++ b/inst/app/www/custom.css @@ -1,3 +1,8 @@ +:root { + --cs-completed: #91C483; + --cs-unmarking: #FF6464; + --cs-marking: #97b0f8; +} .bslib-value-box .value-box-area { padding: 0.1rem 0rem 0.1rem 1rem; @@ -61,19 +66,18 @@ div.datatables div.header { font-weight: bold; } -tr:has(td input[type="checkbox"].checked:not(:checked))>td { - background-color: aquamarine; - border-color: aquamarine; -} - -tr:has(td input[type="checkbox"].unchecked:checked)>td { - background-color: aquamarine; - border-color: aquamarine; +tr:has(td input[type="checkbox"].checked:not(:checked))>td, + tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate):not(:checked))>td { + background-color: var(--cs-unmarking, #FF6464); + border-color: var(--cs-unmarking, #FF6464); + color: #000000; } -tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate))>td { - background-color: aquamarine; - border-color: aquamarine; +tr:has(td input[type="checkbox"].unchecked:checked)>td, + tr:has(td input[type="checkbox"].indeterminate:not(:indeterminate):checked)>td { + background-color: var(--cs-marking, #97b0f8); + border-color: var(--cs-marking, #97b0f8); + color: #000000; } div.cs-progress-container { @@ -85,7 +89,10 @@ div.cs-progress-container { div.cs-progress-container>.cs-progress-bar { width: 100%; - background-color: #b3b3b3; + background-color: #eeeeee; + border-color: #b3b3b3; + border-style: solid; + border-width: thin; color: #ffffff; border-radius: 10px; height: 10px; @@ -103,13 +110,13 @@ div.cs-progress-container>.cs-progress-bar>.cs-progress { } div.cs-progress-container>.cs-progress-bar>.cs-progress.completed { - background-color: green; + background-color: var(--cs-completed, #91C483); } div.cs-progress-container>.cs-progress-bar>.cs-progress.unmarking { - background-color: red; + background-color: var(--cs-unmarking, #FF6464); } div.cs-progress-container>.cs-progress-bar>.cs-progress.marking { - background-color: blue; + background-color: var(--cs-marking, #97b0f8); } From c6ef036a9479ca93a12ab413299e6ae229714c27 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:31:38 -0500 Subject: [PATCH 42/49] Fix "form already reviewed" indicator --- R/mod_review_forms.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index 8e61766d..b9c5c147 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -355,7 +355,7 @@ mod_review_forms_server <- function( "No user name found. Cannot save review" )) validate(need( - !unique(with(review_data_active(), reviewed[edit_date_time == max(as.POSIXct(edit_date_time))])) == "Yes", + any(review_data_active()[["reviewed"]] != "Yes"), "Form already reviewed" )) validate(need(input$form_reviewed, "Requires review")) From a36d7cface12d8bb99a8a8a1bcc9c5001ceb6fb5 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:58:30 -0500 Subject: [PATCH 43/49] Update version --- DESCRIPTION | 2 +- inst/golem-config.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 744bcd2e..6e7b8ac4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: clinsight Title: ClinSight -Version: 0.1.1.9011 +Version: 0.1.1.9012 Authors@R: c( person("Leonard Daniël", "Samson", , "lsamson@gcp-service.com", role = c("cre", "aut"), comment = c(ORCID = "0000-0002-6252-7639")), diff --git a/inst/golem-config.yml b/inst/golem-config.yml index 3d15e651..19beab51 100644 --- a/inst/golem-config.yml +++ b/inst/golem-config.yml @@ -1,6 +1,6 @@ default: golem_name: clinsight - golem_version: 0.1.1.9011 + golem_version: 0.1.1.9012 app_prod: no user_identification: test_user study_data: !expr clinsight::clinsightful_data From a746b2ee3515a29b658cb80c3a6ba04127962b52 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:02:55 -0500 Subject: [PATCH 44/49] Only review selected subject --- R/mod_common_forms.R | 12 ++++++++++-- R/mod_review_forms.R | 1 + R/mod_study_forms.R | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index e41428f2..9ca04e0e 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -165,8 +165,12 @@ mod_common_forms_server <- function( by = "id" ) |> dplyr::filter(!is.na(reviewed)) |> + dplyr::semi_join( + subset(r$review_data, subject_id == r$subject_id & item_group == form), + by = "id" + ) |> dplyr::anti_join( - subset(r$review_data, item_group == form), + subset(r$review_data, subject_id == r$subject_id & item_group == form), by = c("id", "reviewed") ) |> dplyr::arrange(id) @@ -189,8 +193,12 @@ mod_common_forms_server <- function( by = "id" ) |> dplyr::filter(!is.na(reviewed)) |> + dplyr::semi_join( + subset(r$review_data, subject_id == r$subject_id & item_group == form), + by = "id" + ) |> dplyr::anti_join( - subset(r$review_data, item_group == form), + subset(r$review_data, subject_id == r$subject_id & item_group == form), by = c("id", "reviewed") ) |> dplyr::arrange(id) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index b9c5c147..2275a1e4 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -125,6 +125,7 @@ mod_review_forms_server <- function( observe({ req(session$userData$review_records[[active_form()]]) + # browser() review_status <- review_data_active()[,c("id", "reviewed")] |> dplyr::rows_update(session$userData$review_records[[active_form()]][,c("id", "reviewed")], by = "id") |> diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index e1a4133f..70105a89 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -209,8 +209,12 @@ mod_study_forms_server <- function( by = "id" ) |> dplyr::filter(!is.na(reviewed)) |> + dplyr::semi_join( + subset(r$review_data, subject_id == r$subject_id & item_group == form), + by = "id" + ) |> dplyr::anti_join( - subset(r$review_data, item_group == form), + subset(r$review_data, subject_id == r$subject_id & item_group == form), by = c("id", "reviewed") ) |> dplyr::arrange(id) From 546b4e4b57f00389bcc5c010980b84127c056d4a Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:04:06 -0500 Subject: [PATCH 45/49] Save updated status in DOM --- R/shiny.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/shiny.R b/R/shiny.R index 487b1501..4a697a9d 100644 --- a/R/shiny.R +++ b/R/shiny.R @@ -12,6 +12,7 @@ checkbox_callback <- DT::JS( "var rowIdx = table.row($(this).closest('tr')).index();", "var ids = cell.data().ids;", "var review = $(this).is(':indeterminate') ? null : $(this).is(':checked');", + "cell.data().updated = review;", "var info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};", "Shiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);", "})" @@ -20,9 +21,10 @@ checkbox_callback <- DT::JS( checkbox_render <- DT::JS( "function(data, type, row, meta) {", "var reviewed = data.reviewed;", + "var updated = data.updated;", "return ``;", "}" ) From c07540a17d763ffae8cec7b0da2195fc0d404657 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:14:12 -0500 Subject: [PATCH 46/49] Set `server=FALSE` for the moment --- R/mod_common_forms.R | 4 ++-- R/mod_study_forms.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/mod_common_forms.R b/R/mod_common_forms.R index 9ca04e0e..4a3b55d8 100644 --- a/R/mod_common_forms.R +++ b/R/mod_common_forms.R @@ -148,7 +148,7 @@ mod_common_forms_server <- function( )), createdRow = checkbox_create_callback )) - }) + }, server = FALSE) observeEvent(data_active(), { session$userData$update_checkboxes[[form]] <- NULL @@ -228,7 +228,7 @@ mod_common_forms_server <- function( )), createdRow = checkbox_create_callback )) - }) + }, server = FALSE) }) } diff --git a/R/mod_study_forms.R b/R/mod_study_forms.R index 70105a89..a552b3bc 100644 --- a/R/mod_study_forms.R +++ b/R/mod_study_forms.R @@ -270,7 +270,7 @@ mod_study_forms_server <- function( )), createdRow = checkbox_create_callback )) - }) + }, server = FALSE) if(form %in% c("Vital signs", "Vitals adjusted")){ shiny::exportTestValues( From ddc0eeeb57a0a104b9cedd6285054bf751305141 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:38:27 -0500 Subject: [PATCH 47/49] Update `app-feature-1` JSONs --- R/mod_review_forms.R | 1 - .../app_feature_01/app-feature-1-002.json | 214 +++++++++- .../app_feature_01/app-feature-1-003.json | 214 +++++++++- .../app_feature_01/app-feature-1-004.json | 394 ++++++++++++++++-- .../app_feature_01/app-feature-1-005.json | 292 +++++++++++-- 5 files changed, 1014 insertions(+), 101 deletions(-) diff --git a/R/mod_review_forms.R b/R/mod_review_forms.R index 2275a1e4..b9c5c147 100644 --- a/R/mod_review_forms.R +++ b/R/mod_review_forms.R @@ -125,7 +125,6 @@ mod_review_forms_server <- function( observe({ req(session$userData$review_records[[active_form()]]) - # browser() review_status <- review_data_active()[,c("id", "reviewed")] |> dplyr::rows_update(session$userData$review_records[[active_form()]][,c("id", "reviewed")], by = "id") |> diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json index 39fd69f7..5861e600 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-002.json @@ -9,6 +9,50 @@ "Scroller", "ColReorder" ], + "data": [ + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -21,7 +65,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -91,15 +135,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -111,7 +149,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -256,6 +293,150 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2235 + ] + }, + { + "reviewed": false, + "ids": [ + 2203, + 2204, + 2205, + 2206, + 2207, + 2208, + 2209, + 2210, + 2236 + ] + }, + { + "reviewed": false, + "ids": [ + 2211, + 2212, + 2213, + 2214, + 2215, + 2216, + 2217, + 2218, + 2237 + ] + }, + { + "reviewed": false, + "ids": [ + 2219, + 2220, + 2221, + 2222, + 2223, + 2224, + 2225, + 2226, + 2238 + ] + }, + { + "reviewed": false, + "ids": [ + 2227, + 2228, + 2229, + 2230, + 2231, + 2232, + 2233, + 2234, + 2239 + ] + } + ], + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + "Hypotension*<\/b>", + "Atrial Fibrillation*<\/b>", + "Tachycardia*<\/b>", + "Urinary Tract Infection*<\/b>", + "Atrial Fibrillation*<\/b>" + ], + [ + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>" + ], + [ + "2023-07-07*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-08-16*<\/b>" + ], + [ + null, + null, + null, + null, + null + ], + [ + "Grade 1*<\/b>", + "Grade 2*<\/b>", + "Grade 2*<\/b>", + "Grade 1*<\/b>", + "Grade 2*<\/b>" + ], + [ + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>" + ], + [ + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>" + ], + [ + "None*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>" + ], + [ + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>" + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -268,7 +449,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -333,15 +514,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -353,7 +528,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json index 653561cc..3f127320 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-003.json @@ -9,6 +9,50 @@ "Scroller", "ColReorder" ], + "data": [ + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -21,7 +65,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -91,15 +135,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -111,7 +149,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -256,6 +293,150 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2235 + ] + }, + { + "reviewed": false, + "ids": [ + 2203, + 2204, + 2205, + 2206, + 2207, + 2208, + 2209, + 2210, + 2236 + ] + }, + { + "reviewed": false, + "ids": [ + 2211, + 2212, + 2213, + 2214, + 2215, + 2216, + 2217, + 2218, + 2237 + ] + }, + { + "reviewed": false, + "ids": [ + 2219, + 2220, + 2221, + 2222, + 2223, + 2224, + 2225, + 2226, + 2238 + ] + }, + { + "reviewed": false, + "ids": [ + 2227, + 2228, + 2229, + 2230, + 2231, + 2232, + 2233, + 2234, + 2239 + ] + } + ], + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + "Hypotension*<\/b>", + "Atrial Fibrillation*<\/b>", + "Tachycardia*<\/b>", + "Urinary Tract Infection*<\/b>", + "Atrial Fibrillation*<\/b>" + ], + [ + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>" + ], + [ + "2023-07-07*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-08-16*<\/b>" + ], + [ + null, + null, + null, + null, + null + ], + [ + "Grade 1*<\/b>", + "Grade 2*<\/b>", + "Grade 2*<\/b>", + "Grade 1*<\/b>", + "Grade 2*<\/b>" + ], + [ + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>" + ], + [ + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>" + ], + [ + "None*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>" + ], + [ + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>" + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -268,7 +449,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -333,15 +514,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -353,7 +528,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json index bbbd9ca2..c6551b79 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-004.json @@ -9,6 +9,50 @@ "Scroller", "ColReorder" ], + "data": [ + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -21,7 +65,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -91,15 +135,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -111,7 +149,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -256,6 +293,150 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2235 + ] + }, + { + "reviewed": false, + "ids": [ + 2203, + 2204, + 2205, + 2206, + 2207, + 2208, + 2209, + 2210, + 2236 + ] + }, + { + "reviewed": false, + "ids": [ + 2211, + 2212, + 2213, + 2214, + 2215, + 2216, + 2217, + 2218, + 2237 + ] + }, + { + "reviewed": false, + "ids": [ + 2219, + 2220, + 2221, + 2222, + 2223, + 2224, + 2225, + 2226, + 2238 + ] + }, + { + "reviewed": false, + "ids": [ + 2227, + 2228, + 2229, + 2230, + 2231, + 2232, + 2233, + 2234, + 2239 + ] + } + ], + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + "Hypotension*<\/b>", + "Atrial Fibrillation*<\/b>", + "Tachycardia*<\/b>", + "Urinary Tract Infection*<\/b>", + "Atrial Fibrillation*<\/b>" + ], + [ + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>" + ], + [ + "2023-07-07*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-08-16*<\/b>" + ], + [ + null, + null, + null, + null, + null + ], + [ + "Grade 1*<\/b>", + "Grade 2*<\/b>", + "Grade 2*<\/b>", + "Grade 1*<\/b>", + "Grade 2*<\/b>" + ], + [ + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>" + ], + [ + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>" + ], + [ + "None*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>" + ], + [ + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>" + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -268,7 +449,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -333,15 +514,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -353,7 +528,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -8345,6 +8519,173 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 1217, + 1218, + 1219, + 1220, + 1221, + 1222, + 1223, + 1441 + ] + }, + { + "reviewed": false, + "ids": [ + 1224, + 1225, + 1226, + 1227, + 1228, + 1229, + 1230, + 1442 + ] + }, + { + "reviewed": false, + "ids": [ + 1231, + 1232, + 1233, + 1234, + 1235 + ] + }, + { + "reviewed": false, + "ids": [ + 1236, + 1237, + 1238, + 1239, + 1240, + 1241, + 1242, + 1443 + ] + }, + { + "reviewed": false, + "ids": [ + 1243, + 1244, + 1245, + 1246, + 1247 + ] + }, + { + "reviewed": false, + "ids": [ + 1248, + 1249, + 1250, + 1251, + 1252, + 1253, + 1254, + 1444 + ] + }, + { + "reviewed": false, + "ids": [ + 1255, + 1256, + 1257, + 1258, + 1259 + ] + } + ], + [ + "Screening", + "Visit 1", + "Visit 2", + "Visit 3", + "Visit 4", + "Visit 5", + "Visit 6" + ], + [ + "131*<\/b> mmHg", + "132*<\/b> mmHg", + "129*<\/b> mmHg", + "117*<\/b> mmHg", + "128*<\/b> mmHg", + "137*<\/b> mmHg", + "131*<\/b> mmHg" + ], + [ + "68*<\/b> mmHg", + "79*<\/b> mmHg", + "73*<\/b> mmHg", + "77*<\/b> mmHg", + "62*<\/b> mmHg", + "76*<\/b> mmHg", + "61*<\/b> mmHg" + ], + [ + "76*<\/b> beats/min", + "63*<\/b> beats/min", + "73*<\/b> beats/min", + "70*<\/b> beats/min", + "70*<\/b> beats/min", + "75*<\/b> beats/min", + "72*<\/b> beats/min" + ], + [ + "17*<\/b> breaths/min", + "16*<\/b> breaths/min", + "16*<\/b> breaths/min", + "18*<\/b> breaths/min", + "18*<\/b> breaths/min", + "18*<\/b> breaths/min", + "19*<\/b> breaths/min" + ], + [ + "37*<\/b> °C", + "36.7*<\/b> °C", + "36.9*<\/b> °C", + "36*<\/b> °C", + "36.6*<\/b> °C", + "36.1*<\/b> °C", + "36.9*<\/b> °C" + ], + [ + "0.01*<\/b> %", + "2*<\/b> %", + null, + "0.01*<\/b> %", + null, + "0.01*<\/b> %", + null + ], + [ + "17.44*<\/b> kg/m2", + "17.1*<\/b> kg/m2", + null, + "17.1*<\/b> kg/m2", + null, + "24.13*<\/b> kg/m2", + null + ], + [ + "61*<\/b> kg", + "62*<\/b> kg", + null, + "50*<\/b> kg", + null, + "50*<\/b> kg", + null + ] + ], "container": "\n \n \n
Review Status<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -8357,7 +8698,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "name": "Review Status", @@ -8414,15 +8755,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -8434,7 +8769,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json index 4308e08c..4ad1f051 100644 --- a/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json +++ b/tests/testthat/_snaps/app_feature_01/app-feature-1-005.json @@ -9,6 +9,50 @@ "Scroller", "ColReorder" ], + "data": [ + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -21,7 +65,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -91,15 +135,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -111,7 +149,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -256,6 +293,150 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2235 + ] + }, + { + "reviewed": false, + "ids": [ + 2203, + 2204, + 2205, + 2206, + 2207, + 2208, + 2209, + 2210, + 2236 + ] + }, + { + "reviewed": false, + "ids": [ + 2211, + 2212, + 2213, + 2214, + 2215, + 2216, + 2217, + 2218, + 2237 + ] + }, + { + "reviewed": false, + "ids": [ + 2219, + 2220, + 2221, + 2222, + 2223, + 2224, + 2225, + 2226, + 2238 + ] + }, + { + "reviewed": false, + "ids": [ + 2227, + 2228, + 2229, + 2230, + 2231, + 2232, + 2233, + 2234, + 2239 + ] + } + ], + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + "Hypotension*<\/b>", + "Atrial Fibrillation*<\/b>", + "Tachycardia*<\/b>", + "Urinary Tract Infection*<\/b>", + "Atrial Fibrillation*<\/b>" + ], + [ + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>" + ], + [ + "2023-07-07*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-08-16*<\/b>" + ], + [ + null, + null, + null, + null, + null + ], + [ + "Grade 1*<\/b>", + "Grade 2*<\/b>", + "Grade 2*<\/b>", + "Grade 1*<\/b>", + "Grade 2*<\/b>" + ], + [ + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>" + ], + [ + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>" + ], + [ + "None*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>" + ], + [ + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>" + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -268,7 +449,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -333,15 +514,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -353,7 +528,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -8346,6 +8520,71 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 598, + 599, + 600, + 601, + 602, + 603, + 604, + 1423 + ] + }, + { + "reviewed": false, + "ids": [ + 605, + 606, + 607, + 608, + 609, + 610, + 1424 + ] + } + ], + [ + "Screening", + "Visit 1" + ], + [ + "133*<\/b> mmHg", + "115*<\/b> mmHg" + ], + [ + "69*<\/b> mmHg", + "62*<\/b> mmHg" + ], + [ + "56*<\/b> beats/min", + "84*<\/b> beats/min" + ], + [ + "18*<\/b> breaths/min", + null + ], + [ + "37*<\/b> °C", + "36.6*<\/b> °C" + ], + [ + "0.01*<\/b> %", + "0.01*<\/b> %" + ], + [ + "23.66*<\/b> kg/m2", + "23.66*<\/b> kg/m2" + ], + [ + "70*<\/b> kg", + "62*<\/b> kg" + ] + ], "container": "\n \n \n
Review Status<\/th>\n Event<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -8358,7 +8597,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "name": "Review Status", @@ -8415,15 +8654,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -8435,7 +8668,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ From 31346b6452ccbef0544325bc71d470950fe37bc4 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:40:27 -0500 Subject: [PATCH 48/49] Update `app-feature-3` JSON --- .../app_feature_03/app-feature-3-002.json | 214 ++++++++++++++++-- 1 file changed, 194 insertions(+), 20 deletions(-) diff --git a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json index 6ff26824..63696d48 100644 --- a/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json +++ b/tests/testthat/_snaps/app_feature_03/app-feature-3-002.json @@ -483,6 +483,50 @@ "Scroller", "ColReorder" ], + "data": [ + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ], + [ + + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n Start date<\/th>\n End date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Category<\/th>\n Awareness date<\/th>\n Date of death<\/th>\n Death reason<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -495,7 +539,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -565,15 +609,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -585,7 +623,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ @@ -730,6 +767,150 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": false, + "ids": [ + 2195, + 2196, + 2197, + 2198, + 2199, + 2200, + 2201, + 2202, + 2235 + ] + }, + { + "reviewed": false, + "ids": [ + 2203, + 2204, + 2205, + 2206, + 2207, + 2208, + 2209, + 2210, + 2236 + ] + }, + { + "reviewed": false, + "ids": [ + 2211, + 2212, + 2213, + 2214, + 2215, + 2216, + 2217, + 2218, + 2237 + ] + }, + { + "reviewed": false, + "ids": [ + 2219, + 2220, + 2221, + 2222, + 2223, + 2224, + 2225, + 2226, + 2238 + ] + }, + { + "reviewed": false, + "ids": [ + 2227, + 2228, + 2229, + 2230, + 2231, + 2232, + 2233, + 2234, + 2239 + ] + } + ], + [ + 1, + 2, + 3, + 4, + 5 + ], + [ + "Hypotension*<\/b>", + "Atrial Fibrillation*<\/b>", + "Tachycardia*<\/b>", + "Urinary Tract Infection*<\/b>", + "Atrial Fibrillation*<\/b>" + ], + [ + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>", + "None*<\/b>" + ], + [ + "2023-07-07*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-07-05*<\/b>", + "2023-08-16*<\/b>" + ], + [ + null, + null, + null, + null, + null + ], + [ + "Grade 1*<\/b>", + "Grade 2*<\/b>", + "Grade 2*<\/b>", + "Grade 1*<\/b>", + "Grade 2*<\/b>" + ], + [ + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>", + "Not related*<\/b>" + ], + [ + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>", + "Not Applicable*<\/b>" + ], + [ + "None*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>", + "Concomitant therapy/medication*<\/b>" + ], + [ + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>", + "No*<\/b>" + ] + ], "container": "\n \n \n
Review Status<\/th>\n N<\/th>\n Name<\/th>\n AESI<\/th>\n start date<\/th>\n end date<\/th>\n CTCAE severity<\/th>\n Treatment related<\/th>\n Treatment action<\/th>\n Other action<\/th>\n Serious Adverse Event<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -742,7 +923,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "className": "dt-right", @@ -807,15 +988,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -827,7 +1002,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ From 52c5d4255856e72236aa21fbb032a22c04997c2c Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 6 Dec 2024 08:43:04 -0500 Subject: [PATCH 49/49] Update `study_forms` JSONs --- .../mod_study_forms/study_forms-001.json | 98 +++++++++++++++++-- .../mod_study_forms/study_forms-002.json | 98 +++++++++++++++++-- 2 files changed, 176 insertions(+), 20 deletions(-) diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json index 78f82307..2cbebe15 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-001.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-001.json @@ -1244,6 +1244,91 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": null, + "ids": [ + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 440 + ] + }, + { + "reviewed": null, + "ids": [ + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 441 + ] + }, + { + "reviewed": false, + "ids": [ + 92, + 93, + 94, + 95, + 96 + ] + } + ], + [ + "Screening", + "Visit 1", + "Visit 2" + ], + [ + "121*<\/b> mmHg", + "120*<\/b> mmHg", + "149*<\/b> mmHg" + ], + [ + "68 mmHg", + "68 mmHg", + "77*<\/b> mmHg" + ], + [ + "82 beats/min", + "82 beats/min", + "63*<\/b> beats/min" + ], + [ + "18*<\/b> breaths/min", + "18 breaths/min", + "19*<\/b> breaths/min" + ], + [ + "36.7*<\/b> °C", + "36.7 °C", + "37*<\/b> °C" + ], + [ + "6.3*<\/b> %", + "0.01 %", + null + ], + [ + "20.96 kg/m2", + "21.87 kg/m2", + null + ], + [ + "77.2*<\/b> kg", + "61*<\/b> kg", + null + ] + ], "container": "\n \n \n
Review Status<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -1256,7 +1341,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "name": "Review Status", @@ -1313,15 +1398,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -1333,7 +1412,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [ diff --git a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json index 78f82307..2cbebe15 100644 --- a/tests/testthat/_snaps/mod_study_forms/study_forms-002.json +++ b/tests/testthat/_snaps/mod_study_forms/study_forms-002.json @@ -1244,6 +1244,91 @@ "Scroller", "ColReorder" ], + "data": [ + [ + { + "reviewed": null, + "ids": [ + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 440 + ] + }, + { + "reviewed": null, + "ids": [ + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 441 + ] + }, + { + "reviewed": false, + "ids": [ + 92, + 93, + 94, + 95, + 96 + ] + } + ], + [ + "Screening", + "Visit 1", + "Visit 2" + ], + [ + "121*<\/b> mmHg", + "120*<\/b> mmHg", + "149*<\/b> mmHg" + ], + [ + "68 mmHg", + "68 mmHg", + "77*<\/b> mmHg" + ], + [ + "82 beats/min", + "82 beats/min", + "63*<\/b> beats/min" + ], + [ + "18*<\/b> breaths/min", + "18 breaths/min", + "19*<\/b> breaths/min" + ], + [ + "36.7*<\/b> °C", + "36.7 °C", + "37*<\/b> °C" + ], + [ + "6.3*<\/b> %", + "0.01 %", + null + ], + [ + "20.96 kg/m2", + "21.87 kg/m2", + null + ], + [ + "77.2*<\/b> kg", + "61*<\/b> kg", + null + ] + ], "container": "\n \n \n
Review Status<\/th>\n event_name<\/th>\n Systolic blood pressure<\/th>\n Diastolic blood pressure<\/th>\n Pulse<\/th>\n Resp<\/th>\n Temperature<\/th>\n Weight change since screening<\/th>\n BMI<\/th>\n Weight<\/th>\n <\/tr>\n <\/thead>\n<\/table>", "options": { "scrollY": 400, @@ -1256,7 +1341,7 @@ "columnDefs": [ { "targets": 0, - "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nreturn ``;\n}" + "render": "function(data, type, row, meta) {\nvar reviewed = data.reviewed;\nvar updated = data.updated;\nreturn ``;\n}" }, { "name": "Review Status", @@ -1313,15 +1398,9 @@ ], "autoWidth": false, - "orderClasses": false, - "ajax": { - "type": "POST", - "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = false;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" - }, - "serverSide": true, - "processing": true + "orderClasses": false }, - "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", + "callback": "function(table) {\ntable.on('click', 'input[type=\"checkbox\"]', function(){\nvar tblId = $(this).closest('.datatables').attr('id');\nvar cell = table.cell($(this).closest('td'));\nvar rowIdx = table.row($(this).closest('tr')).index();\nvar ids = cell.data().ids;\nvar review = $(this).is(':indeterminate') ? null : $(this).is(':checked');\ncell.data().updated = review;\nvar info = {review: review, ids: ids, row: tblId + '_row_' + rowIdx};\nShiny.setInputValue(tblId + '_review_selection:CS.reviewInfo', info);\n})\n}", "selection": { "mode": "none", "selected": null, @@ -1333,7 +1412,6 @@ "options.columnDefs.0.render", "options.createdRow", "options.initComplete", - "options.ajax.data", "callback" ], "jsHooks": [