From 0d776a4e80404973e551f3a9e72d1c65dbc57ab9 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Tue, 10 Dec 2024 14:33:06 +0100 Subject: [PATCH 1/3] fix --- R/module_nested_tabs.R | 4 ++-- R/modules.R | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/R/module_nested_tabs.R b/R/module_nested_tabs.R index e26533cc92..528b18bb1d 100644 --- a/R/module_nested_tabs.R +++ b/R/module_nested_tabs.R @@ -347,8 +347,8 @@ srv_teal_module.teal_module <- function(id, .resolve_module_datanames <- function(data, modules) { stopifnot("data_rv must be teal_data object." = inherits(data, "teal_data")) - if (is.null(modules$datanames) || identical(modules$datanames, "all")) { - names(data) + if (is.null(modules$datanames) || setequal(modules$datanames, "all")) { + setdiff(names(data), attr(modules$datanames, "excluded")) } else { intersect( names(data), # Keep topological order from teal.data::names() diff --git a/R/modules.R b/R/modules.R index 2b27d5bb41..76759c016e 100644 --- a/R/modules.R +++ b/R/modules.R @@ -610,7 +610,13 @@ set_datanames <- function(modules, datanames) { modules$children <- lapply(modules$children, set_datanames, datanames) } else { if (identical(modules$datanames, "all")) { - modules$datanames <- datanames + included <- grep("^[^-]", datanames, value = TRUE) + if (length(included)) { + modules$datanames <- included + } else { + excluded <- gsub("^-", "", grep("^-", datanames, value = TRUE)) + attr(modules$datanames, "excluded") <- excluded + } } else { warning( "Not possible to modify datanames of the module ", modules$label, From c13d8311fe43199b5470244d94459384097adfc4 Mon Sep 17 00:00:00 2001 From: Dawid Kaledkowski Date: Thu, 12 Dec 2024 14:51:54 +0100 Subject: [PATCH 2/3] inheriting datanames --- R/init.R | 2 +- R/module_nested_tabs.R | 68 ++++++++++++++----- R/modules.R | 106 ++++++++++++++---------------- R/reporter_previewer_module.R | 2 +- R/teal_transform_module.R | 4 +- R/utils.R | 6 +- tests/testthat/test-module_teal.R | 2 +- 7 files changed, 109 insertions(+), 81 deletions(-) diff --git a/R/init.R b/R/init.R index 3f27eb385e..09af1f5a54 100644 --- a/R/init.R +++ b/R/init.R @@ -115,7 +115,7 @@ init <- function(data, if (inherits(modules, "teal_module")) { modules <- list(modules) } - if (checkmate::test_list(modules, min.len = 1, any.missing = FALSE, types = c("teal_module", "teal_modules"))) { + if (inherits(modules, "list")) { modules <- do.call(teal::modules, modules) } diff --git a/R/module_nested_tabs.R b/R/module_nested_tabs.R index 528b18bb1d..49c740ae93 100644 --- a/R/module_nested_tabs.R +++ b/R/module_nested_tabs.R @@ -60,12 +60,12 @@ ui_teal_module.teal_modules <- function(id, modules, depth = 0L) { # by giving an id, we can reactively respond to tab changes list( id = ns("active_tab"), - type = if (modules$label == "root") "pills" else "tabs" + type = if (attr(modules, "label") == "root") "pills" else "tabs" ), lapply( - names(modules$children), + names(modules), function(module_id) { - module_label <- modules$children[[module_id]]$label + module_label <- attr(modules[[module_id]], "label") if (is.null(module_label)) { module_label <- icon("fas fa-database") } @@ -74,7 +74,7 @@ ui_teal_module.teal_modules <- function(id, modules, depth = 0L) { value = module_id, # when clicked this tab value changes input$ ui_teal_module( id = ns(module_id), - modules = modules$children[[module_id]], + modules = modules[[module_id]], depth = depth + 1L ) ) @@ -89,7 +89,7 @@ ui_teal_module.teal_modules <- function(id, modules, depth = 0L) { #' @export ui_teal_module.teal_module <- function(id, modules, depth = 0L) { ns <- NS(id) - args <- c(list(id = ns("module")), modules$ui_args) + args <- c(list(id = ns("module")), attr(modules, "ui_args")) ui_teal <- tagList( shinyjs::hidden( @@ -118,14 +118,18 @@ ui_teal_module.teal_module <- function(id, modules, depth = 0L) { uiOutput(ns("data_reactive"), inline = TRUE), tagList( if (depth >= 2L) tags$div(style = "mt-6"), - if (!is.null(modules$datanames)) { + if (!is.null(attr(modules, "datanames"))) { fluidRow( column(width = 9, ui_teal, class = "teal_primary_col"), column( width = 3, ui_data_summary(ns("data_summary")), ui_filter_data(ns("filter_panel")), - ui_transform_teal_data(ns("data_transform"), transformators = modules$transformators, class = "well"), + ui_transform_teal_data( + ns("data_transform"), + transformators = attr(modules, "transformators"), + class = "well" + ), class = "teal_secondary_col" ) ) @@ -141,6 +145,7 @@ srv_teal_module <- function(id, data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), @@ -161,6 +166,7 @@ srv_teal_module.default <- function(id, data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), @@ -174,12 +180,13 @@ srv_teal_module.teal_modules <- function(id, data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), is_active = reactive(TRUE)) { moduleServer(id = id, module = function(input, output, session) { - logger::log_debug("srv_teal_module.teal_modules initializing the module { deparse1(modules$label) }.") + logger::log_debug("srv_teal_module.teal_modules initializing the module { deparse1(attr(modules, 'label')) }.") observeEvent(data_load_status(), { tabs_selector <- sprintf("#%s li a", session$ns("active_tab")) @@ -196,14 +203,16 @@ srv_teal_module.teal_modules <- function(id, } }) + resolved_datanames <- .resolve_parent_datanames(modules, inherited = inherited_datanames) modules_output <- sapply( - names(modules$children), + names(modules), function(module_id) { srv_teal_module( id = module_id, data_rv = data_rv, - modules = modules$children[[module_id]], + modules = modules[[module_id]], datasets = datasets, + inherited_datanames = resolved_datanames, slices_global = slices_global, reporter = reporter, is_active = reactive( @@ -226,14 +235,15 @@ srv_teal_module.teal_module <- function(id, data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), is_active = reactive(TRUE)) { - logger::log_debug("srv_teal_module.teal_module initializing the module: { deparse1(modules$label) }.") + logger::log_debug("srv_teal_module.teal_module initializing the module: { deparse1(attr(modules, 'label')) }.") moduleServer(id = id, module = function(input, output, session) { module_out <- reactiveVal() - + attr(modules, "datanames") <- .resolve_parent_datanames(modules, inherited = inherited_datanames) active_datanames <- reactive({ .resolve_module_datanames(data = data_rv(), modules = modules) }) @@ -250,7 +260,7 @@ srv_teal_module.teal_module <- function(id, # filter_manager_module_srv needs to be called before filter_panel_srv # Because available_teal_slices is used in FilteredData$srv_available_slices (via srv_filter_panel) # and if it is not set, then it won't be available in the srv_filter_panel - srv_module_filter_manager(modules$label, module_fd = datasets, slices_global = slices_global) + srv_module_filter_manager(attr(modules, "label"), module_fd = datasets, slices_global = slices_global) call_once_when(is_active(), { filtered_teal_data <- srv_filter_data( @@ -264,7 +274,7 @@ srv_teal_module.teal_module <- function(id, transformed_teal_data <- srv_transform_teal_data( "data_transform", data = filtered_teal_data, - transformators = modules$transformators, + transformators = attr(modules, "transformators"), modules = modules, is_transform_failed = is_transform_failed ) @@ -320,7 +330,7 @@ srv_teal_module.teal_module <- function(id, # This function calls a module server function. .call_teal_module <- function(modules, datasets, filtered_teal_data, reporter) { # collect arguments to run teal_module - args <- c(list(id = "module"), modules$server_args) + args <- c(list(id = "module"), attr(modules, "server_args")) if (is_arg_used(modules$server, "reporter")) { args <- c(args, list(reporter = reporter)) } @@ -347,16 +357,38 @@ srv_teal_module.teal_module <- function(id, .resolve_module_datanames <- function(data, modules) { stopifnot("data_rv must be teal_data object." = inherits(data, "teal_data")) - if (is.null(modules$datanames) || setequal(modules$datanames, "all")) { - setdiff(names(data), attr(modules$datanames, "excluded")) + if (is.null(attr(modules, "datanames")) || setequal(attr(modules, "datanames"), "all")) { + names(data) + } else if (any(grepl("^-", attr(modules, "datanames")))) { + setdiff(names(data), gsub("^-", "", attr(modules, "datanames"))) } else { intersect( names(data), # Keep topological order from teal.data::names() - .include_parent_datanames(modules$datanames, teal.data::join_keys(data)) + .include_parent_datanames(attr(modules, "datanames"), teal.data::join_keys(data)) ) } } +.resolve_parent_datanames <- function(modules, inherited) { + if (is.null(inherited)) inherited <- "all" + if (identical(attr(modules, "datanames"), "all")) { + inherited + } else if (any(grepl("^[^-]", attr(modules, "datanames")))) { + grep("^-", attr(modules, "datanames"), value = TRUE) # keep only positive if positive set in module + } else if (any(grepl("^-", attr(modules, "datanames")))) { + if (identical(inherited, "all")) { + attr(modules, "datanames") + } else if (any(grepl("^-", inherited))) { + union(attr(modules, "datanames"), inherited) + } else { + setdiff( + inherited, + gsub("^-", "", attr(modules, "datanames")) + ) + } + } +} + #' Calls expression when condition is met #' #' Function postpones `handlerExpr` to the moment when `eventExpr` (condition) returns `TRUE`, diff --git a/R/modules.R b/R/modules.R index 76759c016e..176d6ce49a 100644 --- a/R/modules.R +++ b/R/modules.R @@ -276,15 +276,12 @@ module <- function(label = "module", } structure( - list( - label = label, - server = server, - ui = ui, - datanames = combined_datanames, - server_args = server_args, - ui_args = ui_args, - transformators = transformators - ), + list(ui = ui, server = server), + label = label, + datanames = combined_datanames, + server_args = server_args, + ui_args = ui_args, + transformators = transformators, class = "teal_module" ) } @@ -305,13 +302,11 @@ modules <- function(..., label = "root") { checkmate::assert_list(submodules, min.len = 1, any.missing = FALSE, types = c("teal_module", "teal_modules")) # name them so we can more easily access the children # beware however that the label of the submodules should not be changed as it must be kept synced - labels <- vapply(submodules, function(submodule) submodule$label, character(1)) + labels <- vapply(submodules, function(submodule) attr(submodule, "label"), character(1)) names(submodules) <- get_unique_labels(labels) structure( - list( - label = label, - children = submodules - ), + submodules, + label = label, class = "teal_modules" ) } @@ -375,21 +370,22 @@ format.teal_module <- function( } } - bookmarkable <- isTRUE(attr(x, "teal_bookmarkable")) + attrs <- attributes(x) + bookmarkable <- isTRUE(attrs$teal_bookmarkable) reportable <- "reporter" %in% names(formals(x$server)) - transformators <- if (length(x$transformators) > 0) { - paste(sapply(x$transformators, function(t) attr(t, "label")), collapse = ", ") + transformators <- if (length(attrs$transformators) > 0) { + paste(sapply(attrs$transformators, function(t) attr(t, "label")), collapse = ", ") } else { empty_text } - output <- pasten(current_prefix, crayon::bgWhite(x$label)) + output <- pasten(current_prefix, crayon::bgWhite(attrs$label)) if ("datasets" %in% what) { output <- paste0( output, - content_prefix, "|- ", crayon::yellow("Datasets : "), paste(x$datanames, collapse = ", "), "\n" + content_prefix, "|- ", crayon::yellow("Datasets : "), toString(attrs$datanames), "\n" ) } if ("properties" %in% what) { @@ -401,14 +397,14 @@ format.teal_module <- function( ) } if ("ui_args" %in% what) { - ui_args_formatted <- format_list(x$ui_args, label_width = 19) + ui_args_formatted <- format_list(attrs$ui_args, label_width = 19) output <- paste0( output, content_prefix, "|- ", crayon::green("UI Arguments : "), ui_args_formatted, "\n" ) } if ("server_args" %in% what) { - server_args_formatted <- format_list(x$server_args, label_width = 19) + server_args_formatted <- format_list(attrs$server_args, label_width = 19) output <- paste0( output, content_prefix, "|- ", crayon::green("Server Arguments : "), server_args_formatted, "\n" @@ -525,13 +521,14 @@ format.teal_module <- function( #' cat(format(complete_modules, what = c("ui_args", "server_args", "transformators"))) #' @export format.teal_modules <- function(x, is_root = TRUE, is_last = FALSE, parent_prefix = "", ...) { + attrs <- attributes(x) if (is_root) { header <- pasten(crayon::bold("TEAL ROOT")) new_parent_prefix <- " " #' Initial indent for root level } else { - if (!is.null(x$label)) { + if (!is.null(attrs$label)) { branch <- if (is_last) "L-" else "|-" - header <- pasten(parent_prefix, branch, " ", crayon::bold(x$label)) + header <- pasten(parent_prefix, branch, " ", crayon::bold(attrs$label)) new_parent_prefix <- paste0(parent_prefix, if (is_last) " " else "| ") } else { header <- "" @@ -539,12 +536,17 @@ format.teal_modules <- function(x, is_root = TRUE, is_last = FALSE, parent_prefi } } - if (length(x$children) > 0) { + if (length(attrs$datanames)) { + datasets_branch <- paste0(parent_prefix, "|- Datasets : ", toString(attrs$datanames)) + header <- paste0(header, datasets_branch, "\n") + } + + if (length(x) > 0) { children_output <- character(0) - n_children <- length(x$children) + n_children <- length(x) - for (i in seq_along(x$children)) { - child <- x$children[[i]] + for (i in seq_along(x)) { + child <- x[[i]] is_last_child <- (i == n_children) if (inherits(child, "teal_modules")) { @@ -606,24 +608,14 @@ print.teal_modules <- function(x, ...) { #' @export set_datanames <- function(modules, datanames) { checkmate::assert_multi_class(modules, c("teal_modules", "teal_module")) - if (inherits(modules, "teal_modules")) { - modules$children <- lapply(modules$children, set_datanames, datanames) + if (is.null(attr(modules, "datanames")) || identical(attr(modules, "datanames"), "all")) { + attr(modules, "datanames") <- datanames } else { - if (identical(modules$datanames, "all")) { - included <- grep("^[^-]", datanames, value = TRUE) - if (length(included)) { - modules$datanames <- included - } else { - excluded <- gsub("^-", "", grep("^-", datanames, value = TRUE)) - attr(modules$datanames, "excluded") <- excluded - } - } else { - warning( - "Not possible to modify datanames of the module ", modules$label, - ". set_datanames() can only change datanames if it was set to \"all\".", - call. = FALSE - ) - } + warning( + "Not possible to modify datanames of the", class(modules)[1], attr(modules, "label"), + ". set_datanames() can only change datanames if it was set to \"all\".", + call. = FALSE + ) } modules } @@ -639,9 +631,9 @@ set_datanames <- function(modules, datanames) { append_module <- function(modules, module) { checkmate::assert_class(modules, "teal_modules") checkmate::assert_class(module, "teal_module") - modules$children <- c(modules$children, list(module)) - labels <- vapply(modules$children, function(submodule) submodule$label, character(1)) - names(modules$children) <- get_unique_labels(labels) + modules <- c(modules, list(module)) + labels <- vapply(modules, function(submodule) attr(submodule, "label"), character(1)) + names(modules) <- get_unique_labels(labels) modules } @@ -662,7 +654,7 @@ extract_module <- function(modules, class) { } else if (inherits(modules, "teal_module")) { NULL } else if (inherits(modules, "teal_modules")) { - Filter(function(x) length(x) > 0L, lapply(modules$children, extract_module, class)) + Filter(function(x) length(x) > 0L, lapply(modules, extract_module, class)) } } @@ -677,7 +669,11 @@ drop_module <- function(modules, class) { } else if (inherits(modules, "teal_modules")) { do.call( "modules", - c(Filter(function(x) length(x) > 0L, lapply(modules$children, drop_module, class)), label = modules$label) + c( + Filter(function(x) length(x) > 0L, lapply(modules, drop_module, class)), + label = attr(modules, "label"), + datanames = attr(modules, "datanames") + ) ) } } @@ -694,7 +690,7 @@ drop_module <- function(modules, class) { is_arg_used <- function(modules, arg) { checkmate::assert_string(arg) if (inherits(modules, "teal_modules")) { - any(unlist(lapply(modules$children, is_arg_used, arg))) + any(unlist(lapply(modules, is_arg_used, arg))) } else if (inherits(modules, "teal_module")) { is_arg_used(modules$server, arg) || is_arg_used(modules$ui, arg) } else if (is.function(modules)) { @@ -719,7 +715,7 @@ modules_depth <- function(modules, depth = 0L) { checkmate::assert_multi_class(modules, c("teal_module", "teal_modules")) checkmate::assert_int(depth, lower = 0) if (inherits(modules, "teal_modules")) { - max(vapply(modules$children, modules_depth, integer(1), depth = depth + 1L)) + max(vapply(modules, modules_depth, integer(1), depth = depth + 1L)) } else { depth } @@ -733,9 +729,9 @@ modules_depth <- function(modules, depth = 0L) { #' @keywords internal module_labels <- function(modules) { if (inherits(modules, "teal_modules")) { - lapply(modules$children, module_labels) + lapply(modules, module_labels) } else { - modules$label + attr(modules, "label") } } @@ -749,8 +745,8 @@ modules_bookmarkable <- function(modules) { checkmate::assert_multi_class(modules, c("teal_modules", "teal_module")) if (inherits(modules, "teal_modules")) { setNames( - lapply(modules$children, modules_bookmarkable), - vapply(modules$children, `[[`, "label", FUN.VALUE = character(1)) + lapply(modules, modules_bookmarkable), + vapply(modules, attr, "label", FUN.VALUE = character(1)) ) } else { attr(modules, "teal_bookmarkable", exact = TRUE) diff --git a/R/reporter_previewer_module.R b/R/reporter_previewer_module.R index 19b707b34f..bd9689ed76 100644 --- a/R/reporter_previewer_module.R +++ b/R/reporter_previewer_module.R @@ -42,7 +42,7 @@ reporter_previewer_module <- function(label = "Report previewer", server_args = # Module is created with a placeholder label and the label is changed later. # This is to prevent another module being labeled "Report previewer". class(module) <- c(class(module), "teal_module_previewer") - module$label <- label + attr(module, "label") <- label attr(module, "teal_bookmarkable") <- TRUE module } diff --git a/R/teal_transform_module.R b/R/teal_transform_module.R index b4a6a9deda..9f9394bdc0 100644 --- a/R/teal_transform_module.R +++ b/R/teal_transform_module.R @@ -219,8 +219,8 @@ make_teal_transform_server <- function(expr) { #' @keywords internal extract_transformators <- function(modules) { if (inherits(modules, "teal_module")) { - modules$transformators + attr(modules, "transformators") } else if (inherits(modules, "teal_modules")) { - lapply(modules$children, extract_transformators) + lapply(modules, extract_transformators) } } diff --git a/R/utils.R b/R/utils.R index 5bd81b7a28..fcedc040bb 100644 --- a/R/utils.R +++ b/R/utils.R @@ -212,14 +212,14 @@ check_modules_datanames_recursive <- function(modules, datanames) { # nolint: ob checkmate::assert_character(datanames) if (inherits(modules, "teal_modules")) { unlist( - lapply(modules$children, check_modules_datanames_recursive, datanames = datanames), + lapply(modules, check_modules_datanames_recursive, datanames = datanames), recursive = FALSE ) } else { - missing_datanames <- setdiff(modules$datanames, c("all", datanames)) + missing_datanames <- setdiff(attr(modules, "datanames"), c("all", datanames)) if (length(missing_datanames)) { list(list( - label = modules$label, + label = attr(modules, "label"), missing_datanames = missing_datanames )) } diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index b4eced1301..b713364b79 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -1028,7 +1028,7 @@ testthat::describe("srv_teal teal_modules", { expr = { session$setInputs(`teal_modules-active_tab` = "module_1") testthat::expect_identical( - modules$children$module_1$server_args, + modules$module_1$server_args, list(x = 1L, y = 2L) ) } From 46b23eb6aa8f50aeebcab81d5b6f54918e23570c Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:44:13 +0000 Subject: [PATCH 3/3] [skip roxygen] [skip vbump] Roxygen Man Pages Auto Update --- man/module_teal_module.Rd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/man/module_teal_module.Rd b/man/module_teal_module.Rd index bc46f86c61..b3d5ea4c2d 100644 --- a/man/module_teal_module.Rd +++ b/man/module_teal_module.Rd @@ -25,6 +25,7 @@ srv_teal_module( data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), @@ -36,6 +37,7 @@ srv_teal_module( data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), @@ -47,6 +49,7 @@ srv_teal_module( data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"), @@ -58,6 +61,7 @@ srv_teal_module( data_rv, modules, datasets = NULL, + inherited_datanames = "all", slices_global, reporter = teal.reporter::Reporter$new(), data_load_status = reactive("ok"),