From 23e47b0a60647e247a9c6cc3d578f6f471b3c735 Mon Sep 17 00:00:00 2001 From: Dean Attali Date: Wed, 5 Jun 2024 22:31:16 -0400 Subject: [PATCH 1/5] ExtendedTask: add example to docs --- R/extended-task.R | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/R/extended-task.R b/R/extended-task.R index 659a41f471..f03958d569 100644 --- a/R/extended-task.R +++ b/R/extended-task.R @@ -41,6 +41,45 @@ #' is, a function that quickly returns a promise) and allows even that very #' session to immediately unblock and carry on with other user interactions. #' +#' @examplesIf rlang::is_interactive() +#' +#' library(shiny) +#' library(bslib) +#' library(future) +#' plan(multisession) +#' +#' ui <- page_sidebar( +#' sidebar = sidebar( +#' input_task_button("recalc", "Recalculate") +#' ), +#' textOutput("outval") +#' ) +#' +#' server <- function(input, output) { +#' rand_task <- ExtendedTask$new(function() { +#' future({ +#' # Slow operation goes here +#' Sys.sleep(2) +#' runif(1) +#' }, seed = TRUE) +#' }) +#' +#' # Make button state reflect task. +#' # If using R >=4.1, you can do this instead: +#' # rand_task <- ExtendedTask$new(...) |> bind_task_button("recalc") +#' bind_task_button(rand_task, "recalc") +#' +#' observeEvent(input$recalc, { +#' rand_task$invoke() +#' }) +#' +#' output$outval <- renderText({ +#' rand_task$result() +#' }) +#' } +#' +#' shinyApp(ui, server) +#' #' @export ExtendedTask <- R6Class("ExtendedTask", portable = TRUE, cloneable = FALSE, public = list( From 36f67c296343b55825358813f74bb37d0151a274 Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Fri, 6 Dec 2024 14:01:58 -0500 Subject: [PATCH 2/5] chore: small edits to the example (also requires `future`) --- R/extended-task.R | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/R/extended-task.R b/R/extended-task.R index f03958d569..e29e78dafe 100644 --- a/R/extended-task.R +++ b/R/extended-task.R @@ -41,40 +41,49 @@ #' is, a function that quickly returns a promise) and allows even that very #' session to immediately unblock and carry on with other user interactions. #' -#' @examplesIf rlang::is_interactive() +#' @examplesIf rlang::is_interactive() && rlang::is_installed("future") #' #' library(shiny) #' library(bslib) #' library(future) #' plan(multisession) #' -#' ui <- page_sidebar( -#' sidebar = sidebar( -#' input_task_button("recalc", "Recalculate") +#' ui <- page_fluid( +#' titlePanel("Extended Task Demo"), +#' p( +#' 'Click the button below to perform a "calculation"', +#' "that takes a while to perform." #' ), -#' textOutput("outval") +#' input_task_button("recalculate", "Recalculate"), +#' p(textOutput("result")) #' ) #' #' server <- function(input, output) { #' rand_task <- ExtendedTask$new(function() { -#' future({ -#' # Slow operation goes here -#' Sys.sleep(2) -#' runif(1) -#' }, seed = TRUE) +#' future( +#' { +#' # Slow operation goes here +#' Sys.sleep(2) +#' sample(1:100, 1) +#' }, +#' seed = TRUE +#' ) #' }) #' #' # Make button state reflect task. #' # If using R >=4.1, you can do this instead: -#' # rand_task <- ExtendedTask$new(...) |> bind_task_button("recalc") -#' bind_task_button(rand_task, "recalc") +#' # rand_task <- ExtendedTask$new(...) |> bind_task_button("recalculate") +#' bind_task_button(rand_task, "recalculate") #' -#' observeEvent(input$recalc, { +#' observeEvent(input$recalculate, { +#' # Invoke the extended in an observer #' rand_task$invoke() #' }) #' -#' output$outval <- renderText({ -#' rand_task$result() +#' output$result <- renderText({ +#' # React to updated results when the task completes +#' number <- rand_task$result() +#' paste0("Your number is ", number, ".") #' }) #' } #' From 3c5bb3619cbd7b49a2716d6c393e15bf35ee179c Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Fri, 6 Dec 2024 14:02:10 -0500 Subject: [PATCH 3/5] chore: document --- man/ExtendedTask.Rd | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/man/ExtendedTask.Rd b/man/ExtendedTask.Rd index 893017320b..ad2da1b1f1 100644 --- a/man/ExtendedTask.Rd +++ b/man/ExtendedTask.Rd @@ -45,6 +45,57 @@ is, a function that quickly returns a promise) and allows even that very session to immediately unblock and carry on with other user interactions. } +\examples{ +\dontshow{if (rlang::is_interactive() && rlang::is_installed("future")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} + +library(shiny) +library(bslib) +library(future) +plan(multisession) + +ui <- page_fluid( + titlePanel("Extended Task Demo"), + p( + 'Click the button below to perform a "calculation"', + "that takes a while to perform." + ), + input_task_button("recalculate", "Recalculate"), + p(textOutput("result")) +) + +server <- function(input, output) { + rand_task <- ExtendedTask$new(function() { + future( + { + # Slow operation goes here + Sys.sleep(2) + sample(1:100, 1) + }, + seed = TRUE + ) + }) + + # Make button state reflect task. + # If using R >=4.1, you can do this instead: + # rand_task <- ExtendedTask$new(...) |> bind_task_button("recalculate") + bind_task_button(rand_task, "recalculate") + + observeEvent(input$recalculate, { + # Invoke the extended in an observer + rand_task$invoke() + }) + + output$result <- renderText({ + # React to updated results when the task completes + number <- rand_task$result() + paste0("Your number is ", number, ".") + }) +} + +shinyApp(ui, server) + +\dontshow{\}) # examplesIf} +} \section{Methods}{ \subsection{Public methods}{ \itemize{ From 85cddeb6bbc987f49f00b12473dc61aa1490658c Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Fri, 6 Dec 2024 14:16:27 -0500 Subject: [PATCH 4/5] chore: docs again --- man/ExtendedTask.Rd | 1 - 1 file changed, 1 deletion(-) diff --git a/man/ExtendedTask.Rd b/man/ExtendedTask.Rd index ad2da1b1f1..ade5334bd8 100644 --- a/man/ExtendedTask.Rd +++ b/man/ExtendedTask.Rd @@ -93,7 +93,6 @@ server <- function(input, output) { } shinyApp(ui, server) - \dontshow{\}) # examplesIf} } \section{Methods}{ From 0de9a65bd7080b99d334500e041bf763ae0dcf15 Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Fri, 6 Dec 2024 14:23:21 -0500 Subject: [PATCH 5/5] chore: add news item --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 359deea445..6394c4dcd4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,8 @@ * Improve collection of deep stack traces (stack traces that are tracked across steps in an async promise chain) with `coro` async generators such as `elmer` chat streams. Previously, Shiny treated each iteration of an async generator as a distinct deep stack, leading to pathologically long stack traces; now, Shiny only keeps/prints unique deep stack trace, discarding duplicates. (#4156) +* Added an example to the `ExtendedTask` documentation. (@daattali #4087) + ## Bug fixes * Fixed a bug in `conditionalPanel()` that would cause the panel to repeatedly show/hide itself when the provided condition was not boolean. (@kamilzyla, #4127)