-
-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
1304 handover error@main #1341
1304 handover error@main #1341
Conversation
Signed-off-by: Vedha Viyash <[email protected]>
Co-authored-by: Marcin <[email protected]> Signed-off-by: Vedha Viyash <[email protected]>
Co-authored-by: Marcin <[email protected]> Signed-off-by: Vedha Viyash <[email protected]>
Co-authored-by: Marcin <[email protected]> Signed-off-by: Vedha Viyash <[email protected]>
This PR extends #1333 Starting a new PR against the feature branch in case my changes break pipelines. The current feature branch is green and working. The only thing we wanted to improve is the reduction of the repetitive code and inclusion of such code into modules. @gogonzo the last thing to discuss is whether we rename `srv_validate_teal_data` or `srv_validate_reactive_teal_data`. Maybe this discussion can be continued in here #1330 (comment) <details><summary>Tested with below code</summary> ```r pkgload::load_all("teal") # ░█──░█ ─█▀▀█ ░█─── ▀█▀ ░█▀▀▄ # ─░█░█─ ░█▄▄█ ░█─── ░█─ ░█─░█ # ──▀▄▀─ ░█─░█ ░█▄▄█ ▄█▄ ░█▄▄▀ # 1. Teal App with teal_data app <- init( data = teal_data(iris_raw = iris, mtcars = mtcars), modules = modules(example_module("Module 1"), example_module("Module 2")) ) shinyApp(app$ui, app$server) # 2. Teal App with teal_data_module app <- init( data = teal_data_module( ui = function(id) { actionButton(NS(id, "submit"), "Submit") }, server = function(id) { moduleServer(id, function(input, output, session) { eventReactive(input$submit, { teal_data(iris = iris, mtcars = mtcars) }) }) }, once = TRUE # also try once = FALSE ), modules = modules(example_module("Module 1"), example_module("Module 2")) ) shinyApp(app$ui, app$server) # 3. Teal Module with teal_data modules <- modules(example_module(), example_module("mtcars only", datanames = "mtcars")) ui <- fluidPage( "Custom UI", ui_teal(id = "teal_1", modules = modules), ui_teal(id = "teal_2", modules = modules) ) server <- function(input, output, session) { data <- teal_data(iris = iris, mtcars = mtcars) srv_teal(id = "teal_1", data = data, modules = modules) srv_teal(id = "teal_2", data = data, modules = modules) } shinyApp(ui, server) # 4. Teal Module with teal_data_module modules <- modules(example_module("Module 1"), example_module("Module 2")) data <- teal_data_module( ui = function(id) { actionButton(NS(id, "submit"), "Submit") }, server = function(id) { moduleServer(id, function(input, output, session) { eventReactive(input$submit, { teal_data(iris = iris, mtcars = mtcars) }) }) }, once = TRUE # also try once = FALSE ) ui <- fluidPage( "Custom UI", ui_teal(id = "teal1", data = data, modules = modules), ui_teal(id = "teal2", data = data, modules = modules) ) server <- function(input, output, session) { srv_teal(id = "teal1", data = data, modules = modules) srv_teal(id = "teal2", data = data, modules = modules) } shinyApp(ui, server) # 5. Teal Module with reactive(teal_data) modules <- modules(example_module("One"), example_module("Two")) ui <- fluidPage( selectInput("data", "Data", c("iris", "mtcars"), multiple = TRUE), ui_teal(id = "teal_1", modules = modules), ui_teal(id = "teal_2", modules = modules) ) server <- function(input, output, session) { data <- reactive({ req(input$data) within( teal_data(), { if ("iris" %in% selection) { iris <- iris } if ("mtcars" %in% selection) { mtcars <- mtcars } }, selection = input$data ) }) srv_teal(id = "teal_1", data = data, modules = modules) srv_teal(id = "teal_2", data = data, modules = modules) } shinyApp(ui, server) # ░█▀▀▀ ░█▀▀█ ░█▀▀█ ░█▀▀▀█ ░█▀▀█ # ░█▀▀▀ ░█▄▄▀ ░█▄▄▀ ░█──░█ ░█▄▄▀ # ░█▄▄▄ ░█─░█ ░█─░█ ░█▄▄▄█ ░█─░█ # 1. Teal App with teal_data app <- init( data = within(teal_data(), { stop("error") }), modules = modules(example_module("Module 1"), example_module("Module 2")) ) app <- init( data = teal_data(), modules = modules(example_module("Module 1"), example_module("Module 2")) ) # 2. Teal App with teal_data_module app <- init( data = teal_data_module( ui = function(id) { actionButton(NS(id, "submit"), "Submit") }, server = function(id) { moduleServer(id, function(input, output, session) { eventReactive(input$submit, { within( teal_data(), { iris <- head(iris, count) if (count %% 2 != 0) { stop("error") } mtcars <- mtcars }, count = input$submit ) }) }) }, once = FALSE ), modules = modules(example_module("Module 1"), example_module("Module 2")) ) shinyApp(app$ui, app$server) # 3. Teal Module with teal_data modules <- modules(example_module(), example_module("mtcars only", datanames = "mtcars")) ui <- fluidPage( "Custom UI", ui_teal(id = "teal_1", modules = modules), ui_teal(id = "teal_2", modules = modules) ) server <- function(input, output, session) { data <- teal_data(iris = iris, mtcars = mtcars) srv_teal( id = "teal_1", data = within(teal_data(), { stop("error") }), modules = modules ) srv_teal( id = "teal_2", data = within(teal_data(), { stop("error") }), modules = modules ) } shinyApp(ui, server) # 4. Teal Module with teal_data_module modules <- modules(example_module("Module 1"), example_module("Module 2")) data <- teal_data_module( ui = function(id) { actionButton(NS(id, "submit"), "Submit") }, server = function(id) { moduleServer(id, function(input, output, session) { eventReactive(input$submit, { within( teal_data(), { iris <- head(iris, count) if (count %% 2 != 0) { stop("error") } mtcars <- mtcars }, count = input$submit ) }) }) }, once = F ) ui <- fluidPage( "Custom UI", ui_teal(id = "teal", data = data, modules = modules) ) server <- function(input, output, session) { srv_teal(id = "teal", data = data, modules = modules) } shinyApp(ui, server) # 4. Teal Module with teal_data_module - DELEGATE THE DATANAMES VALIDATION AFTER TEAL TRANSFORM modules <- modules(example_module(datanames = "CO2"), example_module("Module 2")) data <- teal_data_module( ui = function(id) { actionButton(NS(id, "submit"), "Submit") }, server = function(id) { moduleServer(id, function(input, output, session) { eventReactive(input$submit, { within( teal_data(), { if (count %% 2 != 0) { CO2 <- CO2 } iris <- head(iris, count) mtcars <- mtcars }, count = input$submit ) }) }) }, once = FALSE ) ui <- fluidPage( "Custom UI", ui_teal(id = "teal", data = data, modules = modules) ) server <- function(input, output, session) { srv_teal(id = "teal", data = data, modules = modules) } shinyApp(ui, server) # 5. Teal Module with reactive(teal_data) - Error is not observed modules <- modules(example_module("One"), example_module("Two")) ui <- fluidPage( selectInput("data", "Data", c("iris", "mtcars"), multiple = TRUE), ui_teal(id = "teal_1", modules = modules), ui_teal(id = "teal_2", modules = modules) ) server <- function(input, output, session) { data <- reactive({ within( teal_data(), { if ("iris" %in% selection) { iris <- iris } else { stop("No iris is an error!") } if ("mtcars" %in% selection) { mtcars <- mtcars } }, selection = input$data ) }) srv_teal(id = "teal_1", data = data, modules = modules) srv_teal(id = "teal_2", data = data, modules = modules) } shinyApp(ui, server) ``` </details> <details><summary>Results of local tests</summary> ```r > options(TESTING_DEPTH = 5) > devtools::test() ℹ Testing teal [INFO] 2024-09-02 12:59:39.2876 pid:23540 token:[] teal You are using teal version 0.15.2.9059 ✔ | F W S OK | Context ✔ | 11 | init [1.0s] ✔ | 6 126 | module_teal [44.0s] ✔ | 95 | modules ✔ | 7 | rcode_utils ✔ | 8 | report_previewer_module ✔ | 6 | shinytest2-data_summary [38.5s] ✔ | 5 | shinytest2-filter_panel [40.7s] ✔ | 17 | shinytest2-init [24.2s] ✔ | 11 | shinytest2-landing_popup [41.1s] ✔ | 4 | shinytest2-module_bookmark_manager [35.4s] ✔ | 5 | shinytest2-modules [38.8s] ✔ | 8 | shinytest2-reporter [72.1s] ✔ | 9 | shinytest2-show-rcode [9.7s] ✔ | 9 | shinytest2-teal_data_module [57.1s] ✔ | 18 | shinytest2-teal_slices [61.3s] ✔ | 4 | shinytest2-utils [9.6s] ✔ | 4 | shinytest2-wunder_bar [18.9s] ✔ | 16 | teal_data_module-eval_code ✔ | 4 | teal_data_module ✔ | 25 | teal_reporter ✔ | 15 | teal_slices-store ✔ | 18 | teal_slices ✔ | 36 | utils [7.4s] ✔ | 17 | validate_has_data ✔ | 36 | validate_inputs ══ Results ══════════════════════════════════════════════════════════════════════════════════════════════════════════════════ Duration: 502.8 s ── Skipped tests (6) ──────────────────────────────────────────────────────────────────────────────────────────────────────── • need a fix in a .slicesGlobal (1): test-module_teal.R:1178:11 • todo (5): test-module_teal.R:1443:7, test-module_teal.R:1450:5, test-module_teal.R:1453:5, test-module_teal.R:1709:5, test-module_teal.R:1715:5 [ FAIL 0 | WARN 0 | SKIP 6 | PASS 514 ] ``` </details> --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Unit Tests Summary 1 files 25 suites 8m 33s ⏱️ Results for commit 9c1b9d6. ♻️ This comment has been updated with latest results. |
Unit Test Performance Difference
Additional test case details
Results for commit fe50356 ♻️ This comment has been updated with latest results. |
I can see the warnings. Did you click the button?
Please clarify, I don't understand. |
I did : P I don't see them
I only see a notification in the bottom right corner, but not a warning on the top left part of the app (in case of teal_data_module) and no warning inside transformer UI (in case for teal_transform_module). |
This is a warning for filters which are not applied ( |
… or not remove unnecessary
Signed-off-by: Marcin <[email protected]>
Signed-off-by: Marcin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work 💪🏽 The error handling is robust and I really like the clear distinction between the init data and data during transform.
The data_load_status
for init data and is_transformer_failed
for data transforms a good way to manage what is happening.
The show/disable/hide logic living inside nested tabs makes sense 👍🏽
I just have minor comments and we can merge this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works like a charm 🎉
🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 🔥 |
Alternative solution to #1330. Closes #1304, #1307, and #1308
The most important part of the implementation is that when teal_data_module fails then it return the previous valid data (i.e. it return unchanged data). This means that failure doesn't trigger downstream reactivity and we don't need to deal with
data
input as error. In other words, this implementation halts reactivity when something goes wrong.When something goes wrong, teal-module-output is hidden and instead error message is displayed.
Also, I've moved
data
completely away fromui
and now if there isteal_data_module
then data-tab is added dynamically.app w/ teal_data_module
app wrapped