Skip to content

Commit

Permalink
Merge pull request #148 from openpharma/jt-99-review_by_row-devex
Browse files Browse the repository at this point in the history
Devex: Review by records instead of `subject_id` & `form_id` "rv_row"
  • Loading branch information
jthompson-arcus authored Dec 6, 2024
2 parents f896b4f + 52c5d42 commit 1306692
Show file tree
Hide file tree
Showing 23 changed files with 2,364 additions and 428 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: clinsight
Title: ClinSight
Version: 0.1.1.9011
DevexVersion: 9000
DevexVersion: 9001
Authors@R: c(
person("Leonard Daniël", "Samson", , "[email protected]", role = c("cre", "aut"),
comment = c(ORCID = "0000-0002-6252-7639")),
Expand Down
10 changes: 5 additions & 5 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
- Added form type as a class to be used in `create_table()` to display tables.
- Add a logging table to the DB for reviews.
- Simplify pulling data from DB for reviews.
- Review data by records IDs instead of subject & form

## Bug fixes

- The test-coverage GHA workflow is updated so that codecov uploads work again.

## `devex` changes
- Added `Excel` download button to Queries table & patient listings that need review.
- Added helper function to automatically determine when adding said excel button is appropriate.
- Review data by records IDs instead of subject & form

# clinsight 0.1.1

## Changed
Expand All @@ -26,10 +30,6 @@
- Fixed inconsistencies in app messages when saving a review for a form with items with different review states (with some items reviewed previously by a different reviewer, and some items being completely new).
- Fixed a bug where clinsight deployed with `shinyproxy` would crash when a user with non-ASCII letters in their name would attempt to login. In this new version, when using the `shinyproxy` deployment configuration, the user name is now expected to be base64 encoded, and will now be base64 encoded by `clinsight` by default, so that the app can also handle non-ASCII signs in user names that are stored in HTTP headers. To display the user name correctly, use base64 encoding in the `application.yml` in ShinyProxy settings (for example: `http-headers.X_SP_USERNAME: "#{T(java.util.Base64).getEncoder().encodeToString(oidcUser.getFullName().getBytes())}"`).

## `devex` changes
- Added `Excel` download button to Queries table & patient listings that need review.
- Added helper function to automatically determine when adding said excel button is appropriate.

# clinsight 0.1.0

## Changed
Expand Down
3 changes: 3 additions & 0 deletions R/app_server.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ 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,
credentials_db = credentials_db,
Expand Down
12 changes: 12 additions & 0 deletions R/fct_tables.R
Original file line number Diff line number Diff line change
Expand Up @@ -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") ~ list(list(reviewed = NA, ids = id)),
any(reviewed == "Yes") ~ list(list(reviewed = TRUE, ids = id)),
.default = list(list(reviewed = FALSE, ids = id))
),
.by = dplyr::all_of(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}},
Expand Down Expand Up @@ -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",
Expand Down
105 changes: 94 additions & 11 deletions R/mod_common_forms.R
Original file line number Diff line number Diff line change
Expand Up @@ -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, "'.")
Expand Down Expand Up @@ -125,23 +126,90 @@ 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

# determine DT dom / exts / opts
DT <- dt_config(SAE_data,
table_name = paste("SAE", ifelse(input$show_all_data,
"all_patients", r$subject_id), sep = "."))
datatable_custom(
SAE_data, rename_vars = table_names, rownames= FALSE,
title = "Serious Adverse Events", escape = FALSE,
dom = DT$dom, extensions = DT$exts, options = DT$opts
)
SAE_data,
rename_vars = c("Review Status" = "o_reviewed", table_names),
rownames = FALSE,
title = "Serious Adverse Events",
escape = FALSE,
dom = DT$dom,
extensions = DT$exts,
selection = "none",
callback = checkbox_callback,
options = append(list(
columnDefs = list(list(
targets = 0,
render = checkbox_render
)),
createdRow = checkbox_create_callback
),
DT$opts))
}, server = FALSE)

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

Check warning on line 167 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L167

Added line #L167 was not covered by tests

session$userData$review_records[[form]] <-
dplyr::rows_upsert(
session$userData$review_records[[form]],
input$common_form_table_review_selection,
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, subject_id == r$subject_id & item_group == form),
by = c("id", "reviewed")
) |>
dplyr::arrange(id)

Check warning on line 184 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L169-L184

Added lines #L169 - L184 were not covered by tests
})

observeEvent(session$userData$update_checkboxes[[form]], {
checked <- session$userData$update_checkboxes[[form]]

Check warning on line 188 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L188

Added line #L188 was not covered by tests

update_cbs(ns("common_form_table"), checked)
update_cbs(ns("SAE_table"), checked)

Check warning on line 191 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L190-L191

Added lines #L190 - L191 were not covered by tests
})

observeEvent(input$SAE_table_review_selection, {
session$userData$update_checkboxes[[form]] <- NULL

Check warning on line 195 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L195

Added line #L195 was not covered by tests

session$userData$review_records[[form]] <-
dplyr::rows_upsert(
session$userData$review_records[[form]],
input$SAE_table_review_selection,
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, subject_id == r$subject_id & item_group == form),
by = c("id", "reviewed")
) |>
dplyr::arrange(id)

Check warning on line 212 in R/mod_common_forms.R

View check run for this annotation

Codecov / codecov/patch

R/mod_common_forms.R#L197-L212

Added lines #L197 - L212 were not covered by tests
})

output[["common_form_table"]] <- DT::renderDT({
Expand All @@ -153,16 +221,31 @@ mod_common_forms_server <- function(
dplyr::select(-dplyr::starts_with("SAE"))
}
if(!input$show_all_data) df$subject_id <- NULL

# determine DT dom / exts / opts
DT <- dt_config(df,
table_name = paste(form, ifelse(input$show_all_data,
"all_patients", r$subject_id), sep = "."))
datatable_custom(
df, rename_vars = table_names, rownames= FALSE,title = form,
escape = FALSE, dom = DT$dom, extensions = DT$exts, options = DT$opts)
})

df,
rename_vars = c("Review Status" = "o_reviewed", table_names),
rownames= FALSE,
title = form,
escape = FALSE,
dom = DT$dom,
extensions = DT$exts,
selection = "none",
callback = checkbox_callback,
options = append(list(
columnDefs = list(list(
targets = 0,
render = checkbox_render
)),
createdRow = checkbox_create_callback
),
DT$opts))
}, server = FALSE)

})
}

Expand Down
Loading

0 comments on commit 1306692

Please sign in to comment.