Skip to content
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

Closes #242 #241

Merged
merged 8 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
5 changes: 5 additions & 0 deletions inst/WORDLIST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1121,3 +1121,8 @@ laura
MeetLaura
needleman
WEL
Parmar
RMarkdown
roxy
roxygen
Voilà
73 changes: 73 additions & 0 deletions posts/zzz_DO_NOT_EDIT_roxy.shinyl.../appendix.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
suppressMessages(library(dplyr))
# markdown helpers --------------------------------------------------------

markdown_appendix <- function(name, content) {
paste(paste("##", name, "{.appendix}"), " ", content, sep = "\n")
}
markdown_link <- function(text, path) {
paste0("[", text, "](", path, ")")
}



# worker functions --------------------------------------------------------

insert_source <- function(repo_spec, name,
collection = "posts",
branch = "main",
host = "https://github.com",
text = "Source",
file_name) {
path <- paste(
host,
repo_spec,
"tree",
branch,
collection,
name,
file_name,
sep = "/"
)
return(markdown_link(text, path))
}

insert_timestamp <- function(tzone = Sys.timezone()) {
time <- lubridate::now(tzone = tzone)
stamp <- as.character(time, tz = tzone, usetz = TRUE)
return(stamp)
}

insert_lockfile <- function(repo_spec, name,
collection = "posts",
branch = "main",
host = "https://github.com",
text = "Session info") {
path <- path <- "https://pharmaverse.github.io/blog/session_info.html"

return(markdown_link(text, path))
}



# top level function ------------------------------------------------------

insert_appendix <- function(repo_spec, name, collection = "posts", file_name) {
appendices <- paste(
markdown_appendix(
name = "Last updated",
content = insert_timestamp()
),
" ",
markdown_appendix(
name = "Details",
content = paste(
insert_source(repo_spec, name, collection, file_name = file_name),
# get renv information,
insert_lockfile(repo_spec, name, collection),
sep = ", "
)
),
sep = "\n"
)
knitr::asis_output(appendices)
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: "roxy.shinylive - shinylive applications in roxygen documentation"
author:
- name: Pawel Rucki
description: "Introducing a `roxy.shinylive` - a new tool for Shiny package developers"
# Note that the date below will be auto-updated when the post is merged.
date: "2024-10-07"
# Please do not use any non-default categories.
# You can find the default categories in the repository README.md
categories: [Shiny, Technical]
# Feel free to change the image
image: "roxy.shinylive.gif"

---

<!--------------- typical setup ----------------->

```{r setup, include=FALSE}
long_slug <- "zzz_DO_NOT_EDIT_roxy.shinyl..."
# renv::use(lockfile = "renv.lock")
```

<!--------------- post begins here ----------------->

![](roxy.shinylive.gif)

Continuing my exploration of WebR (see my previous post [here](https://pharmaverse.github.io/blog/posts/2024-05-08_tlg_catalog_webr/tlg_catalog_webr.html)), I'm happy to introduce a new tool for Shiny package developers - [`roxy.shinylive`](https://insightsengineering.github.io/roxy.shinylive/). The package is designed for anyone building their Shiny applications or modules as an R package. With just a few lines of code, you can easily embed an `iframe` to a Shinylive application based on the code from the "Examples" section of your documentation.

Typically, you might have something like this:
```{r}
#| eval: false
#' This is a super app constructor.
#' @param ... something
#' @return shiny app object
#' @examples
#' if (interactive()) {
#' my_super_app()
#' }
my_super_app <- function(...) {
...
shiny::shinyApp(...)
}
```

Now, let's use `@examplesShinyLive` tag and make small adjustments to the example code to make it work in Shinylive:
```{r}
#| eval: false
#' @examplesShinyLive
#' library(mypackage)
#' interactive <- function() TRUE
#' {{ next_example }}
#' @examples
#' (...)
```

Voilà! Now your documentation includes Shinylive app! As a result, the end-users are able to see your application in action without needing to install anything. This makes your package more accessible and closer to the end-users.

In addition, the package exports `create_shinylive_url()` function, which creates an URL based on the application code as a string. This opens up more possibilities, such as embedding application(s) in README files, vignettes or even outside of package documentation. Combined with `knitr::knit_code$get("<chunk id>")` and `knitr::include_url()`, you can reuse other chunk(s) code to embed `iframe`s in RMarkdown or Quarto documents.

For a practical example of implementation, please see the documentation of [`teal.modules.general`](https://insightsengineering.github.io/teal.modules.general/main/) or [`teal.modules.clinical`](https://insightsengineering.github.io/teal.modules.clinical/main/) packages with more to come.
pawelru marked this conversation as resolved.
Show resolved Hide resolved

Special thanks to Sam Parmar from Pfizer - the author of the [`lzstring`](https://parmsam.github.io/lzstring-r/) package, which makes encoding / decoding possible. Yet another example of cross-pharma collaboration!

PS. Yes - it's coming to CRAN soon.

PS2. I've been also thinking about a similar solution for non-Shiny R codes. See [this](https://github.com/r-lib/pkgdown/issues/2348) and [this](https://github.com/r-wasm/webr/issues/356) issues for more updates.

I’d love for you to try out `roxy.shinylive` and see how it can enhance your Shiny package development workflow. Whether you have feedback, suggestions, or feature requests, please feel free to file an issue on the https://github.com/insightsengineering/roxy.shinylive, or join our [`pharmaverse` Slack channel](https://pharmaverse.slack.com/) to stay up to date and be part of the discussion.
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's really cool!
What would the placeholder for such an iframe be in the pdf version of the manual?
What does it look like when I look at the help page from the r console in rstudio, i.e. using ?function

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For pdf it would be just an empty space. It's in the docs here. If you are curious about implementation -> here

In the R console you can do the following:
? roxy.shinylive::create_shinylive_url -> it would open a manual of create_shinylive_url() which is also here
One can also do help("tag-examplesShinylive") to see this. I don't know how to open the latter via ? - that's why I encouraged the use of pkgdown help throughout the article.

I think I don't want to mention that here not to make it too detailed or become a technical writing. That's just to pitch an idea if you know what I mean


<!--------------- appendices go here ----------------->

```{r, echo=FALSE}
source("appendix.R")
insert_appendix(
repo_spec = "pharmaverse/blog",
name = long_slug,
# file_name should be the name of your file
file_name = list.files() %>% stringr::str_subset(".qmd") %>% first()
)
```
Loading