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>",
+ " | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |