diff --git a/R/Report_StudyInfo.R b/R/Report_StudyInfo.R index 3ca7f78f6..9407aacd0 100644 --- a/R/Report_StudyInfo.R +++ b/R/Report_StudyInfo.R @@ -1,13 +1,15 @@ #' Report Study Information #' -#' @description -#' `r lifecycle::badge("stable")` +#' @description `r lifecycle::badge("stable")` #' #' This function generates a table summarizing study metadata as an interactive #' [gt::gt()] wrapped in HTML. #' #' @inheritParams shared-params -#' @param lStudyLabels A list containing study labels. Default is NULL. +#' @param lStudyLabels `list` A list containing study labels. Default is NULL. +#' @param strId `character` A string to identify the output table. +#' @param tagHeader `shiny.tag` An HTML tag or tags to use as a header for the +#' table. #' @param lStudy `deprecated` Study information as a named list. #' #' @export @@ -17,36 +19,75 @@ Report_StudyInfo <- function( dfGroups, lStudyLabels = NULL, + strId = "study_table", + tagHeader = htmltools::h2("Study Status"), lStudy = deprecated() ) { rlang::check_installed("gt", reason = "to render table from `Report_StudyInfo`") study_status_table <- MakeStudyInfo(dfGroups, lStudyLabels, lStudy = lStudy) + subcols <- c("GroupID", "nickname", "Status", "SiteCount", "ParticipantCount") show_table <- study_status_table %>% - dplyr::filter( - .data$Param %in% c("GroupID", "nickname", "Status", "SiteCount", "ParticipantCount") - ) %>% - dplyr::select("Description", "Value") %>% - gsm_gt(id = "study_table") + dplyr::filter(.data$Param %in% subcols) %>% + gt_StudyInfo(id = strId) - hide_table <- study_status_table %>% - dplyr::select("Description", "Value") %>% - gsm_gt(id = "study_table_hide") + strId_hide <- paste0(strId, "_hide") + hide_table <- htmltools::div( + id = strId_hide, + style = "display: none;", + gt_StudyInfo(study_status_table, id = paste0(strId_hide, "_gt")) + ) - show_details_button <- HTML(glue::glue( + htmltools::tagList( + tagHeader, + htmlDetailsButton(strId, strId_hide), + show_table, + hide_table, + htmlDependency_toggleTables() + ) +} + +htmlDetailsButton <- function(strId, strId_hide) { + HTML(glue::glue( '", + '', .sep = "\n" )) +} +htmlDependency_toggleTables <- function() { htmltools::tagList( - htmltools::h2("Study Status"), - show_details_button, - show_table, - hide_table + htmltools::htmlDependency( + name = "toggleTables", + version = "1.0.0", + src = "report/lib", + package = "gsm", + script = "toggleTables.js" + ), + htmltools::htmlDependency( + name = "toggleButton", + version = "1.0.0", + src = "report", + package = "gsm", + stylesheet = "toggleButton.css" + ) ) } + +gt_StudyInfo <- function(data, ...) { + data %>% + dplyr::select("Description", "Value") %>% + gsm_gt(...) %>% + gt::cols_align(columns = "Value", align = "right") %>% + gt::tab_options( + column_labels.hidden = TRUE + ) +} diff --git a/inst/README.md b/inst/README.md index 82df9affd..e13662d87 100644 --- a/inst/README.md +++ b/inst/README.md @@ -139,7 +139,7 @@ JavaScript utility functions used to configure `htmlwidgets` and for custom repo ├── dragOverallSiteDropdown.js ├── number_to_array.js ├── overallSiteDropdown.js -└── showMetaTableDetails.js +└── toggleTables.js ``` --- diff --git a/inst/report/Report_KRI.Rmd b/inst/report/Report_KRI.Rmd index 3b738b87f..26e3166be 100644 --- a/inst/report/Report_KRI.Rmd +++ b/inst/report/Report_KRI.Rmd @@ -154,7 +154,6 @@ params$dfMetrics %>% ```{r echo=FALSE} group_dropdown <- system.file('report', 'lib', 'overallGroupDropdown.js', package = "gsm") dropdown_drag <- system.file('report', 'lib', 'dragOverallGroupDropdown.js', package = "gsm") -meta_details <- system.file('report', 'lib', 'showMetaTableDetails.js', package = "gsm") ``` ```{js, file={group_dropdown}, echo=FALSE} @@ -162,6 +161,3 @@ meta_details <- system.file('report', 'lib', 'showMetaTableDetails.js', package ```{js, file={dropdown_drag}, echo=FALSE} ``` - -```{js, file={meta_details}, echo=FALSE} -``` diff --git a/inst/report/lib/showMetaTableDetails.js b/inst/report/lib/showMetaTableDetails.js deleted file mode 100644 index 346a89fc8..000000000 --- a/inst/report/lib/showMetaTableDetails.js +++ /dev/null @@ -1,23 +0,0 @@ -const detailButton = document.querySelector('.btn-show-details'); - -if (detailButton !== null) { - let hidden = false; - - detailButton.addEventListener('click', function() { - const shownTable = document.querySelector('#study_table'); - const hiddenTable = document.querySelector('#study_table_hide'); - const toggleLabel = document.querySelector('.toggle-label'); - - if (!hidden) { - shownTable.style.display = 'none'; - hiddenTable.style.display = 'block'; - toggleLabel.innerHTML = 'Hide Details'; - hidden = true; - } else { - shownTable.style.display = 'block'; - hiddenTable.style.display = 'none'; - toggleLabel.innerHTML = 'Show Details'; - hidden = false; - } - }) -} diff --git a/inst/report/lib/toggleTables.js b/inst/report/lib/toggleTables.js new file mode 100644 index 000000000..dfbe7b22e --- /dev/null +++ b/inst/report/lib/toggleTables.js @@ -0,0 +1,29 @@ +/** + * Toggles between two tables when a checkbox is clicked. + * + * The checkbox element should have the following data attributes: + * - data-shown-table: The ID of the table to show when hidden. + * - data-hidden-table: The ID of the table to hide when shown. + * + * @param {HTMLInputElement} checkbox - The checkbox element that triggers the toggle action. + */ +function toggleTables(checkbox) { + const hidden = checkbox.checked; + + const shownTableId = checkbox.dataset.shownTable; + const hiddenTableId = checkbox.dataset.hiddenTable; + + const shownTable = document.querySelector(`#${shownTableId}`); + const hiddenTable = document.querySelector(`#${hiddenTableId}`); + const toggleLabel = checkbox.parentElement.querySelector('.toggle-label'); + + if (hidden) { + shownTable.style.display = 'none'; + hiddenTable.style.display = 'block'; + toggleLabel.innerHTML = 'Hide Details'; + } else { + shownTable.style.display = 'block'; + hiddenTable.style.display = 'none'; + toggleLabel.innerHTML = 'Show Details'; + } +} diff --git a/inst/report/styles.css b/inst/report/styles.css index f647ef8ae..1f20a72f3 100644 --- a/inst/report/styles.css +++ b/inst/report/styles.css @@ -131,78 +131,6 @@ tbody.gt_table_body tr:hover:nth-child(odd) { background: #f9f9f9; } - -div#study_table_hide { - display: none; -} - - - -/* credit to: https://codepen.io/alvarotrigo/pen/YzEdrKj */ - -*, -*:before, -*:after { - box-sizing: border-box; -} - -.toggle { - cursor: pointer; - display: inline-block; -} - -.toggle-switch { - display: inline-block; - background: #ccc; - border-radius: 16px; - width: 58px; - height: 26px; - position: relative; - vertical-align: middle; - transition: background 0.25s; -} - -.toggle-switch:before, .toggle-switch:after { - content: ""; -} - -.toggle-switch:before { - display: block; - background: linear-gradient(to bottom, #fff 0%, #eee 100%); - border-radius: 50%; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); - width: 20px; - height: 20px; - position: absolute; - top: 4px; - left: 4px; - transition: left 0.25s; -} - -.toggle:hover .toggle-switch:before { - background: linear-gradient(to bottom, #fff 0%, #fff 100%); - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5); -} - -.toggle-checkbox:checked + .toggle-switch { - background: var(--blue-button-color); -} - -.toggle-checkbox:checked + .toggle-switch:before { - left: 30px; -} - -.toggle-checkbox { - position: absolute; - visibility: hidden; -} - -.toggle-label { - margin-left: 5px; - position: relative; - top: 2px; -} - #timeline { display: none; } diff --git a/inst/report/toggleButton.css b/inst/report/toggleButton.css new file mode 100644 index 000000000..ed441b4de --- /dev/null +++ b/inst/report/toggleButton.css @@ -0,0 +1,45 @@ +/* Toggle Switch Styling */ +.toggle { + display: inline-flex; /* Aligns the checkbox and label */ + align-items: center; /* Centers the items vertically */ + cursor: pointer; +} + +.toggle-switch { + background: #ccc; /* Default background color */ + border-radius: 16px; /* Makes the edges rounded */ + width: 58px; + height: 26px; + position: relative; + transition: background 0.25s ease-in-out; /* Smooth transition for color change */ +} + +.toggle-switch::before { + content: ""; + background: #fff; + border-radius: 50%; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); + width: 20px; + height: 20px; + position: absolute; + top: 3px; /* Centers the knob vertically */ + left: 3px; /* Starts at the leftmost side */ + transition: left 0.25s ease-in-out; /* Smooth transition for position change */ +} + +.toggle-checkbox:checked + .toggle-switch { + background: var(--blue-button-color); /* Changes color when toggled */ +} + +.toggle-checkbox:checked + .toggle-switch::before { + left: 33px; /* Moves the knob to the right when checked */ +} + +.toggle-checkbox { + position: absolute; + visibility: hidden; /* Hides the checkbox but maintains accessibility */ +} + +.toggle-label { + margin-left: 8px; /* Adds space between the switch and label text */ +} diff --git a/man/MakeStudyInfo.Rd b/man/MakeStudyInfo.Rd index 16ebf44a6..81d7405e1 100644 --- a/man/MakeStudyInfo.Rd +++ b/man/MakeStudyInfo.Rd @@ -9,7 +9,7 @@ MakeStudyInfo(dfGroups, lStudyLabels = NULL, lStudy = deprecated()) \arguments{ \item{dfGroups}{\code{data.frame} Group-level metadata dictionary. Created by passing CTMS site and study data to \code{\link[=MakeLongMeta]{MakeLongMeta()}}. Expected columns: \code{GroupID}, \code{GroupLevel}, \code{Param}, \code{Value}.} -\item{lStudyLabels}{A list containing study labels. Default is NULL.} +\item{lStudyLabels}{\code{list} A list containing study labels. Default is NULL.} \item{lStudy}{\code{deprecated} Study information as a named list.} } diff --git a/man/Report_StudyInfo.Rd b/man/Report_StudyInfo.Rd index bd5e6671a..ddf1e8b0a 100644 --- a/man/Report_StudyInfo.Rd +++ b/man/Report_StudyInfo.Rd @@ -4,12 +4,23 @@ \alias{Report_StudyInfo} \title{Report Study Information} \usage{ -Report_StudyInfo(dfGroups, lStudyLabels = NULL, lStudy = deprecated()) +Report_StudyInfo( + dfGroups, + lStudyLabels = NULL, + strId = "study_table", + tagHeader = htmltools::h2("Study Status"), + lStudy = deprecated() +) } \arguments{ \item{dfGroups}{\code{data.frame} Group-level metadata dictionary. Created by passing CTMS site and study data to \code{\link[=MakeLongMeta]{MakeLongMeta()}}. Expected columns: \code{GroupID}, \code{GroupLevel}, \code{Param}, \code{Value}.} -\item{lStudyLabels}{A list containing study labels. Default is NULL.} +\item{lStudyLabels}{\code{list} A list containing study labels. Default is NULL.} + +\item{strId}{\code{character} A string to identify the output table.} + +\item{tagHeader}{\code{shiny.tag} An HTML tag or tags to use as a header for the +table.} \item{lStudy}{\code{deprecated} Study information as a named list.} } diff --git a/man/RunStep.Rd b/man/RunStep.Rd index ff97ca86c..1a4f28bea 100644 --- a/man/RunStep.Rd +++ b/man/RunStep.Rd @@ -32,7 +32,7 @@ Parameters should be specified as a named list in \code{lStep$params}, where eac that will be parsed and then passed to the specified function as a set of parameter names/values. Parameter values should be specified as scalar strings. Those values are then pulled from \code{lMeta} or \code{lData} when possible. When no matching \code{lData} or \code{lMeta} objects are found, parameter values are passed through as -stings. Note that parsing vectorized parameters is not supported at this time; they are passed directly +strings. Note that parsing vectorized parameters is not supported at this time; they are passed directly as character vectors. To pass a vector or list, we recommend saving it as an object in \code{lData}. Full prioritization for parsing parameters is below: diff --git a/tests/testthat/_snaps/Report_StudyInfo.md b/tests/testthat/_snaps/Report_StudyInfo.md index cf84060b0..73c550b9a 100644 --- a/tests/testthat/_snaps/Report_StudyInfo.md +++ b/tests/testthat/_snaps/Report_StudyInfo.md @@ -5,7 +5,11 @@ Output

Study Status

@@ -459,37 +463,33 @@ } - - - - - - + - +
DescriptionValue
NicknameNickname
Nickname
-
- - - - - - - - +
DescriptionValue
+ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
Study IDUnique Study ID
Unique Study ID
Protocol TitleStudy Title
Study Title
NicknameNickname
Nickname
Enrolled Sites10
10
Planned Sites15
15
Enrolled Participants100
100
Planned Participants200
200
StatusOngoing
Ongoing
ProductProduct Name
Product Name
PhasePhase 1
Phase 1
Therapeutic AreaTherapeutic Area
Therapeutic Area
Protocol IndicationIndication
Indication
Protocol TypeType
Type
Protocol Row Id123
123
Protocol Product Number456
456
Est Fpfv2023-01-01
2023-01-01
Est Lpfv2023-12-01
2023-12-01
Est Lplv2024-01-01
2024-01-01
+
# Generated table has correct structure and content w/dfGroups @@ -979,7 +975,11 @@ Output

Study Status

@@ -1433,43 +1433,39 @@ } - - - - - - + - + - + - + - +
DescriptionValue
NicknameProtocol Nickname
Protocol Nickname
Study StatusActive
Active
Participants Enrolled50
50
Sites Enrolled154
154
-
- - - - - - - - +
DescriptionValue
+ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
Protocol Row Id1-1G9113
1-1G9113
StudyidAA-AA-000-0000
AA-AA-000-0000
Protocol TitleProtocol Title
Protocol Title
NicknameProtocol Nickname
Protocol Nickname
Protocol TypeInvestigator Sponsored
Investigator Sponsored
PhaseP3
P3
Num Plan Site190
190
Num Site Actl176
176
Est Fpfv2003-01-01
2003-01-01
Act Fpfv2003-01-01
2003-01-01
Est Lplv2021-06-01
2021-06-01
Act Lplv2021-06-01
2021-06-01
Est Lpfv2020-06-01
2020-06-01
Act Lpfv2020-06-01
2020-06-01
Study StatusActive
Active
Num Plan Subj1300
1300
Num Enrolled Subj M1301
1301
Protocol IndicationProtocol Indication
Protocol Indication
ProductProduct
Product
Therapeutic AreaTherapeutic Area
Therapeutic Area
Protocol Product Number123
123
X Rbm FlgY
Y
Participants Enrolled50
50
Sites Enrolled154
154
+