diff --git a/.Rbuildignore b/.Rbuildignore
index ae6b391f..20f43252 100755
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -7,3 +7,5 @@
^\.github$
^\.lintr$
^\.pre-commit-config\.yaml$
+^doc$
+^Meta$
diff --git a/.gitignore b/.gitignore
index cf066375..399bfa9d 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@
.Rhistory
docs
inst/doc
+/doc/
+/Meta/
diff --git a/DESCRIPTION b/DESCRIPTION
index a6d4a790..5b1cc68f 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -12,7 +12,10 @@ Imports:
checkmate,
grid,
R6,
- yaml
+ yaml,
+ shiny,
+ shinyWidgets,
+ zip
Suggests:
ggplot2,
knitr,
diff --git a/NAMESPACE b/NAMESPACE
index 0721d0a6..ff00728f 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -3,6 +3,12 @@
export(ReportCard)
export(Reporter)
export(TealReportCard)
+export(add_card_button_srv)
+export(add_card_button_ui)
+export(download_report_button_srv)
+export(download_report_button_ui)
+export(simple_reporter_srv)
+export(simple_reporter_ui)
importFrom(R6,R6Class)
importFrom(checkmate,assert_string)
importFrom(grid,grid.newpage)
diff --git a/R/AddCardModule.R b/R/AddCardModule.R
new file mode 100644
index 00000000..d1452020
--- /dev/null
+++ b/R/AddCardModule.R
@@ -0,0 +1,100 @@
+#' Add Card Button User Interface
+#' @description button for adding views/cards to the Report.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @return `shiny::tagList`
+#' @export
+add_card_button_ui <- function(id) {
+ ns <- shiny::NS(id)
+ shiny::tagList(
+ shiny::tags$button(
+ id = ns("add_report_card_button"),
+ type = "button",
+ class = "btn btn-primary action-button",
+ `data-val` = shiny::restoreInput(id = ns("add_report_card_button"), default = NULL),
+ NULL,
+ "Add Card"
+ )
+ )
+}
+
+#' Add Card Button Server
+#' @description server for adding views/cards to the Report.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @param reporter `Reporter` instance.
+#' @param card_fun `function` which returns a `ReportCard` instance,
+#' the function have at`card`argument and optional `comment`.
+#' @return `shiny::moduleServer`
+#' @export
+add_card_button_srv <- function(id, reporter, card_fun) {
+ checkmate::assert_function(card_fun)
+ checkmate::assert_class(reporter, "Reporter")
+ checkmate::assert_subset(names(formals(card_fun)), c("card", "comment"), empty.ok = FALSE)
+
+ shiny::moduleServer(
+ id,
+ function(input, output, session) {
+ ns <- session$ns
+ add_modal <- function(failed = FALSE) {
+ shiny::modalDialog(
+ easyClose = TRUE,
+ shiny::tags$h3("Add the Card to the Report"),
+ shiny::tags$hr(),
+ shiny::textInput(
+ ns("comment"),
+ "Comment",
+ value = "The idea behind",
+ width = "100%"
+ ),
+ if (failed) {
+ shiny::tags$div(
+ shiny::tags$b("Invalid", style = "color: red;")
+ )
+ },
+ footer = shiny::tagList(
+ shiny::tags$button(
+ type = "button",
+ class = "btn btn-primary",
+ `data-dismiss` = "modal",
+ `data-bs-dismiss` = "modal",
+ NULL,
+ "Cancel"
+ ),
+ shiny::tags$button(
+ id = ns("add_card_ok"),
+ type = "button",
+ class = "btn btn-primary action-button",
+ `data-val` = shiny::restoreInput(id = ns("add_card_ok"), default = NULL),
+ NULL,
+ "Add Card"
+ )
+ )
+ )
+ }
+
+ shiny::observeEvent(input$add_report_card_button, {
+ shiny::showModal(add_modal())
+ })
+
+ shiny::observeEvent(input$add_card_ok, {
+ card <- ReportCard$new()
+ card_fun_args_nams <- names(formals(card_fun))
+ if (length(card_fun_args_nams) == 1) {
+ card_fun(card)
+ if (length(input$comment) > 0 && input$comment != "") {
+ card$append_text("Comment", "header3")
+ card$append_text(input$comment)
+ }
+ } else {
+ card_fun(card, input$comment)
+ }
+ checkmate::assert_class(card, "ReportCard")
+ reporter$append_cards(list(card))
+ shiny::removeModal()
+ })
+ }
+ )
+}
diff --git a/R/ContentBlock.R b/R/ContentBlock.R
index 0b515f77..c8a07710 100644
--- a/R/ContentBlock.R
+++ b/R/ContentBlock.R
@@ -42,13 +42,13 @@ ContentBlock <- R6::R6Class( # nolint: object_name_linter.
private = list(
content = character(0),
- #' @description The copy constructor.
- #'
- #' @param name `character(1)` the name of the field
- #' @param value the value assigned to the field
- #'
- #' @return the value of the copied field
- #'
+ # @description The copy constructor.
+ #
+ # @param name `character(1)` the name of the field
+ # @param value the value assigned to the field
+ #
+ # @return the value of the copied field
+ #
deep_clone = function(name, value) {
if (name == "content" && checkmate::test_file_exists(value)) {
extension <- ""
diff --git a/R/DownloadModule.R b/R/DownloadModule.R
new file mode 100644
index 00000000..cd34772e
--- /dev/null
+++ b/R/DownloadModule.R
@@ -0,0 +1,197 @@
+#' Download Button Reporter User Interface
+#' @description button for downloading the Report.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @return `shiny::tagList`
+#' @export
+download_report_button_ui <- function(id) {
+ ns <- shiny::NS(id)
+ shiny::tagList(
+ shiny::tags$button(
+ id = ns("download_button"),
+ type = "button",
+ class = "btn btn-primary action-button",
+ `data-val` = shiny::restoreInput(id = ns("download_button"), default = NULL),
+ NULL,
+ "Download Report"
+ )
+ )
+}
+
+#' Download Button Server
+#' @description server for downloading the Report.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @param reporter `Reporter` instance.
+#' @param notification `logical` whether to add a shiny notification about the download process. Default `TRUE`.
+#' @param rmd_output `character` vector with `rmarkdown` output types,
+#' by default all possible `c("pdf_document", "html_document", "powerpoint_presentation", "word_document")`.
+#' @param rmd_yaml_args `named list` vector with `Rmd` `yaml` header fields and their default values.
+#' Default `list(author = "NEST", title = "Report", date = Sys.Date(), output = "html_document")`.
+#' Please update only values at this moment.
+#' @return `shiny::moduleServer`
+#' @export
+download_report_button_srv <- function(id,
+ reporter,
+ notification = TRUE,
+ rmd_output = c(
+ "html_document", "pdf_document",
+ "powerpoint_presentation", "word_document"
+ ),
+ rmd_yaml_args = list(
+ author = "NEST", title = "Report",
+ date = as.character(Sys.Date()), output = "html_document"
+ )) {
+ checkmate::assert_class(reporter, "Reporter")
+ checkmate::assert_flag(notification)
+ checkmate::assert_subset(rmd_output, c(
+ "html_document", "pdf_document",
+ "powerpoint_presentation", "word_document"
+ ))
+ checkmate::assert_list(rmd_yaml_args, names = "named")
+ checkmate::assert_true(all(c("author", "title", "date", "output") %in% names(rmd_yaml_args)))
+
+ shiny::moduleServer(
+ id,
+ function(input, output, session) {
+ ns <- session$ns
+ download_modal <- function(failed = FALSE) {
+ nr_cards <- length(reporter$get_cards())
+ downb <- shiny::tags$a(
+ id = ns("download_data"),
+ class = paste("btn btn-primary shiny-download-link", if (nr_cards) NULL else "disabled"),
+ style = if (nr_cards) NULL else "pointer-events: none;",
+ href = "",
+ target = "_blank",
+ download = NA,
+ shiny::icon("download"),
+ "Download Report"
+ )
+ shiny::modalDialog(
+ easyClose = TRUE,
+ shiny::tags$h3("Download the Report"),
+ shiny::tags$hr(),
+ if (length(reporter$get_cards()) == 0) {
+ shiny::tags$div(
+ shiny::tags$p(shiny::tags$strong("No Cards Added"), style = "color: red; margin-bottom:15px;")
+ )
+ } else {
+ shiny::tags$div(
+ style = "color: green; margin-bottom:15px;",
+ shiny::tags$p(
+ shiny::tags$strong(paste("Number of cards: ", nr_cards))
+ ),
+ )
+ },
+ shiny::textInput(ns("author"), label = "Author:", value = rmd_yaml_args$author),
+ shiny::textInput(ns("title"), label = "Title:", value = rmd_yaml_args$title),
+ shiny::dateInput(ns("date"), "Date:", value = rmd_yaml_args$date),
+ shiny::tags$div(
+ shinyWidgets::pickerInput(
+ inputId = ns("output"),
+ label = "Choose a document type: ",
+ choices = rmd_output,
+ selected = rmd_yaml_args$output
+ )
+ ),
+ if (failed) {
+ shiny::tags$div(shiny::tags$b("Invalid", style = "color: red;"))
+ },
+ footer = shiny::tagList(
+ shiny::tags$button(
+ id = ns("reset_reporter"),
+ type = "button",
+ style = "float: left;",
+ class = "btn btn-danger action-button",
+ `data-val` = shiny::restoreInput(id = ns("reset_reporter"), default = NULL),
+ NULL,
+ "Reset Reporter"
+ ),
+ shiny::tags$button(
+ type = "button",
+ class = "btn btn-primary",
+ `data-dismiss` = "modal",
+ `data-bs-dismiss` = "modal",
+ NULL,
+ "Cancel"
+ ),
+ downb
+ )
+ )
+ }
+
+ shiny::observeEvent(input$download_button, {
+ shiny::showModal(download_modal())
+ })
+
+ shiny::observeEvent(input$reset_reporter, {
+ shiny::showModal(
+ shiny::modalDialog(
+ shiny::tags$h3("Reset the Report"),
+ shiny::tags$hr(),
+ shiny::tags$strong(shiny::tags$p("Are you sure you want to reset the report?")),
+ footer = shiny::tagList(
+ shiny::modalButton("Cancel"),
+ shiny::actionButton(ns("reset_reporter_ok"), "Reset")
+ )
+ )
+ )
+ })
+
+ shiny::observeEvent(input$reset_reporter_ok, {
+ reporter$reset()
+ shiny::removeModal()
+ })
+
+ output$download_data <- shiny::downloadHandler(
+ filename = function() {
+ paste("report_", format(Sys.time(), "%y%m%d%H%M%S"), ".zip", sep = "")
+ },
+ content = function(file) {
+ if (notification) {
+ shiny::showNotification(sprintf("Rendering and Downloading a document."))
+ }
+ input_list <- lapply(names(rmd_yaml_args), function(x) input[[x]])
+ names(input_list) <- names(rmd_yaml_args)
+ report_render_and_compress(reporter, input_list, file)
+ },
+ contentType = "application/zip"
+ )
+ }
+ )
+}
+
+#' Render the Report
+#' @description render the report and zip the created directory.
+#' @param reporter `Reporter` instance.
+#' @param input `list` like shiny input converted to a regular list.
+#' @param file `character` where to copy the returned directory.
+#' @return `file` argument
+#' @keywords internal
+report_render_and_compress <- function(reporter, input, file = tempdir()) {
+ checkmate::assert_class(reporter, "Reporter")
+ checkmate::assert_list(input, names = "named")
+ checkmate::assert_string(file)
+
+ yaml <- list(
+ author = input$author,
+ title = input$title,
+ date = as.character(input$date)
+ )
+ if (!is.null(input$output)) {
+ yaml[["output"]] <- input$output
+ }
+ yaml_header <- md_header(yaml::as.yaml(yaml))
+
+ renderer <- Renderer$new()
+ renderer$render(reporter$get_blocks(), yaml_header)
+
+ temp_zip_file <- tempfile(fileext = ".zip")
+ zip::zipr(temp_zip_file, renderer$get_output_dir())
+ file.copy(temp_zip_file, file)
+
+ rm(renderer)
+ file
+}
diff --git a/R/Renderer.R b/R/Renderer.R
index 0631307a..5b1ee727 100644
--- a/R/Renderer.R
+++ b/R/Renderer.R
@@ -51,7 +51,7 @@ Renderer <- R6::R6Class( # nolint: object_name_linter.
#' author = teal.reporter:::yaml_quoted("NEST"),
#' title = teal.reporter:::yaml_quoted("Report"),
#' date = teal.reporter:::yaml_quoted("07/04/2019"),
- #' output = list(pdf_document = list(keep_tex = TRUE))
+ #' output = list(html_document = list(toc = FALSE))
#' )
#'
#' yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
@@ -103,7 +103,7 @@ Renderer <- R6::R6Class( # nolint: object_name_linter.
#' author = teal.reporter:::yaml_quoted("NEST"),
#' title = teal.reporter:::yaml_quoted("Report"),
#' date = teal.reporter:::yaml_quoted("07/04/2019"),
- #' output = list(pdf_document = list(keep_tex = TRUE))
+ #' output = list(html_document = list(toc = FALSE))
#' )
#'
#' yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
diff --git a/R/ReportCard.R b/R/ReportCard.R
index 84262ddf..935036b1 100644
--- a/R/ReportCard.R
+++ b/R/ReportCard.R
@@ -135,12 +135,12 @@ ReportCard <- R6::R6Class( # nolint: object_name_linter.
content = list(),
chr_converters = list(),
- #' @description The copy constructor.
- #'
- #' @param name the name of the field
- #' @param value the value of the field
- #' @return the new value of the field
- #'
+ # @description The copy constructor.
+ #
+ # @param name the name of the field
+ # @param value the value of the field
+ # @return the new value of the field
+ #
deep_clone = function(name, value) {
if (name == "content") {
lapply(value, function(content_block) {
diff --git a/R/Reporter.R b/R/Reporter.R
index 4ecbe5f8..ff260570 100644
--- a/R/Reporter.R
+++ b/R/Reporter.R
@@ -107,16 +107,24 @@ Reporter <- R6::R6Class( # nolint: object_name_linter.
blocks <- append(blocks, private$cards[[length(private$cards)]]$get_content())
}
blocks
+ },
+ #' @description Removes all `ReportCard` objects added to this `Reporter`.
+ #'
+ #' @return invisibly self
+ #'
+ reset = function() {
+ private$cards <- list()
+ invisible(self)
}
),
private = list(
cards = list(),
- #' @description The copy constructor.
- #'
- #' @param name the name of the field
- #' @param value the value of the field
- #' @return the new value of the field
- #'
+ # @description The copy constructor.
+ #
+ # @param name the name of the field
+ # @param value the value of the field
+ # @return the new value of the field
+ #
deep_clone = function(name, value) {
if (name == "cards") {
lapply(value, function(card) card$clone(deep = TRUE))
diff --git a/R/SimpleReporter.R b/R/SimpleReporter.R
new file mode 100644
index 00000000..824a0f3f
--- /dev/null
+++ b/R/SimpleReporter.R
@@ -0,0 +1,36 @@
+#' Simple Reporter User Interface
+#' @description two buttons for adding views and downloading the Report.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @return `shiny::tagList`
+#' @export
+simple_reporter_ui <- function(id) {
+ ns <- shiny::NS(id)
+ shiny::tagList(
+ add_card_button_ui(ns("add_report_card_simple")),
+ download_report_button_ui(ns("download_button_simple")),
+ )
+}
+
+#' Simple Reporter Server
+#' @description two buttons for adding views and downloading the Report.
+#' The add module has `add_report_card_simple` id and download module the `download_button_simple` id.
+#'
+#' For more details see the vignette: `vignette("simpleReporter", "teal.reporter")`.
+#' @param id `character`
+#' @param reporter `Reporter` instance.
+#' @param card_fun `function` which returns a `ReportCard` instance,
+#' the function have at`card`argument and optional `comment`.
+#' @param notification logical if to add shiny notification about the download process.
+#' @return `shiny::moduleServer`
+#' @export
+simple_reporter_srv <- function(id, reporter, card_fun, notification = TRUE) {
+ shiny::moduleServer(
+ id,
+ function(input, output, session) {
+ add_card_button_srv("add_report_card_simple", reporter = reporter, card_fun = card_fun)
+ download_report_button_srv("download_button_simple", reporter = reporter, notification = notification)
+ }
+ )
+}
diff --git a/man/Renderer.Rd b/man/Renderer.Rd
index 57d8fc35..8cc8eca4 100644
--- a/man/Renderer.Rd
+++ b/man/Renderer.Rd
@@ -44,7 +44,7 @@ yaml_l <- list(
author = teal.reporter:::yaml_quoted("NEST"),
title = teal.reporter:::yaml_quoted("Report"),
date = teal.reporter:::yaml_quoted("07/04/2019"),
- output = list(pdf_document = list(keep_tex = TRUE))
+ output = list(html_document = list(toc = FALSE))
)
yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
@@ -76,7 +76,7 @@ yaml_l <- list(
author = teal.reporter:::yaml_quoted("NEST"),
title = teal.reporter:::yaml_quoted("Report"),
date = teal.reporter:::yaml_quoted("07/04/2019"),
- output = list(pdf_document = list(keep_tex = TRUE))
+ output = list(html_document = list(toc = FALSE))
)
yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
@@ -183,7 +183,7 @@ yaml_l <- list(
author = teal.reporter:::yaml_quoted("NEST"),
title = teal.reporter:::yaml_quoted("Report"),
date = teal.reporter:::yaml_quoted("07/04/2019"),
- output = list(pdf_document = list(keep_tex = TRUE))
+ output = list(html_document = list(toc = FALSE))
)
yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
@@ -241,7 +241,7 @@ yaml_l <- list(
author = teal.reporter:::yaml_quoted("NEST"),
title = teal.reporter:::yaml_quoted("Report"),
date = teal.reporter:::yaml_quoted("07/04/2019"),
- output = list(pdf_document = list(keep_tex = TRUE))
+ output = list(html_document = list(toc = FALSE))
)
yaml_header <- teal.reporter:::md_header(yaml::as.yaml(yaml_l))
diff --git a/man/Reporter.Rd b/man/Reporter.Rd
index 325ed9a7..43aecb02 100644
--- a/man/Reporter.Rd
+++ b/man/Reporter.Rd
@@ -100,6 +100,7 @@ reporter$get_blocks()
\item \href{#method-append_cards}{\code{Reporter$append_cards()}}
\item \href{#method-get_cards}{\code{Reporter$get_cards()}}
\item \href{#method-get_blocks}{\code{Reporter$get_blocks()}}
+\item \href{#method-reset}{\code{Reporter$reset()}}
\item \href{#method-clone}{\code{Reporter$clone()}}
}
}
@@ -260,6 +261,19 @@ reporter$get_blocks()
}
+}
+\if{html}{\out{
}}
+\if{html}{\out{}}
+\if{latex}{\out{\hypertarget{method-reset}{}}}
+\subsection{Method \code{reset()}}{
+Removes all \code{ReportCard} objects added to this \code{Reporter}.
+\subsection{Usage}{
+\if{html}{\out{}}\preformatted{Reporter$reset()}\if{html}{\out{
}}
+}
+
+\subsection{Returns}{
+invisibly self
+}
}
\if{html}{\out{
}}
\if{html}{\out{}}
diff --git a/man/add_card_button_srv.Rd b/man/add_card_button_srv.Rd
new file mode 100644
index 00000000..fedec6b0
--- /dev/null
+++ b/man/add_card_button_srv.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/AddCardModule.R
+\name{add_card_button_srv}
+\alias{add_card_button_srv}
+\title{Add Card Button Server}
+\usage{
+add_card_button_srv(id, reporter, card_fun)
+}
+\arguments{
+\item{id}{\code{character}}
+
+\item{reporter}{\code{Reporter} instance.}
+
+\item{card_fun}{\code{function} which returns a \code{ReportCard} instance,
+the function have at\code{card}argument and optional \code{comment}.}
+}
+\value{
+\code{shiny::moduleServer}
+}
+\description{
+server for adding views/cards to the Report.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/man/add_card_button_ui.Rd b/man/add_card_button_ui.Rd
new file mode 100644
index 00000000..dcb88bb1
--- /dev/null
+++ b/man/add_card_button_ui.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/AddCardModule.R
+\name{add_card_button_ui}
+\alias{add_card_button_ui}
+\title{Add Card Button User Interface}
+\usage{
+add_card_button_ui(id)
+}
+\arguments{
+\item{id}{\code{character}}
+}
+\value{
+\code{shiny::tagList}
+}
+\description{
+button for adding views/cards to the Report.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/man/download_report_button_srv.Rd b/man/download_report_button_srv.Rd
new file mode 100644
index 00000000..80c38935
--- /dev/null
+++ b/man/download_report_button_srv.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/DownloadModule.R
+\name{download_report_button_srv}
+\alias{download_report_button_srv}
+\title{Download Button Server}
+\usage{
+download_report_button_srv(
+ id,
+ reporter,
+ notification = TRUE,
+ rmd_output = c("html_document", "pdf_document", "powerpoint_presentation",
+ "word_document"),
+ rmd_yaml_args = list(author = "NEST", title = "Report", date =
+ as.character(Sys.Date()), output = "html_document")
+)
+}
+\arguments{
+\item{id}{\code{character}}
+
+\item{reporter}{\code{Reporter} instance.}
+
+\item{notification}{\code{logical} whether to add a shiny notification about the download process. Default \code{TRUE}.}
+
+\item{rmd_output}{\code{character} vector with \code{rmarkdown} output types,
+by default all possible \code{c("pdf_document", "html_document", "powerpoint_presentation", "word_document")}.}
+
+\item{rmd_yaml_args}{\verb{named list} vector with \code{Rmd} \code{yaml} header fields and their default values.
+Default \code{list(author = "NEST", title = "Report", date = Sys.Date(), output = "html_document")}.
+Please update only values at this moment.}
+}
+\value{
+\code{shiny::moduleServer}
+}
+\description{
+server for downloading the Report.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/man/download_report_button_ui.Rd b/man/download_report_button_ui.Rd
new file mode 100644
index 00000000..e7419e2a
--- /dev/null
+++ b/man/download_report_button_ui.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/DownloadModule.R
+\name{download_report_button_ui}
+\alias{download_report_button_ui}
+\title{Download Button Reporter User Interface}
+\usage{
+download_report_button_ui(id)
+}
+\arguments{
+\item{id}{\code{character}}
+}
+\value{
+\code{shiny::tagList}
+}
+\description{
+button for downloading the Report.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/man/report_render_and_compress.Rd b/man/report_render_and_compress.Rd
new file mode 100644
index 00000000..574e74b4
--- /dev/null
+++ b/man/report_render_and_compress.Rd
@@ -0,0 +1,22 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/DownloadModule.R
+\name{report_render_and_compress}
+\alias{report_render_and_compress}
+\title{Render the Report}
+\usage{
+report_render_and_compress(reporter, input, file = tempdir())
+}
+\arguments{
+\item{reporter}{\code{Reporter} instance.}
+
+\item{input}{\code{list} like shiny input converted to a regular list.}
+
+\item{file}{\code{character} where to copy the returned directory.}
+}
+\value{
+\code{file} argument
+}
+\description{
+render the report and zip the created directory.
+}
+\keyword{internal}
diff --git a/man/simple_reporter_srv.Rd b/man/simple_reporter_srv.Rd
new file mode 100644
index 00000000..4bf73e97
--- /dev/null
+++ b/man/simple_reporter_srv.Rd
@@ -0,0 +1,27 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/SimpleReporter.R
+\name{simple_reporter_srv}
+\alias{simple_reporter_srv}
+\title{Simple Reporter Server}
+\usage{
+simple_reporter_srv(id, reporter, card_fun, notification = TRUE)
+}
+\arguments{
+\item{id}{\code{character}}
+
+\item{reporter}{\code{Reporter} instance.}
+
+\item{card_fun}{\code{function} which returns a \code{ReportCard} instance,
+the function have at\code{card}argument and optional \code{comment}.}
+
+\item{notification}{logical if to add shiny notification about the download process.}
+}
+\value{
+\code{shiny::moduleServer}
+}
+\description{
+two buttons for adding views and downloading the Report.
+The add module has \code{add_report_card_simple} id and download module the \code{download_button_simple} id.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/man/simple_reporter_ui.Rd b/man/simple_reporter_ui.Rd
new file mode 100644
index 00000000..0f268fe1
--- /dev/null
+++ b/man/simple_reporter_ui.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/SimpleReporter.R
+\name{simple_reporter_ui}
+\alias{simple_reporter_ui}
+\title{Simple Reporter User Interface}
+\usage{
+simple_reporter_ui(id)
+}
+\arguments{
+\item{id}{\code{character}}
+}
+\value{
+\code{shiny::tagList}
+}
+\description{
+two buttons for adding views and downloading the Report.
+
+For more details see the vignette: \code{vignette("simpleReporter", "teal.reporter")}.
+}
diff --git a/tests/testthat/test-DownloadReportModule.R b/tests/testthat/test-DownloadReportModule.R
new file mode 100644
index 00000000..25c7c625
--- /dev/null
+++ b/tests/testthat/test-DownloadReportModule.R
@@ -0,0 +1,97 @@
+card1 <- ReportCard$new()
+card1$append_text("Header 2 text", "header2")
+card1$append_text("A paragraph of default text", "header2")
+card1$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+)
+
+reporter <- Reporter$new()
+reporter$append_cards(list(card1))
+
+testthat::test_that("download_report_button_srv - render and downlaod a document", {
+ shiny::testServer(
+ download_report_button_srv,
+ args = list(reporter = reporter, notification = FALSE),
+ expr = {
+ session$setInputs(`download_button` = 0)
+ session$setInputs(`output` = "html_document")
+ session$setInputs(`title` = "TITLE")
+ session$setInputs(`author` = "AUTHOR")
+ session$setInputs(`download_data` = 0)
+
+ f <- output$download_data
+ testthat::expect_true(file.exists(f))
+ tmp_dir <- tempdir()
+ output_dir <- file.path(tmp_dir, sprintf("report_test_%s", gsub("[.]", "", format(Sys.time(), "%Y%m%d%H%M%OS4"))))
+ dir.create(path = output_dir)
+ zip::unzip(f, exdir = output_dir)
+ files <- list.files(output_dir, recursive = TRUE)
+ testthat::expect_true(any(grepl("[.]Rmd", files)))
+ testthat::expect_true(any(grepl("[.]html", files)))
+ }
+ )
+})
+
+card1 <- ReportCard$new()
+card1$append_text("Header 2 text", "header2")
+card1$append_text("A paragraph of default text", "header2")
+card1$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+)
+
+reporter <- Reporter$new()
+reporter$append_cards(list(card1))
+
+testthat::test_that("download_report_button_srv - reset a report", {
+ shiny::testServer(
+ download_report_button_srv,
+ args = list(reporter = reporter, notification = FALSE),
+ expr = {
+ testthat::expect_identical(reporter$get_cards(), list(card1))
+ session$setInputs(`reset_reporter` = 0)
+ session$setInputs(`reset_reporter_ok` = 0)
+ testthat::expect_identical(reporter$get_blocks(), list())
+ }
+ )
+})
+
+testthat::test_that("download_report_button_ui - returns a tagList", {
+ testthat::expect_true(
+ inherits(download_report_button_ui("sth"), c("shiny.tag.list", "list"))
+ )
+})
+
+card1 <- ReportCard$new()
+card1$append_text("Header 2 text", "header2")
+card1$append_text("A paragraph of default text", "header2")
+card1$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+)
+
+reporter <- Reporter$new()
+reporter$append_cards(list(card1))
+input <- list(author = "NEST", title = "Report", output = "html_document")
+temp_dir <- tempdir()
+
+testthat::test_that("report_render_and_compress - valid arguments", {
+ testthat::expect_error(report_render_and_compress(reporter, input, temp_dir), NA)
+})
+
+testthat::test_that("report_render_and_compress - invalid arguments", {
+ testthat::expect_error(report_render_and_compress(reporter, list(), temp_zip))
+ testthat::expect_error(report_render_and_compress(reporter, input, 2))
+ testthat::expect_error(report_render_and_compress(reporter, list, ""))
+})
+
+testthat::test_that("report_render_and_compress - render an html document", {
+ input <- list(author = "NEST", title = "Report", output = "html_document")
+ temp_dir <- tempdir()
+ res_path <- report_render_and_compress(reporter, input, temp_dir)
+ expect_identical(res_path, temp_dir)
+ files <- list.files(temp_dir, recursive = TRUE)
+ testthat::expect_true(any(grepl("[.]Rmd", files)))
+ testthat::expect_true(any(grepl("[.]html", files)))
+})
diff --git a/tests/testthat/test-SimpleReporter.R b/tests/testthat/test-SimpleReporter.R
new file mode 100644
index 00000000..a1485c7f
--- /dev/null
+++ b/tests/testthat/test-SimpleReporter.R
@@ -0,0 +1,93 @@
+card_fun0 <- function(card = ReportCard$new()) {
+ card$append_text("Header 2 text", "header2")
+ card$append_text("A paragraph of default text", "header2")
+ card$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+ )
+ card
+}
+
+
+reporter <- Reporter$new()
+reporter$append_cards(list(card_fun0()))
+
+testthat::test_that("simple_reporter_srv - render and downlaod a document", {
+ shiny::testServer(
+ simple_reporter_srv,
+ args = list(reporter = reporter, notification = FALSE, card_fun = card_fun0),
+ expr = {
+ session$setInputs(`download_button_simple` = 0)
+ session$setInputs(`download_button_simple-output` = "html_document")
+ session$setInputs(`download_button_simple-title` = "TITLE")
+ session$setInputs(`download_button_simple-author` = "AUTHOR")
+ session$setInputs(`download_button_simple-download_data` = 0)
+
+
+ f <- output$`download_button_simple-download_data`
+ testthat::expect_true(file.exists(f))
+ tmp_dir <- tempdir()
+ output_dir <- file.path(tmp_dir, sprintf("report_test_%s", gsub("[.]", "", format(Sys.time(), "%Y%m%d%H%M%OS4"))))
+ dir.create(path = output_dir)
+ zip::unzip(f, exdir = output_dir)
+ files <- list.files(output_dir, recursive = TRUE)
+ testthat::expect_true(any(grepl("[.]Rmd", files)))
+ testthat::expect_true(any(grepl("[.]html", files)))
+ }
+ )
+})
+
+card_fun <- function(card = ReportCard$new(), comment = NULL) {
+ card$append_text("Header 2 text", "header2")
+ card$append_text("A paragraph of default text", "header2")
+ card$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+ )
+ card
+}
+
+card1 <- card_fun()
+
+reporter <- Reporter$new()
+reporter$append_cards(list(card1))
+
+testthat::test_that("simple_reporter_srv - reset a reporter", {
+ shiny::testServer(
+ simple_reporter_srv,
+ args = list(reporter = reporter, notification = FALSE, card_fun = card_fun),
+ expr = {
+ testthat::expect_identical(reporter$get_cards(), list(card1))
+ session$setInputs(`download_button_simple-reset_reporter` = 0)
+ session$setInputs(`download_button_simple-reset_reporter_ok` = 0)
+ testthat::expect_identical(reporter$get_blocks(), list())
+ }
+ )
+})
+
+
+reporter <- Reporter$new()
+
+testthat::test_that("simple_reporter_srv - add a Card to Reporter", {
+ shiny::testServer(
+ simple_reporter_srv,
+ args = list(reporter = reporter, notification = FALSE, card_fun = card_fun0),
+ expr = {
+ card_len <- length(card_fun0()$get_content())
+ session$setInputs(`add_report_card_simple-add_report_card_button` = 0)
+ session$setInputs(`add_report_card_simple-comment` = "Comment Body")
+ session$setInputs(`add_report_card_simple-add_card_ok` = 0)
+
+ testthat::expect_identical(
+ length(reporter$get_blocks()),
+ card_len + 2L
+ )
+ }
+ )
+})
+
+testthat::test_that("simple_reporter_ui - returns a tagList", {
+ testthat::expect_true(
+ inherits(simple_reporter_ui("sth"), c("shiny.tag.list", "list"))
+ )
+})
diff --git a/tests/testthat/test-addCardModule.R b/tests/testthat/test-addCardModule.R
new file mode 100644
index 00000000..43d866ef
--- /dev/null
+++ b/tests/testthat/test-addCardModule.R
@@ -0,0 +1,37 @@
+card_fun <- function(card = ReportCard$new(),
+ comment = NULL) {
+ card$append_text("Header 2 text", "header2")
+ card$append_text("A paragraph of default text", "header2")
+ card$append_plot(
+ ggplot2::ggplot(iris, ggplot2::aes(x = Petal.Length)) +
+ ggplot2::geom_histogram()
+ )
+ card
+}
+
+
+reporter <- Reporter$new()
+
+testthat::test_that("add_card_button_srv - add a Card to the Reporter", {
+ shiny::testServer(
+ add_card_button_srv,
+ args = list(reporter = reporter, card_fun = card_fun),
+ expr = {
+ card_len <- length(card_fun()$get_content())
+ session$setInputs(`add_report_card_button` = 0)
+ session$setInputs(comment = "Comment Body")
+ session$setInputs(`add_card_ok` = 0)
+
+ testthat::expect_identical(
+ length(reporter$get_blocks()),
+ card_len
+ )
+ }
+ )
+})
+
+testthat::test_that("add_card_button_ui - returns a tagList", {
+ testthat::expect_true(
+ inherits(add_card_button_ui("sth"), c("shiny.tag.list", "list"))
+ )
+})
diff --git a/vignettes/.gitignore b/vignettes/.gitignore
new file mode 100644
index 00000000..097b2416
--- /dev/null
+++ b/vignettes/.gitignore
@@ -0,0 +1,2 @@
+*.html
+*.R
diff --git a/vignettes/simpleReporter.Rmd b/vignettes/simpleReporter.Rmd
new file mode 100644
index 00000000..24ab375b
--- /dev/null
+++ b/vignettes/simpleReporter.Rmd
@@ -0,0 +1,221 @@
+---
+title: "Simple Reporter"
+output: rmarkdown::html_vignette
+vignette: >
+ %\VignetteIndexEntry{Simple Reporter}
+ %\VignetteEngine{knitr::rmarkdown}
+ %\VignetteEncoding{UTF-8}
+---
+
+```{r, include = FALSE}
+knitr::opts_chunk$set(
+ collapse = TRUE,
+ comment = "#>"
+)
+```
+
+```{r setup}
+library(shiny)
+library(teal.reporter)
+library(ggplot2)
+library(rtables)
+```
+
+Simple Reporter is a shiny module for capturing app views during the session, and eventually downloading a report document.
+The Simple Reporter module consists of two separate modules one for each of the two buttons, Add Card and Download Report buttons modules.
+
+The code added to introduce the simple reporter is wrapped in the `### REPORTER` code blocks.
+
+The implementation should consist of 5 steps:
+
+1. Add modules user interface to the user interface of the app.
+2. Initialize Reporter instance.
+3. Create the Report Card function with two arguments: card and comment.
+The function should build the Card step by step and assuming it is empty at the beginning,
+the optional comment argument is a string provided by the user when the card is added.
+If the comment argument is not specified then it is added automatically at the end of the Card.
+This part requires the developer to use their imagination on how the document page should look like.
+4. Invoke the servers with the reporter instance and the function to create the report card instance.
+
+Simple Reporter shiny app with separate modules for each button:
+
+```{r}
+ui <- fluidPage(
+ titlePanel(""),
+ sidebarLayout(
+ sidebarPanel(
+ uiOutput("encoding")
+ ),
+ mainPanel(
+ ### REPORTER
+ teal.reporter::add_card_button_ui("addReportCard"),
+ teal.reporter::download_report_button_ui("downloadButton"),
+ ###
+ tags$br(),
+ tags$br(),
+ tabsetPanel(
+ id = "tabs",
+ tabPanel("Plot", plotOutput("dist_plot")),
+ tabPanel("Table", verbatimTextOutput("table"))
+ )
+ )
+ )
+)
+
+server <- function(input, output, session) {
+ output$encoding <- renderUI({
+ if (input$tabs == "Plot") {
+ sliderInput(
+ "binwidth",
+ "binwidth",
+ min = 2,
+ max = 10,
+ value = 8
+ )
+ } else {
+ selectInput(
+ "stat",
+ label = "Statistic",
+ choices = c("mean", "median", "sd"),
+ "mean"
+ )
+ }
+ })
+
+ plot <- reactive({
+ req(input$binwidth)
+ x <- mtcars$mpg
+ ggplot2::ggplot(data = mtcars, ggplot2::aes(x = mpg)) +
+ ggplot2::geom_histogram(binwidth = input$binwidth)
+ })
+
+ output$dist_plot <- renderPlot({
+ plot()
+ })
+
+ table <- reactive({
+ req(input$stat)
+ lyt <- basic_table() %>%
+ split_rows_by("Month", label_pos = "visible") %>%
+ analyze("Ozone", afun = eval(str2expression(input$stat)))
+
+ build_table(lyt, airquality)
+ })
+
+ output$table <- renderPrint({
+ table()
+ })
+
+ ### REPORTER
+ reporter <- teal.reporter::Reporter$new()
+ card_fun <- function(card = ReportCard$new(), comment) {
+ if (input$tabs == "Plot") {
+ card$append_text("My plot", "header2")
+ card$append_plot(plot())
+ } else if (input$tabs == "Table") {
+ card$append_text("My Table", "header2")
+ card$append_table(table())
+ }
+ card$append_text("Comment", "header3")
+ card$append_text(comment)
+ card
+ }
+
+ teal.reporter::add_card_button_srv("addReportCard", reporter = reporter, card_fun = card_fun)
+ teal.reporter::download_report_button_srv("downloadButton", reporter = reporter)
+ ###
+}
+
+shinyApp(ui = ui, server = server)
+```
+
+Simple Reporter shiny app with combined buttons modules:
+
+```{r}
+ui <- fluidPage(
+ titlePanel(""),
+ sidebarLayout(
+ sidebarPanel(
+ uiOutput("encoding")
+ ),
+ mainPanel(
+ ### REPORTER
+ teal.reporter::simple_reporter_ui("simpleReporter"),
+ ###
+ tags$br(),
+ tags$br(),
+ tabsetPanel(
+ id = "tabs",
+ tabPanel("Plot", plotOutput("dist_plot")),
+ tabPanel("Table", verbatimTextOutput("table"))
+ )
+ )
+ )
+)
+
+server <- function(input, output, session) {
+ output$encoding <- renderUI({
+ if (input$tabs == "Plot") {
+ sliderInput(
+ "binwidth",
+ "binwidth",
+ min = 2,
+ max = 10,
+ value = 8
+ )
+ } else {
+ selectInput(
+ "stat",
+ label = "Statistic",
+ choices = c("mean", "median", "sd"),
+ "mean"
+ )
+ }
+ })
+
+ plot <- reactive({
+ req(input$binwidth)
+ x <- mtcars$mpg
+ ggplot2::ggplot(data = mtcars, ggplot2::aes(x = mpg)) +
+ ggplot2::geom_histogram(binwidth = input$binwidth)
+ })
+
+ output$dist_plot <- renderPlot({
+ plot()
+ })
+
+ table <- reactive({
+ req(input$stat)
+ lyt <- basic_table() %>%
+ split_rows_by("Month", label_pos = "visible") %>%
+ analyze("Ozone", afun = eval(str2expression(input$stat)))
+
+ build_table(lyt, airquality)
+ })
+
+ output$table <- renderPrint({
+ table()
+ })
+
+ ### REPORTER
+ reporter <- teal.reporter::Reporter$new()
+ card_fun <- function(card = ReportCard$new(), comment) {
+ if (input$tabs == "Plot") {
+ card$append_text("My plot", "header2")
+ card$append_plot(plot())
+ } else if (input$tabs == "Table") {
+ card$append_text("My Table", "header2")
+ card$append_table(table())
+ }
+ card$append_text("Comment", "header3")
+ card$append_text(comment)
+ card
+ }
+
+ teal.reporter::simple_reporter_srv("simpleReporter", reporter = reporter, card_fun = card_fun)
+ ###
+}
+
+shinyApp(ui = ui, server = server)
+```
+