Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
133d6f7
module_bookmark_manager tests
m7pr Nov 6, 2025
9d9480b
Delete tests/testthat/test-module_bookmark_manager.R
m7pr Nov 6, 2025
0e628aa
more tests for snapshot manager and bookmark manager
m7pr Nov 6, 2025
5c559e2
remove skip
m7pr Nov 6, 2025
71a458e
ignore R/zzz.R
m7pr Nov 6, 2025
f62099e
tests for zzz.R
m7pr Nov 6, 2025
8053af7
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 6, 2025
99381fb
bring back tests for z zz.R
m7pr Nov 6, 2025
d638012
Merge branch 'covr' of https://github.com/insightsengineering/teal in…
m7pr Nov 6, 2025
cde50df
extend bookmarking tests
m7pr Nov 6, 2025
e306059
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 6, 2025
0df407d
add test-validations for validate_* functions
m7pr Nov 7, 2025
54f20ce
add tests for deprecated functions validation
m7pr Nov 7, 2025
06897df
tests for report_previewer_module
m7pr Nov 7, 2025
c008a08
delete test for deprecated funcionts
m7pr Nov 7, 2025
ff8d146
ignore coverage of deprecated files
m7pr Nov 7, 2025
db4bbd6
Merge branch 'covr' of https://github.com/insightsengineering/teal in…
m7pr Nov 7, 2025
2b9ccdb
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 7, 2025
a6c74f8
teal_data_module tests
m7pr Nov 7, 2025
57da7ec
Merge branch 'covr' of https://github.com/insightsengineering/teal in…
m7pr Nov 7, 2025
2c8aab8
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 7, 2025
084482e
test-reporter_previewer_module.R
m7pr Nov 7, 2025
0dd71fb
Merge branch 'covr' of https://github.com/insightsengineering/teal in…
m7pr Nov 7, 2025
3e55ac8
remove bookmarking tests. mark places for TODO
m7pr Nov 7, 2025
176d8aa
comment out fishy AI tests
m7pr Nov 7, 2025
408e990
uncomment 3 tests
m7pr Nov 7, 2025
b160fa3
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 7, 2025
74a2709
rewrite 2 tests so they expect a specific log message
m7pr Nov 7, 2025
89faa70
Merge branch 'covr' of https://github.com/insightsengineering/teal in…
m7pr Nov 7, 2025
6031170
[skip style] [skip vbump] Restyle files
github-actions[bot] Nov 7, 2025
21afa04
cover snapshot manager
gogonzo Nov 10, 2025
88fe006
remove redundant code
gogonzo Nov 10, 2025
35781ac
increase coverage
gogonzo Nov 11, 2025
d5f0305
isn't used in NEST repo
gogonzo Nov 11, 2025
9e674a7
add more coverage in the filter_manager
gogonzo Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .covrignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
R/module_teal_with_splash.R
R/tdata.R
R/landing_popup_module.R
R/show_rcode_modal.R
Comment on lines +1 to +4
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those files have functions deprecated in 0.16.0. We discussed with gogonzo, that those files could be deleted and functions could be removed as we had a MAJOR release to 1.0.0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice finding. Should we do that here? Or you want a different PR for this code to be removed on 1.1.0 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llrs-roche unsure yet. Maybe we can discuss today during the standup

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, because to reach 80% of coverage is not a hard requirement, I would not ignore the files. I think for the matter of the 80% coverage issue, the task is done, even if the CI report does not have >80% of coverage if we do not ignore the files. We can prove in a screenshot or comment that by ignoring those files we reach 80% of coverage.
Then, on a separate issue and PR, we remove the deprecated functions as it was already announced to users. The same actions are applicable to other packages, like teal.widgets, where deprecated functions alter the count of coverage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand. Lets talk during the standup. And my vote would be to remove those files from the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Marcin. They are not used or needed, so let's remove the dead code. But let's talk now about this

2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ Collate:
'module_snapshot_manager.R'
'module_source_code.R'
'module_teal.R'
'module_teal_data.R'
'module_teal_lockfile.R'
'module_teal_reporter.R'
'module_teal_with_splash.R'
'module_transform_data.R'
'module_validate_error.R'
'reporter_previewer_module.R'
'show_rcode_modal.R'
'tdata.R'
Expand Down
113 changes: 1 addition & 112 deletions R/module_bookmark_manager.R
Original file line number Diff line number Diff line change
Expand Up @@ -189,128 +189,17 @@ need_bookmarking <- function(modules) {
#' @keywords internal
#'
restoreValue <- function(value, default) { # nolint: object_name.
checkmate::assert_character("value")
checkmate::assert_character(value)
session_default <- shiny::getDefaultReactiveDomain()
session_parent <- .subset2(session_default, "parent")
session <- if (is.null(session_parent)) session_default else session_parent

if (isTRUE(session$restoreContext$active) && exists(value, session$restoreContext$values, inherits = FALSE)) {
session$restoreContext$values[[value]]
} else {
default
}
}

#' Compare bookmarks.
#'
#' Test if two bookmarks store identical state.
#'
#' `input` environments are compared one variable at a time and if not identical,
#' values in both bookmarks are reported. States of `datatable`s are stripped
#' of the `time` element before comparing because the time stamp is always different.
#' The contents themselves are not printed as they are large and the contents are not informative.
#' Elements present in one bookmark and absent in the other are also reported.
#' Differences are printed as messages.
#'
#' `values` environments are compared with `all.equal`.
#'
#' @section How to use:
#' Open an application, change relevant inputs (typically, all of them), and create a bookmark.
#' Then open that bookmark and immediately create a bookmark of that.
#' If restoring bookmarks occurred properly, the two bookmarks should store the same state.
#'
#'
#' @param book1,book2 bookmark directories stored in `shiny_bookmarks/`;
#' default to the two most recently modified directories
#'
#' @return
#' Invisible `NULL` if bookmarks are identical or if there are no bookmarks to test.
#' `FALSE` if inconsistencies are detected.
#'
#' @keywords internal
#'
bookmarks_identical <- function(book1, book2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!dir.exists("shiny_bookmarks")) {
message("no bookmark directory")
return(invisible(NULL))
}

ans <- TRUE

if (missing(book1) && missing(book2)) {
dirs <- list.dirs("shiny_bookmarks", recursive = FALSE)
bookmarks_sorted <- basename(rev(dirs[order(file.mtime(dirs))]))
if (length(bookmarks_sorted) < 2L) {
message("no bookmarks to compare")
return(invisible(NULL))
}
book1 <- bookmarks_sorted[2L]
book2 <- bookmarks_sorted[1L]
} else {
if (!dir.exists(file.path("shiny_bookmarks", book1))) stop(book1, " not found")
if (!dir.exists(file.path("shiny_bookmarks", book2))) stop(book2, " not found")
}

book1_input <- readRDS(file.path("shiny_bookmarks", book1, "input.rds"))
book2_input <- readRDS(file.path("shiny_bookmarks", book2, "input.rds"))

elements_common <- intersect(names(book1_input), names(book2_input))
dt_states <- grepl("_state$", elements_common)
if (any(dt_states)) {
for (el in elements_common[dt_states]) {
book1_input[[el]][["time"]] <- NULL
book2_input[[el]][["time"]] <- NULL
}
}

identicals <- mapply(identical, book1_input[elements_common], book2_input[elements_common])
non_identicals <- names(identicals[!identicals])
compares <- sprintf("$ %s:\t%s --- %s", non_identicals, book1_input[non_identicals], book2_input[non_identicals])
if (length(compares) != 0L) {
message("common elements not identical: \n", paste(compares, collapse = "\n"))
ans <- FALSE
}

elements_boook1 <- setdiff(names(book1_input), names(book2_input))
if (length(elements_boook1) != 0L) {
dt_states <- grepl("_state$", elements_boook1)
if (any(dt_states)) {
for (el in elements_boook1[dt_states]) {
if (is.list(book1_input[[el]])) book1_input[[el]] <- "--- data table state ---"
}
}
excess1 <- sprintf("$ %s:\t%s", elements_boook1, book1_input[elements_boook1])
message("elements only in book1: \n", paste(excess1, collapse = "\n"))
ans <- FALSE
}

elements_boook2 <- setdiff(names(book2_input), names(book1_input))
if (length(elements_boook2) != 0L) {
dt_states <- grepl("_state$", elements_boook1)
if (any(dt_states)) {
for (el in elements_boook1[dt_states]) {
if (is.list(book2_input[[el]])) book2_input[[el]] <- "--- data table state ---"
}
}
excess2 <- sprintf("$ %s:\t%s", elements_boook2, book2_input[elements_boook2])
message("elements only in book2: \n", paste(excess2, collapse = "\n"))
ans <- FALSE
}

book1_values <- readRDS(file.path("shiny_bookmarks", book1, "values.rds"))
book2_values <- readRDS(file.path("shiny_bookmarks", book2, "values.rds"))

if (!isTRUE(all.equal(book1_values, book2_values))) {
message("different values detected")
message("choices for numeric filters MAY be different, see RangeFilterState$set_choices")
ans <- FALSE
}

if (ans) message("perfect!")
invisible(NULL)
}


# Replacement for [base::rapply] which doesn't handle NULL values - skips the evaluation
# of the function and returns NULL for given element.
rapply2 <- function(x, f) {
Expand Down
26 changes: 0 additions & 26 deletions R/module_filter_manager.R
Original file line number Diff line number Diff line change
Expand Up @@ -286,32 +286,6 @@ methods::setOldClass("reactivevalues")
invisible(.self)
})
},
slices_deactivate_all = function(module_label) {
Copy link
Contributor

@gogonzo gogonzo Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed as this method (in private class) is never used in whole NEST project. Please

shiny::isolate({
new_slices <- .self$all_slices()
old_mapping <- attr(new_slices, "mapping")

new_mapping <- if (.self$is_module_specific()) {
new_module_mapping <- setNames(nm = module_label, list(character(0)))
modifyList(old_mapping, new_module_mapping)
} else if (missing(module_label)) {
lapply(
attr(.self$all_slices(), "mapping"),
function(x) character(0)
)
} else {
old_mapping[[module_label]] <- character(0)
old_mapping
}

if (!identical(new_mapping, old_mapping)) {
logger::log_debug(".slicesGlobal@slices_deactivate_all: deactivating all slices.")
attr(new_slices, "mapping") <- new_mapping
.self$all_slices(new_slices)
}
invisible(.self)
})
},
slices_active = function(mapping_elem) {
shiny::isolate({
if (.self$is_module_specific()) {
Expand Down
1 change: 0 additions & 1 deletion R/module_init_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#' lies in data control: the first method involves external control, while the second method
#' involves control from a custom module within the app.
#'
#' For more details, see [`module_teal_data`].
#'
#' @inheritParams module_teal
#'
Expand Down
3 changes: 2 additions & 1 deletion R/module_snapshot_manager.R
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ srv_snapshot_manager_panel <- function(id, slices_global) {
)
)
})
srv_snapshot_manager("module", slices_global = slices_global)
snapshot_history <- srv_snapshot_manager("module", slices_global = slices_global)
snapshot_history
})
}

Expand Down
6 changes: 4 additions & 2 deletions R/module_transform_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
#' Module calls [teal_transform_module()] in sequence so that `reactive teal_data` output
#' from one module is handed over to the following module's input.
#'
#' @inheritParams module_teal_data
#' @inheritParams module_validate_error
#' @inheritParams teal_modules
#' @param class (character(1)) CSS class to be added in the `div` wrapper tag.

#' @param is_transform_failed (`reactiveValues`) contains `logical` flags named after each transformator.
#' Help to determine if any previous transformator failed, so that following transformators can be disabled
#' and display a generic failure message.
#' @return `reactive` `teal_data`
#'
#' @name module_transform_data
Expand Down
129 changes: 8 additions & 121 deletions R/module_teal_data.R → R/module_validate_error.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,140 +21,24 @@
#' (except error 1).
#'
#' @inheritParams module_teal
#' @param data_module (`teal_data_module`)
#' @param modules (`teal_modules` or `teal_module`) For `datanames` validation purpose
#' @param validate_shiny_silent_error (`logical`) If `TRUE`, then `shiny.silent.error` is validated and
#' @param is_transform_failed (`reactiveValues`) contains `logical` flags named after each transformator.
#' Help to determine if any previous transformator failed, so that following transformators can be disabled
#' and display a generic failure message.
#'
#' @return `reactive` `teal_data`
#'
#' @rdname module_teal_data
#' @name module_teal_data
#' @rdname module_validate_error
#' @name module_validate_error
#' @keywords internal
NULL

#' @rdname module_teal_data
#' @aliases ui_teal_data
#' @note
#' `ui_teal_data_module` was renamed from `ui_teal_data`.
ui_teal_data_module <- function(id, data_module = function(id) NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkmate::assert_string(id)
checkmate::assert_function(data_module, args = "id")
ns <- NS(id)

shiny::tagList(
tags$div(id = ns("wrapper"), data_module(id = ns("data"))),
ui_validate_reactive_teal_data(ns("validate"))
)
}

#' @rdname module_teal_data
#' @aliases srv_teal_data
#' @note
#' `srv_teal_data_module` was renamed from `srv_teal_data`.
srv_teal_data_module <- function(id,
data_module = function(id) NULL,
modules = NULL,
validate_shiny_silent_error = TRUE,
is_transform_failed = reactiveValues()) {
checkmate::assert_string(id)
checkmate::assert_function(data_module, args = "id")
checkmate::assert_multi_class(modules, c("teal_modules", "teal_module"), null.ok = TRUE)
checkmate::assert_class(is_transform_failed, "reactivevalues")

moduleServer(id, function(input, output, session) {
logger::log_debug("srv_teal_data_module initializing.")
is_transform_failed[[id]] <- FALSE
module_out <- data_module(id = "data")
try_module_out <- reactive(tryCatch(module_out(), error = function(e) e))
observeEvent(try_module_out(), {
if (!inherits(try_module_out(), "teal_data")) {
is_transform_failed[[id]] <- TRUE
} else {
is_transform_failed[[id]] <- FALSE
}
})

is_previous_failed <- reactive({
idx_this <- which(names(is_transform_failed) == id)
is_transform_failed_list <- reactiveValuesToList(is_transform_failed)
idx_failures <- which(unlist(is_transform_failed_list))
any(idx_failures < idx_this)
})

observeEvent(is_previous_failed(), {
if (is_previous_failed()) {
shinyjs::disable("wrapper")
} else {
shinyjs::enable("wrapper")
}
})

srv_validate_reactive_teal_data(
"validate",
data = try_module_out,
modules = modules,
validate_shiny_silent_error = validate_shiny_silent_error,
hide_validation_error = is_previous_failed
)
})
}

#' @rdname module_teal_data
ui_validate_reactive_teal_data <- function(id) {
ns <- NS(id)
tags$div(
div(
id = ns("validate_messages"),
class = "teal_validated",
ui_validate_error(ns("silent_error")),
ui_check_class_teal_data(ns("class_teal_data")),
ui_check_module_datanames(ns("shiny_warnings"))
),
div(
class = "teal_validated",
uiOutput(ns("previous_failed"))
)
)
}

#' @rdname module_teal_data
srv_validate_reactive_teal_data <- function(id, # nolint: object_length
data,
modules = NULL,
validate_shiny_silent_error = FALSE,
hide_validation_error = reactive(FALSE)) {
checkmate::assert_string(id)
checkmate::assert_multi_class(modules, c("teal_modules", "teal_module"), null.ok = TRUE)
checkmate::assert_flag(validate_shiny_silent_error)

moduleServer(id, function(input, output, session) {
# there is an empty reactive cycle on `init` and `data` has `shiny.silent.error` class
srv_validate_error("silent_error", data, validate_shiny_silent_error)
srv_check_class_teal_data("class_teal_data", data)
srv_check_module_datanames("shiny_warnings", data, modules)
output$previous_failed <- renderUI({
if (hide_validation_error()) {
shinyjs::hide("validate_messages")
tags$div("One of previous transformators failed. Please check its inputs.", class = "teal-output-warning")
} else {
shinyjs::show("validate_messages")
NULL
}
})

.trigger_on_success(data)
})
}

#' @rdname module_validate_error
#' @keywords internal
ui_validate_error <- function(id) {
ns <- NS(id)
uiOutput(ns("message"))
}

#' @rdname module_validate_error
#' @keywords internal
srv_validate_error <- function(id, data, validate_shiny_silent_error) {
checkmate::assert_string(id)
Expand Down Expand Up @@ -193,13 +77,14 @@ srv_validate_error <- function(id, data, validate_shiny_silent_error) {
})
}


#' @rdname module_validate_error
#' @keywords internal
ui_check_class_teal_data <- function(id) {
ns <- NS(id)
uiOutput(ns("message"))
}

#' @rdname module_validate_error
#' @keywords internal
srv_check_class_teal_data <- function(id, data) {
checkmate::assert_string(id)
Expand All @@ -215,12 +100,14 @@ srv_check_class_teal_data <- function(id, data) {
})
}

#' @rdname module_validate_error
#' @keywords internal
ui_check_module_datanames <- function(id) {
ns <- NS(id)
uiOutput(NS(id, "message"))
}

#' @rdname module_validate_error
#' @keywords internal
srv_check_module_datanames <- function(id, data, modules) {
checkmate::assert_string(id)
Expand Down
Loading
Loading