From d410e2626547d21053764c29bad4d241a0edac5f Mon Sep 17 00:00:00 2001 From: Olu Adetayo Date: Sun, 16 Mar 2025 21:56:53 +0000 Subject: [PATCH 01/15] add functions to createe template files --- NAMESPACE | 4 + R/init_app.R | 161 +++++++++++++++++++++++++++++++++++++++ man/init_app.Rd | 28 +++++++ man/init_commit_hooks.Rd | 28 +++++++ man/init_template.Rd | 33 ++++++++ man/init_workflow.Rd | 32 ++++++++ 6 files changed, 286 insertions(+) create mode 100644 R/init_app.R create mode 100644 man/init_app.Rd create mode 100644 man/init_commit_hooks.Rd create mode 100644 man/init_template.Rd create mode 100644 man/init_workflow.Rd diff --git a/NAMESPACE b/NAMESPACE index 9e4e5391..55830242 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,8 +12,12 @@ export(dfe_reactable) export(external_link) export(header) export(init_analytics) +export(init_app) +export(init_commit_hooks) export(init_cookies) export(init_hooks) +export(init_template) +export(init_workflow) export(section_tags) export(support_panel) export(tidy_code) diff --git a/R/init_app.R b/R/init_app.R new file mode 100644 index 00000000..fdc67ff5 --- /dev/null +++ b/R/init_app.R @@ -0,0 +1,161 @@ +#' Initialize the DFE Shiny Template Setup +#' +#' This function sets up a complete DFE Shiny template by: +#' 1. Cloning the Shiny template repository. +#' 2. Installing a Git pre-commit hook. +#' 3. Setting up a GitHub Actions workflow for deployment. +#' +#' @param dashboard_name A character string specifying the dashboard name for the deployment configuration. +#' If NULL, defaults to `"dfe-shiny-template"`. +#' +#' @details This function runs `init_app()`, `init_commit_hooks()`, and `init_workflow()` +#' in sequence to set up a working environment for a Shiny application. +#' +#' @return No return value. The function initializes the complete template. +#' @examples +#' \dontrun{ +#' init_template() +#' init_template(dashboard_name = "my-dashboard") +#' } +#' @export +init_template <- function(dashboard_name = "dfe-shiny-template") { + message("Initializing the DFE Shiny template...") + + # Step 1: Clone the Shiny template repository + init_app() + + # Step 2: Install Git pre-commit hooks + init_commit_hooks() + + # Step 3: Setup GitHub Actions workflow + init_workflow(dashboard_name = dashboard_name) + + message("DFE Shiny template setup completed successfully.") +} + +#' Load DFE Template R Shiny App into the Working Directory +#' +#' This function clones a template R Shiny application from the repository +#' "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" +#' into the current working directory. +#' +#' @details The function checks if Git is installed before attempting +#' to clone the repository. If Git is not found, it stops with an error message. +#' The downloaded repository contains a pre-configured R Shiny app template, +#' which can be used as a starting point for development. +#' +#' @return No return value. The function downloads the Shiny app template +#' into the current directory. +#' @examples +#' \dontrun{ +#' init_app() +#' } +#' @export +init_app <- function() { + repo_url <- "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" + + # Check if Git is installed + if (system("git --version", intern = TRUE) == "") { + stop("Git is not installed or not found in the system PATH.") + } + + # Clone the repository into the current working directory + cmd <- sprintf("git clone %s", repo_url) + system(cmd) + message("Shiny template app cloned successfully into the current directory.") +} + +#' Initialize Git Pre-Commit Hook for a Shiny App +#' +#' This function checks if the current directory is a Git repository, then +#' downloads a pre-commit hook script from the +#' "dfe-analytical-services/shiny-template" repository and +#' places it in `.git/hooks/pre-commit`, overwriting if necessary. +#' +#' @details The function verifies that the working directory is part of a +#' Git repository before proceeding. If Git is not installed or the directory +#' is not a Git repository, it stops with an error message. +#' The downloaded script ensures best practices before committing changes. +#' +#' @return No return value. The function installs the pre-commit hook. +#' @examples +#' \dontrun{ +#' init_commit_hooks() +#' } +#' @export +init_commit_hooks <- function() { + # Define the Git pre-commit hook file URL + hook_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.hooks/pre-commit.R" + + # Check if this is a Git repository + if (system("git rev-parse --is-inside-work-tree", intern = TRUE) != "true") { + stop("This is not a Git repository. Please initialize a Git repository first.") + } + + # Define the destination path for the pre-commit hook + hook_path <- ".git/hooks/pre-commit" + + # Download and write the file + tryCatch({ + download.file(hook_url, hook_path, mode = "wb") + Sys.chmod(hook_path, mode = "755") # Make it executable + message("Pre-commit hook installed successfully.") + }, error = function(e) { + stop("Failed to download and install the pre-commit hook: ", e$message) + }) +} + +#' Initialize GitHub Actions Workflow for Shiny App Deployment +#' +#' This function sets up a GitHub Actions workflow for deploying a Shiny app. +#' It ensures that the `.github/workflows/` directory exists, downloads a +#' deployment workflow file, and creates a configuration YAML file. +#' +#' @param dashboard_name A character string specifying the dashboard name. +#' default value is `"dfe-shiny-template"`. +#' +#' @details If the `.github/workflows/` directory does not exist, it is created. +#' The function then downloads the deployment workflow file and places it inside +#' `.github/workflows/`. Additionally, it generates a YAML file containing +#' deployment settings, allowing customization of the `dashboard_name`. +#' +#' @return No return value. The function sets up the workflow and configuration. +#' @examples +#' \dontrun{ +#' init_workflow() +#' init_workflow(dashboard_name = "my-custom-dashboard") +#' } +#' @export +init_workflow <- function(dashboard_name = "dfe-shiny-template") { + # Define paths + workflows_dir <- ".github/workflows" + workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") + config_file <- "deployment-config.yaml" + + # Define GitHub workflow file URL + workflow_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.github/workflows/deploy-shiny.yaml" + + # Ensure the .github/workflows directory exists + if (!dir.exists(workflows_dir)) { + dir.create(workflows_dir, recursive = TRUE) + message(".github/workflows directory created.") + } + + # Download and save the workflow file + tryCatch({ + download.file(workflow_url, workflow_file, mode = "wb") + message("GitHub Actions workflow file downloaded successfully.") + }, error = function(e) { + stop("Failed to download the workflow file: ", e$message) + }) + + # Create the deployment configuration YAML file + yaml_content <- sprintf("dashboard_name: %s\ndeploy_target: shinyapps\n", dashboard_name) + + tryCatch({ + writeLines(yaml_content, config_file) + message("Deployment configuration file created successfully.") + }, error = function(e) { + stop("Failed to create the deployment configuration file: ", e$message) + }) +} diff --git a/man/init_app.Rd b/man/init_app.Rd new file mode 100644 index 00000000..1ce6194f --- /dev/null +++ b/man/init_app.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_app} +\alias{init_app} +\title{Load DFE Template R Shiny App into the Working Directory} +\usage{ +init_app() +} +\value{ +No return value. The function downloads the Shiny app template +into the current directory. +} +\description{ +This function clones a template R Shiny application from the repository +"https://github.com.mcas.ms/dfe-analytical-services/shiny-template" +into the current working directory. +} +\details{ +The function checks if Git is installed before attempting +to clone the repository. If Git is not found, it stops with an error message. +The downloaded repository contains a pre-configured R Shiny app template, +which can be used as a starting point for development. +} +\examples{ +\dontrun{ +init_app() +} +} diff --git a/man/init_commit_hooks.Rd b/man/init_commit_hooks.Rd new file mode 100644 index 00000000..31d10f76 --- /dev/null +++ b/man/init_commit_hooks.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_commit_hooks} +\alias{init_commit_hooks} +\title{Initialize Git Pre-Commit Hook for a Shiny App} +\usage{ +init_commit_hooks() +} +\value{ +No return value. The function installs the pre-commit hook. +} +\description{ +This function checks if the current directory is a Git repository, then +downloads a pre-commit hook script from the +"dfe-analytical-services/shiny-template" repository and +places it in \code{.git/hooks/pre-commit}, overwriting if necessary. +} +\details{ +The function verifies that the working directory is part of a +Git repository before proceeding. If Git is not installed or the directory +is not a Git repository, it stops with an error message. +The downloaded script ensures best practices before committing changes. +} +\examples{ +\dontrun{ +init_commit_hooks() +} +} diff --git a/man/init_template.Rd b/man/init_template.Rd new file mode 100644 index 00000000..789332d3 --- /dev/null +++ b/man/init_template.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_template} +\alias{init_template} +\title{Initialize the DFE Shiny Template Setup} +\usage{ +init_template(dashboard_name = "dfe-shiny-template") +} +\arguments{ +\item{dashboard_name}{A character string specifying the dashboard name for the deployment configuration. +If NULL, defaults to \code{"dfe-shiny-template"}.} +} +\value{ +No return value. The function initializes the complete template. +} +\description{ +This function sets up a complete DFE Shiny template by: +\enumerate{ +\item Cloning the Shiny template repository. +\item Installing a Git pre-commit hook. +\item Setting up a GitHub Actions workflow for deployment. +} +} +\details{ +This function runs \code{init_app()}, \code{init_commit_hooks()}, and \code{init_workflow()} +in sequence to set up a working environment for a Shiny application. +} +\examples{ +\dontrun{ +init_template() +init_template(dashboard_name = "my-dashboard") +} +} diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd new file mode 100644 index 00000000..14887825 --- /dev/null +++ b/man/init_workflow.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_workflow} +\alias{init_workflow} +\title{Initialize GitHub Actions Workflow for Shiny App Deployment} +\usage{ +init_workflow(dashboard_name = "dfe-shiny-template") +} +\arguments{ +\item{dashboard_name}{A character string specifying the dashboard name. +default value is \code{"dfe-shiny-template"}.} +} +\value{ +No return value. The function sets up the workflow and configuration. +} +\description{ +This function sets up a GitHub Actions workflow for deploying a Shiny app. +It ensures that the \verb{.github/workflows/} directory exists, downloads a +deployment workflow file, and creates a configuration YAML file. +} +\details{ +If the \verb{.github/workflows/} directory does not exist, it is created. +The function then downloads the deployment workflow file and places it inside +\verb{.github/workflows/}. Additionally, it generates a YAML file containing +deployment settings, allowing customization of the \code{dashboard_name}. +} +\examples{ +\dontrun{ +init_workflow() +init_workflow(dashboard_name = "my-custom-dashboard") +} +} From f2e330b7d4bb6a431b671d48c30e6579ec0cb0e0 Mon Sep 17 00:00:00 2001 From: Olu Adetayo Date: Sun, 16 Mar 2025 21:56:53 +0000 Subject: [PATCH 02/15] add functions to createe template files --- NAMESPACE | 4 + R/init_app.R | 161 +++++++++++++++++++++++++++++++++++++++ man/init_app.Rd | 28 +++++++ man/init_commit_hooks.Rd | 28 +++++++ man/init_template.Rd | 33 ++++++++ man/init_workflow.Rd | 32 ++++++++ 6 files changed, 286 insertions(+) create mode 100644 R/init_app.R create mode 100644 man/init_app.Rd create mode 100644 man/init_commit_hooks.Rd create mode 100644 man/init_template.Rd create mode 100644 man/init_workflow.Rd diff --git a/NAMESPACE b/NAMESPACE index 9e4e5391..55830242 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,8 +12,12 @@ export(dfe_reactable) export(external_link) export(header) export(init_analytics) +export(init_app) +export(init_commit_hooks) export(init_cookies) export(init_hooks) +export(init_template) +export(init_workflow) export(section_tags) export(support_panel) export(tidy_code) diff --git a/R/init_app.R b/R/init_app.R new file mode 100644 index 00000000..fdc67ff5 --- /dev/null +++ b/R/init_app.R @@ -0,0 +1,161 @@ +#' Initialize the DFE Shiny Template Setup +#' +#' This function sets up a complete DFE Shiny template by: +#' 1. Cloning the Shiny template repository. +#' 2. Installing a Git pre-commit hook. +#' 3. Setting up a GitHub Actions workflow for deployment. +#' +#' @param dashboard_name A character string specifying the dashboard name for the deployment configuration. +#' If NULL, defaults to `"dfe-shiny-template"`. +#' +#' @details This function runs `init_app()`, `init_commit_hooks()`, and `init_workflow()` +#' in sequence to set up a working environment for a Shiny application. +#' +#' @return No return value. The function initializes the complete template. +#' @examples +#' \dontrun{ +#' init_template() +#' init_template(dashboard_name = "my-dashboard") +#' } +#' @export +init_template <- function(dashboard_name = "dfe-shiny-template") { + message("Initializing the DFE Shiny template...") + + # Step 1: Clone the Shiny template repository + init_app() + + # Step 2: Install Git pre-commit hooks + init_commit_hooks() + + # Step 3: Setup GitHub Actions workflow + init_workflow(dashboard_name = dashboard_name) + + message("DFE Shiny template setup completed successfully.") +} + +#' Load DFE Template R Shiny App into the Working Directory +#' +#' This function clones a template R Shiny application from the repository +#' "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" +#' into the current working directory. +#' +#' @details The function checks if Git is installed before attempting +#' to clone the repository. If Git is not found, it stops with an error message. +#' The downloaded repository contains a pre-configured R Shiny app template, +#' which can be used as a starting point for development. +#' +#' @return No return value. The function downloads the Shiny app template +#' into the current directory. +#' @examples +#' \dontrun{ +#' init_app() +#' } +#' @export +init_app <- function() { + repo_url <- "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" + + # Check if Git is installed + if (system("git --version", intern = TRUE) == "") { + stop("Git is not installed or not found in the system PATH.") + } + + # Clone the repository into the current working directory + cmd <- sprintf("git clone %s", repo_url) + system(cmd) + message("Shiny template app cloned successfully into the current directory.") +} + +#' Initialize Git Pre-Commit Hook for a Shiny App +#' +#' This function checks if the current directory is a Git repository, then +#' downloads a pre-commit hook script from the +#' "dfe-analytical-services/shiny-template" repository and +#' places it in `.git/hooks/pre-commit`, overwriting if necessary. +#' +#' @details The function verifies that the working directory is part of a +#' Git repository before proceeding. If Git is not installed or the directory +#' is not a Git repository, it stops with an error message. +#' The downloaded script ensures best practices before committing changes. +#' +#' @return No return value. The function installs the pre-commit hook. +#' @examples +#' \dontrun{ +#' init_commit_hooks() +#' } +#' @export +init_commit_hooks <- function() { + # Define the Git pre-commit hook file URL + hook_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.hooks/pre-commit.R" + + # Check if this is a Git repository + if (system("git rev-parse --is-inside-work-tree", intern = TRUE) != "true") { + stop("This is not a Git repository. Please initialize a Git repository first.") + } + + # Define the destination path for the pre-commit hook + hook_path <- ".git/hooks/pre-commit" + + # Download and write the file + tryCatch({ + download.file(hook_url, hook_path, mode = "wb") + Sys.chmod(hook_path, mode = "755") # Make it executable + message("Pre-commit hook installed successfully.") + }, error = function(e) { + stop("Failed to download and install the pre-commit hook: ", e$message) + }) +} + +#' Initialize GitHub Actions Workflow for Shiny App Deployment +#' +#' This function sets up a GitHub Actions workflow for deploying a Shiny app. +#' It ensures that the `.github/workflows/` directory exists, downloads a +#' deployment workflow file, and creates a configuration YAML file. +#' +#' @param dashboard_name A character string specifying the dashboard name. +#' default value is `"dfe-shiny-template"`. +#' +#' @details If the `.github/workflows/` directory does not exist, it is created. +#' The function then downloads the deployment workflow file and places it inside +#' `.github/workflows/`. Additionally, it generates a YAML file containing +#' deployment settings, allowing customization of the `dashboard_name`. +#' +#' @return No return value. The function sets up the workflow and configuration. +#' @examples +#' \dontrun{ +#' init_workflow() +#' init_workflow(dashboard_name = "my-custom-dashboard") +#' } +#' @export +init_workflow <- function(dashboard_name = "dfe-shiny-template") { + # Define paths + workflows_dir <- ".github/workflows" + workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") + config_file <- "deployment-config.yaml" + + # Define GitHub workflow file URL + workflow_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.github/workflows/deploy-shiny.yaml" + + # Ensure the .github/workflows directory exists + if (!dir.exists(workflows_dir)) { + dir.create(workflows_dir, recursive = TRUE) + message(".github/workflows directory created.") + } + + # Download and save the workflow file + tryCatch({ + download.file(workflow_url, workflow_file, mode = "wb") + message("GitHub Actions workflow file downloaded successfully.") + }, error = function(e) { + stop("Failed to download the workflow file: ", e$message) + }) + + # Create the deployment configuration YAML file + yaml_content <- sprintf("dashboard_name: %s\ndeploy_target: shinyapps\n", dashboard_name) + + tryCatch({ + writeLines(yaml_content, config_file) + message("Deployment configuration file created successfully.") + }, error = function(e) { + stop("Failed to create the deployment configuration file: ", e$message) + }) +} diff --git a/man/init_app.Rd b/man/init_app.Rd new file mode 100644 index 00000000..1ce6194f --- /dev/null +++ b/man/init_app.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_app} +\alias{init_app} +\title{Load DFE Template R Shiny App into the Working Directory} +\usage{ +init_app() +} +\value{ +No return value. The function downloads the Shiny app template +into the current directory. +} +\description{ +This function clones a template R Shiny application from the repository +"https://github.com.mcas.ms/dfe-analytical-services/shiny-template" +into the current working directory. +} +\details{ +The function checks if Git is installed before attempting +to clone the repository. If Git is not found, it stops with an error message. +The downloaded repository contains a pre-configured R Shiny app template, +which can be used as a starting point for development. +} +\examples{ +\dontrun{ +init_app() +} +} diff --git a/man/init_commit_hooks.Rd b/man/init_commit_hooks.Rd new file mode 100644 index 00000000..31d10f76 --- /dev/null +++ b/man/init_commit_hooks.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_commit_hooks} +\alias{init_commit_hooks} +\title{Initialize Git Pre-Commit Hook for a Shiny App} +\usage{ +init_commit_hooks() +} +\value{ +No return value. The function installs the pre-commit hook. +} +\description{ +This function checks if the current directory is a Git repository, then +downloads a pre-commit hook script from the +"dfe-analytical-services/shiny-template" repository and +places it in \code{.git/hooks/pre-commit}, overwriting if necessary. +} +\details{ +The function verifies that the working directory is part of a +Git repository before proceeding. If Git is not installed or the directory +is not a Git repository, it stops with an error message. +The downloaded script ensures best practices before committing changes. +} +\examples{ +\dontrun{ +init_commit_hooks() +} +} diff --git a/man/init_template.Rd b/man/init_template.Rd new file mode 100644 index 00000000..789332d3 --- /dev/null +++ b/man/init_template.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_template} +\alias{init_template} +\title{Initialize the DFE Shiny Template Setup} +\usage{ +init_template(dashboard_name = "dfe-shiny-template") +} +\arguments{ +\item{dashboard_name}{A character string specifying the dashboard name for the deployment configuration. +If NULL, defaults to \code{"dfe-shiny-template"}.} +} +\value{ +No return value. The function initializes the complete template. +} +\description{ +This function sets up a complete DFE Shiny template by: +\enumerate{ +\item Cloning the Shiny template repository. +\item Installing a Git pre-commit hook. +\item Setting up a GitHub Actions workflow for deployment. +} +} +\details{ +This function runs \code{init_app()}, \code{init_commit_hooks()}, and \code{init_workflow()} +in sequence to set up a working environment for a Shiny application. +} +\examples{ +\dontrun{ +init_template() +init_template(dashboard_name = "my-dashboard") +} +} diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd new file mode 100644 index 00000000..14887825 --- /dev/null +++ b/man/init_workflow.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init_app.R +\name{init_workflow} +\alias{init_workflow} +\title{Initialize GitHub Actions Workflow for Shiny App Deployment} +\usage{ +init_workflow(dashboard_name = "dfe-shiny-template") +} +\arguments{ +\item{dashboard_name}{A character string specifying the dashboard name. +default value is \code{"dfe-shiny-template"}.} +} +\value{ +No return value. The function sets up the workflow and configuration. +} +\description{ +This function sets up a GitHub Actions workflow for deploying a Shiny app. +It ensures that the \verb{.github/workflows/} directory exists, downloads a +deployment workflow file, and creates a configuration YAML file. +} +\details{ +If the \verb{.github/workflows/} directory does not exist, it is created. +The function then downloads the deployment workflow file and places it inside +\verb{.github/workflows/}. Additionally, it generates a YAML file containing +deployment settings, allowing customization of the \code{dashboard_name}. +} +\examples{ +\dontrun{ +init_workflow() +init_workflow(dashboard_name = "my-custom-dashboard") +} +} From 4dcf40abfb6ff4a4ed587261e4621cd78d616570 Mon Sep 17 00:00:00 2001 From: Olu Adetayo Date: Fri, 28 Mar 2025 10:09:08 +0000 Subject: [PATCH 03/15] update init_app --- R/init_app.R | 71 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/R/init_app.R b/R/init_app.R index fdc67ff5..7b5523ac 100644 --- a/R/init_app.R +++ b/R/init_app.R @@ -5,10 +5,11 @@ #' 2. Installing a Git pre-commit hook. #' 3. Setting up a GitHub Actions workflow for deployment. #' -#' @param dashboard_name A character string specifying the dashboard name for the deployment configuration. -#' If NULL, defaults to `"dfe-shiny-template"`. +#' @param dashboard_name A character string specifying the dashboard name for +#' the deployment configuration. #' -#' @details This function runs `init_app()`, `init_commit_hooks()`, and `init_workflow()` +#' @details This function runs `init_app()`, `init_commit_hooks()`, and +#' `init_workflow()` #' in sequence to set up a working environment for a Shiny application. #' #' @return No return value. The function initializes the complete template. @@ -18,10 +19,10 @@ #' init_template(dashboard_name = "my-dashboard") #' } #' @export -init_template <- function(dashboard_name = "dfe-shiny-template") { +init_template <- function(dashboard_name) { message("Initializing the DFE Shiny template...") - # Step 1: Clone the Shiny template repository + # Step 1: set up basic app structure init_app() # Step 2: Install Git pre-commit hooks @@ -33,36 +34,52 @@ init_template <- function(dashboard_name = "dfe-shiny-template") { message("DFE Shiny template setup completed successfully.") } -#' Load DFE Template R Shiny App into the Working Directory +#' Initialize a Shiny App Project Structure #' -#' This function clones a template R Shiny application from the repository -#' "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" -#' into the current working directory. +#' Creates the basic file and directory structure for a Shiny application, +#' including:`global.R`, `ui.R`, `server.R`, a `data/` folder, +#' and a `tests/testthat/` folder. #' -#' @details The function checks if Git is installed before attempting -#' to clone the repository. If Git is not found, it stops with an error message. -#' The downloaded repository contains a pre-configured R Shiny app template, -#' which can be used as a starting point for development. +#' @param path A character string specifying the root directory +#' where the app structure should be created. Defaults to the current +#' working directory (`"."`). +#' +#' @return No return value. The function is called for +#' its side effects (i.e., file and folder creation). #' -#' @return No return value. The function downloads the Shiny app template -#' into the current directory. #' @examples #' \dontrun{ -#' init_app() +#' init_app() # Creates structure in current directory +#' init_app("myShinyApp") # Creates structure in 'myShinyApp' directory #' } +#' #' @export -init_app <- function() { - repo_url <- "https://github.com.mcas.ms/dfe-analytical-services/shiny-template" - - # Check if Git is installed - if (system("git --version", intern = TRUE) == "") { - stop("Git is not installed or not found in the system PATH.") +init_app <- function(path = ".") { + # Define the full paths + files <- c("global.R", "ui.R", "server.R") + dirs <- c("data", "tests/testthat") + + # Create files + for (file in files) { + file_path <- file.path(path, file) + if (!file.exists(file_path)) { + file.create(file_path) + message("Created file: ", file_path) + } else { + message("File already exists: ", file_path) + } } - # Clone the repository into the current working directory - cmd <- sprintf("git clone %s", repo_url) - system(cmd) - message("Shiny template app cloned successfully into the current directory.") + # Create directories + for (dir in dirs) { + dir_path <- file.path(path, dir) + if (!dir.exists(dir_path)) { + dir.create(dir_path, recursive = TRUE) + message("Created directory: ", dir_path) + } else { + message("Directory already exists: ", dir_path) + } + } } #' Initialize Git Pre-Commit Hook for a Shiny App @@ -126,7 +143,7 @@ init_commit_hooks <- function() { #' init_workflow(dashboard_name = "my-custom-dashboard") #' } #' @export -init_workflow <- function(dashboard_name = "dfe-shiny-template") { +init_workflow <- function(dashboard_name) { # Define paths workflows_dir <- ".github/workflows" workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") From 3b9a09f8794b03cd5cb23c00213807a4188344a0 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Tue, 1 Apr 2025 16:15:43 +0100 Subject: [PATCH 04/15] Updating ROxygen --- man/init_app.Rd | 29 +++++++++++++++-------------- man/init_template.Rd | 9 +++++---- man/init_workflow.Rd | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/man/init_app.Rd b/man/init_app.Rd index 1ce6194f..5b834c0b 100644 --- a/man/init_app.Rd +++ b/man/init_app.Rd @@ -2,27 +2,28 @@ % Please edit documentation in R/init_app.R \name{init_app} \alias{init_app} -\title{Load DFE Template R Shiny App into the Working Directory} +\title{Initialize a Shiny App Project Structure} \usage{ -init_app() +init_app(path = ".") +} +\arguments{ +\item{path}{A character string specifying the root directory +where the app structure should be created. Defaults to the current +working directory (\code{"."}).} } \value{ -No return value. The function downloads the Shiny app template -into the current directory. +No return value. The function is called for +its side effects (i.e., file and folder creation). } \description{ -This function clones a template R Shiny application from the repository -"https://github.com.mcas.ms/dfe-analytical-services/shiny-template" -into the current working directory. -} -\details{ -The function checks if Git is installed before attempting -to clone the repository. If Git is not found, it stops with an error message. -The downloaded repository contains a pre-configured R Shiny app template, -which can be used as a starting point for development. +Creates the basic file and directory structure for a Shiny application, +including:\code{global.R}, \code{ui.R}, \code{server.R}, a \verb{data/} folder, +and a \verb{tests/testthat/} folder. } \examples{ \dontrun{ -init_app() +init_app() # Creates structure in current directory +init_app("myShinyApp") # Creates structure in 'myShinyApp' directory } + } diff --git a/man/init_template.Rd b/man/init_template.Rd index 789332d3..29d3a732 100644 --- a/man/init_template.Rd +++ b/man/init_template.Rd @@ -4,11 +4,11 @@ \alias{init_template} \title{Initialize the DFE Shiny Template Setup} \usage{ -init_template(dashboard_name = "dfe-shiny-template") +init_template(dashboard_name) } \arguments{ -\item{dashboard_name}{A character string specifying the dashboard name for the deployment configuration. -If NULL, defaults to \code{"dfe-shiny-template"}.} +\item{dashboard_name}{A character string specifying the dashboard name for +the deployment configuration.} } \value{ No return value. The function initializes the complete template. @@ -22,7 +22,8 @@ This function sets up a complete DFE Shiny template by: } } \details{ -This function runs \code{init_app()}, \code{init_commit_hooks()}, and \code{init_workflow()} +This function runs \code{init_app()}, \code{init_commit_hooks()}, and +\code{init_workflow()} in sequence to set up a working environment for a Shiny application. } \examples{ diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd index 14887825..8f0cc460 100644 --- a/man/init_workflow.Rd +++ b/man/init_workflow.Rd @@ -4,7 +4,7 @@ \alias{init_workflow} \title{Initialize GitHub Actions Workflow for Shiny App Deployment} \usage{ -init_workflow(dashboard_name = "dfe-shiny-template") +init_workflow(dashboard_name) } \arguments{ \item{dashboard_name}{A character string specifying the dashboard name. From 7580ccc1ee554de3efc7dd166e4cd2313a44a600 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 9 Apr 2025 12:40:25 +0100 Subject: [PATCH 05/15] Added scripts to create template global, ui and server files --- .gitignore | 1 + NAMESPACE | 3 +- R/create_dashboard.R | 565 ++++++++++++++++++ R/init_app.R | 178 ------ man/{init_template.Rd => create_dashboard.Rd} | 22 +- man/{init_app.Rd => init_base_app.Rd} | 22 +- man/init_commit_hooks.Rd | 2 +- man/init_global.Rd | 26 + man/init_server.Rd | 12 + man/init_ui.Rd | 12 + man/init_workflow.Rd | 2 +- 11 files changed, 653 insertions(+), 192 deletions(-) create mode 100644 R/create_dashboard.R delete mode 100644 R/init_app.R rename man/{init_template.Rd => create_dashboard.Rd} (52%) rename man/{init_app.Rd => init_base_app.Rd} (54%) create mode 100644 man/init_global.Rd create mode 100644 man/init_server.Rd create mode 100644 man/init_ui.Rd diff --git a/.gitignore b/.gitignore index 4841380b..b9be6031 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ google-analytics.html tests/testthat/google-analytics.html docs inst/doc +init_test/ diff --git a/NAMESPACE b/NAMESPACE index 690ca0a4..fd7eb774 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,17 +6,16 @@ export(cookies_banner_server) export(cookies_banner_ui) export(cookies_panel_server) export(cookies_panel_ui) +export(create_dashboard) export(custom_disconnect_message) export(dfe_cookies_script) export(dfe_reactable) export(external_link) export(header) export(init_analytics) -export(init_app) export(init_commit_hooks) export(init_cookies) export(init_hooks) -export(init_template) export(init_workflow) export(section_tags) export(set_bookmark_include) diff --git a/R/create_dashboard.R b/R/create_dashboard.R new file mode 100644 index 00000000..be2b8e23 --- /dev/null +++ b/R/create_dashboard.R @@ -0,0 +1,565 @@ +#' Initialize the DFE Shiny Template Setup +#' +#' This function sets up a complete DFE Shiny template by: +#' 1. Cloning the Shiny template repository. +#' 2. Installing a Git pre-commit hook. +#' 3. Setting up a GitHub Actions workflow for deployment. +#' +#' @param path +#' @param google_analytics_key +#' @param dashboard_url +#' @param site_title +#' @param parent_pub_name +#' @param parent_publication +#' @param team_email +#' @param repo_name +#' @param feedback_form_url +#' +#' @details This function runs `init_app()`, `init_commit_hooks()`, and +#' `init_workflow()` +#' in sequence to set up a working environment for a Shiny application. +#' +#' @return No return value. The function initializes the complete template. +#' @examples +#' \dontrun{ +#' init_template() +#' init_template(dashboard_name = "my-dashboard") +#' } +#' @export +create_dashboard <- function( + path = "./", + google_analytics_key = 'XXXXXXXXX', + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) { + message("Initializing the DFE Shiny template...") + + # Step 1: set up basic app structure + init_base_app() + + # Step 2: Install Git pre-commit hooks + init_commit_hooks() + + # Step 3: Setup GitHub Actions workflow + init_workflow(dashboard_name = dashboard_name) + + message("DFE Shiny template setup completed successfully.") +} + +#' Initialize a Shiny App Project Structure +#' +#' Creates the basic file and directory structure for a Shiny application, +#' including:`global.R`, `ui.R`, `server.R`, a `data/` folder, +#' and a `tests/testthat/` folder. +#' +#' @param path A character string specifying the root directory +#' where the app structure should be created. Defaults to the current +#' working directory (`"."`). +#' @inheritParams create_dashboard +#' +#' @return No return value. The function is called for +#' its side effects (i.e., file and folder creation). +#' @keywords internal +#' +#' @examples +#' \dontrun{ +#' init_app() # Creates structure in current directory +#' init_app("myShinyApp") # Creates structure in 'myShinyApp' directory +#' } +#' +init_base_app <- function( + path = "./", + google_analytics_key = 'XXXXXXXXX', + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) { + # Define the full paths + files <- c("server.R") + dirs <- c("data", "tests/testthat") + + init_global( + path = path, + google_analytics_key = google_analytics_key, + dashboard_url = dashboard_url, + site_title = site_title, + parent_pub_name = parent_pub_name, + parent_publication = parent_publication, + team_email = team_email, + repo_name = repo_name, + feedback_form_url = feedback_form_url + ) + init_ui( + path = path, + team_email = team_email + ) + + # Create files + for (file in files) { + file_path <- file.path(path, file) + if (!file.exists(file_path)) { + file.create(file_path) + message("Created file: ", file_path) + } else { + message("File already exists: ", file_path) + } + } + + # Create directories + for (dir in dirs) { + dir_path <- file.path(path, dir) + if (!dir.exists(dir_path)) { + dir.create(dir_path, recursive = TRUE) + message("Created directory: ", dir_path) + } else { + message("Directory already exists: ", dir_path) + } + } +} + +#' Initialise global.R +#' +#' @param google_analytics_key +#' @param site_title +#' @param parent_pub_name +#' @param parent_publication +#' @param team_email +#' @param repo_name +#' @param feedback_form_url +#' +#' @returns +#' @keywords internal +#' +#' @examples +init_global <- function( + path = "./", + google_analytics_key = 'XXXXXXXXX', + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) { + globalr_script <- paste( + c( + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "# This is the global file.", + "# Use it to store functions, library calls, source files etc.", + "# Moving these out of the server file and into here improves performance as the", + "# global file is run only once when the app launches and stays consistent", + "# across users whereas the server and UI files are constantly interacting and", + "# responsive to user input.", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "", + "# Library calls ===============================================================", + "shhh <- suppressPackageStartupMessages # It's a library, so shhh!", + + "## Core shiny and R packages --------------------------------------------------", + "shhh(library(shiny))", + "shhh(library(bslib))", + "shhh(library(shinytitle))", + "shhh(library(metathis))", + + "## Custom packages ------------------------------------------------------------", + "shhh(library(dfeR))", + "shhh(library(dfeshiny))", + "shhh(library(shinyGovstyle))", + "shhh(library(afcolours))", + + "## Creating charts and tables--------------------------------------------------", + "shhh(library(ggplot2))", + "shhh(library(ggiraph))", + + "## Data and string manipulation -----------------------------------------------", + "shhh(library(dplyr))", + "shhh(library(stringr))", + + "## Data downloads -------------------------------------------------------------", + "shhh(library(data.table))", + + "## Testing dependencies -------------------------------------------------------", + "# These are not needed for the app itself but including them here keeps them in", + "# renv but avoids the app needlessly loading them, saving on load time.", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "if (FALSE) {", + " shhh(library(shinytest2))", + " shhh(library(testthat))", + " shhh(library(lintr))", + " shhh(library(styler))", + "}", + + "# Source R scripts ============================================================", + "# Source any scripts here. Scripts may be needed to process data before it gets", + "# to the server file or to hold custom functions to keep the main files shorter.", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + + "# Set global variables ========================================================", + paste0("site_title <- \"", site_title, "\""), + paste0("parent_pub_name <- \"", parent_pub_name, "\""), + paste0("parent_publication <- \"", parent_publication, "\""), + paste0("team_email <- \"", team_email, "\""), + paste0("repo_name <- \"", repo_name, "\""), + paste0("feedback_form_url <- \"", feedback_form_url, "\""), + + "## Set the URLs that the site will be published to", + paste0("site_primary <- \"", dashboard_url, "\""), + + ## Google Analytics tracking + paste0("google_analytics_key <- \"", google_analytics_key, "\"") + ), + collapse = "\n" + ) + sink(file.path(path, "global.R")) + globalr_script |> cat() + sink() +} + +#' Initialise ui.R +#' +#' @inheritParams create_dashboard +#' +#' @returns +#' @keywords internal +#' +#' @examples +init_ui <- function(path = ".", team_email = "team.name@education.gov.uk") { + uir_script <- paste( + c( + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "# This is the ui file. Use it to call elements created in your server file into", + "# the app, and define where they are placed, and define any user inputs.", + "#", + "# Other elements like charts, navigation bars etc. are completely up to you to", + "# decide what goes in. However, every element should meet accessibility", + "# requirements and user needs.", + "#", + "# This is the user-interface definition of a Shiny web application. You can", + "# run the application by clicking 'Run App' above.", + "#", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "", + "ui <- function(input, output, session) {", + " page_fluid(", + "# Metadata for app ========================================================", + "tags$html(lang = \"en\"),", + "tags$head(HTML(paste0(\"\", site_title, \"\"))), # set in global.R", + "tags$head(tags$link(rel = \"shortcut icon\", href = \"dfefavicon.png\")),", + "# Add meta description for search engines", + "metathis::meta() %>%", + "meta_general(", + "application_name = site_title,", + "description = \"Interactive tool for exploring data\",", + "robots = \"index,follow\",", + "generator = \"R Shiny\",", + "subject = \"education\",", + "rating = \"General\",", + "referrer = \"no-referrer\"", + "),", + "", + "# Required to make the title update based on tab changes", + "shinytitle::use_shiny_title(),", + + "## Custom CSS -------------------------------------------------------------", + "tags$head(", + "tags$link(", + "rel = \"stylesheet\",", + "type = \"text/css\",", + "href = \"dfe_shiny_gov_style.css\"", + ")", + "),", + "", + "## Custom disconnect function ---------------------------------------------", + "dfeshiny::custom_disconnect_message(", + "links = site_primary,", + "publication_name = parent_pub_name,", + "publication_link = parent_publication", + "),", + "tags$head(includeHTML((\"google-analytics.html\"))),", + "shinyjs::useShinyjs(),", + "dfeshiny::dfe_cookies_script(),", + "dfeshiny::cookies_banner_ui(", + "name = site_title", + "),", + "", + "## Header -----------------------------------------------------------------", + "dfeshiny::header(", + "header = site_title,", + "),", + "", + "## Beta banner ------------------------------------------------------------", + "shinyGovstyle::banner(", + "\"gds_phase_banner\",", + "\"Alpha\",", + "paste0(", + paste0( + "\"This dashboard is being developed, contact", + team_email, + " with any feedback\"" + ), + ")", + "),", + "", + "# Page navigation =========================================================", + "# This switches between the supporting pages in the footer and the main dashboard", + "gov_main_layout(", + "bslib::navset_hidden(", + "id = \"pages\",", + "nav_panel(", + "\"dashboard\",", + "## Main dashboard ---------------------------------------------------", + "layout_columns(", + "# Override default wrapping breakpoints to avoid text overlap", + "col_widths = breakpoints(sm = c(4, 8), md = c(3, 9), lg = c(2, 9)),", + "## Left navigation ------------------------------------------------", + "dfe_contents_links(", + "links_list = c(", + "\"Panel 1\",", + "\"User guide\"", + ")", + "),", + "## Dashboard panels -----------------------------------------------", + "bslib::navset_hidden(", + "id = \"left_nav\",", + "nav_panel(", + "\"panel_1\",", + "prov_breakdowns_ui(id = \"panel_1\")", + "),", + "nav_panel(\"user_guide\", user_guide())", + ")", + ")", + "),", + "## Footer pages -------------------------------------------------------", + "nav_panel(\"footnotes\", footnotes_page()),", + "nav_panel(\"support\", support_page()),", + "nav_panel(\"accessibility_statement\", accessibility_page()),", + "nav_panel(\"cookies_statement\", cookies_page())", + ")", + "),", + "", + "# Footer ==================================================================", + "dfe_footer(", + "links_list = c(", + "\"Footnotes\",", + "\"Support\",", + "\"Accessibility statement\",", + "\"Cookies statement\"", + ")", + ")", + ")", + "}" + ), + collapse = "\n" + ) + sink(file.path(path, "ui.R")) + uir_script |> cat() + sink() + return(uir_script) +} + +#' Initialise ui.R +#' +#' @inheritParams create_dashboard +#' +#' @returns +#' @keywords internal +#' +#' @examples +init_server <- function( + path = ".", + team_email = "team.name@education.gov.uk" +) { + serverr_script <- paste( + c( + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "# This is the server file.", + "# Use it to create interactive elements like tables, charts and text for your", + "# app.", + "#", + "# Anything you create in the server file won't appear in your app until you call", + "# it in the UI file. This server script gives examples of plots and value boxes", + "#", + "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "", + "server <- function(input, output, session) {", + "# Manage cookie consent", + "output$cookies_status <- dfeshiny::cookies_banner_server(", + "input_cookies = shiny::reactive(input$cookies),", + "parent_session = session,", + "google_analytics_key = google_analytics_key", + ")", + "", + "dfeshiny::cookies_panel_server(", + "input_cookies = shiny::reactive(input$cookies),", + "google_analytics_key = google_analytics_key", + ")", + "", + "# Navigation ================================================================", + "## Main content left navigation ---------------------------------------------", + "observeEvent(", + "input$panel_1,", + "nav_select(\"left_nav\", \"panel_1\")", + ")", + "observeEvent(input$user_guide, nav_select(\"left_nav\", \"user_guide\"))", + "", + "## Footer links -------------------------------------------------------------", + "observeEvent(input$dashboard, nav_select(\"pages\", \"dashboard\"))", + "observeEvent(input$footnotes, nav_select(\"pages\", \"footnotes\"))", + "observeEvent(input$support, nav_select(\"pages\", \"support\"))", + "observeEvent(input$accessibility_statement,nav_select(\"pages\", \"accessibility_statement\"))", + "observeEvent(input$cookies_statement,nav_select(\"pages\", \"cookies_statement\")", + ")", + "", + "## Back links to main dashboard ---------------------------------------------", + "observeEvent(input$footnotes_to_dashboard, nav_select(\"pages\", \"dashboard\"))", + "observeEvent(input$support_to_dashboard, nav_select(\"pages\", \"dashboard\"))", + "observeEvent(input$cookies_to_dashboard, nav_select(\"pages\", \"dashboard\"))", + "observeEvent(", + "input$accessibility_to_dashboard,", + "nav_select(\"pages\", \"dashboard\")", + ")", + "", + "# Update title ==============================================================", + "# This changes the title based on the tab selections and is important for accessibility", + "# If on the main dashboard it uses the active tab from left_nav, else it uses the page input", + "observe({", + "if (input$pages == \"dashboard\") {", + "change_window_title(", + "title = paste0(site_title, \" - \", gsub(\"_\", \" \", input$left_nav))", + ")", + "} else {", + "change_window_title(", + "title = paste0(site_title, \" - \", gsub(\"_\", \" \", input$pages))", + ")", + "}", + "})", + "", + "}" + ), + collapse = "\n" + ) + sink(file.path(path, "server.R")) + serverr_script |> cat() + sink() + return(serverr_script) +} + + +#' Initialize Git Pre-Commit Hook for a Shiny App +#' +#' This function checks if the current directory is a Git repository, then +#' downloads a pre-commit hook script from the +#' "dfe-analytical-services/shiny-template" repository and +#' places it in `.git/hooks/pre-commit`, overwriting if necessary. +#' +#' @details The function verifies that the working directory is part of a +#' Git repository before proceeding. If Git is not installed or the directory +#' is not a Git repository, it stops with an error message. +#' The downloaded script ensures best practices before committing changes. +#' +#' @return No return value. The function installs the pre-commit hook. +#' @examples +#' \dontrun{ +#' init_commit_hooks() +#' } +#' @export +init_commit_hooks <- function() { + # Define the Git pre-commit hook file URL + hook_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.hooks/pre-commit.R" + + # Check if this is a Git repository + if (system("git rev-parse --is-inside-work-tree", intern = TRUE) != "true") { + stop( + "This is not a Git repository. Please initialize a Git repository first." + ) + } + + # Define the destination path for the pre-commit hook + hook_path <- ".git/hooks/pre-commit" + + # Download and write the file + tryCatch( + { + download.file(hook_url, hook_path, mode = "wb") + Sys.chmod(hook_path, mode = "755") # Make it executable + message("Pre-commit hook installed successfully.") + }, + error = function(e) { + stop("Failed to download and install the pre-commit hook: ", e$message) + } + ) +} + +#' Initialize GitHub Actions Workflow for Shiny App Deployment +#' +#' This function sets up a GitHub Actions workflow for deploying a Shiny app. +#' It ensures that the `.github/workflows/` directory exists, downloads a +#' deployment workflow file, and creates a configuration YAML file. +#' +#' @param dashboard_name A character string specifying the dashboard name. +#' default value is `"dfe-shiny-template"`. +#' +#' @details If the `.github/workflows/` directory does not exist, it is created. +#' The function then downloads the deployment workflow file and places it inside +#' `.github/workflows/`. Additionally, it generates a YAML file containing +#' deployment settings, allowing customization of the `dashboard_name`. +#' +#' @return No return value. The function sets up the workflow and configuration. +#' @examples +#' \dontrun{ +#' init_workflow() +#' init_workflow(dashboard_name = "my-custom-dashboard") +#' } +#' @export +init_workflow <- function(dashboard_name) { + # Define paths + workflows_dir <- ".github/workflows" + workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") + config_file <- "deployment-config.yaml" + + # Define GitHub workflow file URL + workflow_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.github/workflows/deploy-shiny.yaml" + + # Ensure the .github/workflows directory exists + if (!dir.exists(workflows_dir)) { + dir.create(workflows_dir, recursive = TRUE) + message(".github/workflows directory created.") + } + + # Download and save the workflow file + tryCatch( + { + download.file(workflow_url, workflow_file, mode = "wb") + message("GitHub Actions workflow file downloaded successfully.") + }, + error = function(e) { + stop("Failed to download the workflow file: ", e$message) + } + ) + + # Create the deployment configuration YAML file + yaml_content <- sprintf( + "dashboard_name: %s\ndeploy_target: shinyapps\n", + dashboard_name + ) + + tryCatch( + { + writeLines(yaml_content, config_file) + message("Deployment configuration file created successfully.") + }, + error = function(e) { + stop("Failed to create the deployment configuration file: ", e$message) + } + ) +} diff --git a/R/init_app.R b/R/init_app.R deleted file mode 100644 index 7b5523ac..00000000 --- a/R/init_app.R +++ /dev/null @@ -1,178 +0,0 @@ -#' Initialize the DFE Shiny Template Setup -#' -#' This function sets up a complete DFE Shiny template by: -#' 1. Cloning the Shiny template repository. -#' 2. Installing a Git pre-commit hook. -#' 3. Setting up a GitHub Actions workflow for deployment. -#' -#' @param dashboard_name A character string specifying the dashboard name for -#' the deployment configuration. -#' -#' @details This function runs `init_app()`, `init_commit_hooks()`, and -#' `init_workflow()` -#' in sequence to set up a working environment for a Shiny application. -#' -#' @return No return value. The function initializes the complete template. -#' @examples -#' \dontrun{ -#' init_template() -#' init_template(dashboard_name = "my-dashboard") -#' } -#' @export -init_template <- function(dashboard_name) { - message("Initializing the DFE Shiny template...") - - # Step 1: set up basic app structure - init_app() - - # Step 2: Install Git pre-commit hooks - init_commit_hooks() - - # Step 3: Setup GitHub Actions workflow - init_workflow(dashboard_name = dashboard_name) - - message("DFE Shiny template setup completed successfully.") -} - -#' Initialize a Shiny App Project Structure -#' -#' Creates the basic file and directory structure for a Shiny application, -#' including:`global.R`, `ui.R`, `server.R`, a `data/` folder, -#' and a `tests/testthat/` folder. -#' -#' @param path A character string specifying the root directory -#' where the app structure should be created. Defaults to the current -#' working directory (`"."`). -#' -#' @return No return value. The function is called for -#' its side effects (i.e., file and folder creation). -#' -#' @examples -#' \dontrun{ -#' init_app() # Creates structure in current directory -#' init_app("myShinyApp") # Creates structure in 'myShinyApp' directory -#' } -#' -#' @export -init_app <- function(path = ".") { - # Define the full paths - files <- c("global.R", "ui.R", "server.R") - dirs <- c("data", "tests/testthat") - - # Create files - for (file in files) { - file_path <- file.path(path, file) - if (!file.exists(file_path)) { - file.create(file_path) - message("Created file: ", file_path) - } else { - message("File already exists: ", file_path) - } - } - - # Create directories - for (dir in dirs) { - dir_path <- file.path(path, dir) - if (!dir.exists(dir_path)) { - dir.create(dir_path, recursive = TRUE) - message("Created directory: ", dir_path) - } else { - message("Directory already exists: ", dir_path) - } - } -} - -#' Initialize Git Pre-Commit Hook for a Shiny App -#' -#' This function checks if the current directory is a Git repository, then -#' downloads a pre-commit hook script from the -#' "dfe-analytical-services/shiny-template" repository and -#' places it in `.git/hooks/pre-commit`, overwriting if necessary. -#' -#' @details The function verifies that the working directory is part of a -#' Git repository before proceeding. If Git is not installed or the directory -#' is not a Git repository, it stops with an error message. -#' The downloaded script ensures best practices before committing changes. -#' -#' @return No return value. The function installs the pre-commit hook. -#' @examples -#' \dontrun{ -#' init_commit_hooks() -#' } -#' @export -init_commit_hooks <- function() { - # Define the Git pre-commit hook file URL - hook_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.hooks/pre-commit.R" - - # Check if this is a Git repository - if (system("git rev-parse --is-inside-work-tree", intern = TRUE) != "true") { - stop("This is not a Git repository. Please initialize a Git repository first.") - } - - # Define the destination path for the pre-commit hook - hook_path <- ".git/hooks/pre-commit" - - # Download and write the file - tryCatch({ - download.file(hook_url, hook_path, mode = "wb") - Sys.chmod(hook_path, mode = "755") # Make it executable - message("Pre-commit hook installed successfully.") - }, error = function(e) { - stop("Failed to download and install the pre-commit hook: ", e$message) - }) -} - -#' Initialize GitHub Actions Workflow for Shiny App Deployment -#' -#' This function sets up a GitHub Actions workflow for deploying a Shiny app. -#' It ensures that the `.github/workflows/` directory exists, downloads a -#' deployment workflow file, and creates a configuration YAML file. -#' -#' @param dashboard_name A character string specifying the dashboard name. -#' default value is `"dfe-shiny-template"`. -#' -#' @details If the `.github/workflows/` directory does not exist, it is created. -#' The function then downloads the deployment workflow file and places it inside -#' `.github/workflows/`. Additionally, it generates a YAML file containing -#' deployment settings, allowing customization of the `dashboard_name`. -#' -#' @return No return value. The function sets up the workflow and configuration. -#' @examples -#' \dontrun{ -#' init_workflow() -#' init_workflow(dashboard_name = "my-custom-dashboard") -#' } -#' @export -init_workflow <- function(dashboard_name) { - # Define paths - workflows_dir <- ".github/workflows" - workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") - config_file <- "deployment-config.yaml" - - # Define GitHub workflow file URL - workflow_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.github/workflows/deploy-shiny.yaml" - - # Ensure the .github/workflows directory exists - if (!dir.exists(workflows_dir)) { - dir.create(workflows_dir, recursive = TRUE) - message(".github/workflows directory created.") - } - - # Download and save the workflow file - tryCatch({ - download.file(workflow_url, workflow_file, mode = "wb") - message("GitHub Actions workflow file downloaded successfully.") - }, error = function(e) { - stop("Failed to download the workflow file: ", e$message) - }) - - # Create the deployment configuration YAML file - yaml_content <- sprintf("dashboard_name: %s\ndeploy_target: shinyapps\n", dashboard_name) - - tryCatch({ - writeLines(yaml_content, config_file) - message("Deployment configuration file created successfully.") - }, error = function(e) { - stop("Failed to create the deployment configuration file: ", e$message) - }) -} diff --git a/man/init_template.Rd b/man/create_dashboard.Rd similarity index 52% rename from man/init_template.Rd rename to man/create_dashboard.Rd index 29d3a732..a96e753e 100644 --- a/man/init_template.Rd +++ b/man/create_dashboard.Rd @@ -1,14 +1,24 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/init_app.R -\name{init_template} -\alias{init_template} +% Please edit documentation in R/create_dashboard.R +\name{create_dashboard} +\alias{create_dashboard} \title{Initialize the DFE Shiny Template Setup} \usage{ -init_template(dashboard_name) +create_dashboard( + path = "./", + google_analytics_key = "XXXXXXXXX", + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = + "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) } \arguments{ -\item{dashboard_name}{A character string specifying the dashboard name for -the deployment configuration.} +\item{feedback_form_url}{} } \value{ No return value. The function initializes the complete template. diff --git a/man/init_app.Rd b/man/init_base_app.Rd similarity index 54% rename from man/init_app.Rd rename to man/init_base_app.Rd index 5b834c0b..67e3b1e2 100644 --- a/man/init_app.Rd +++ b/man/init_base_app.Rd @@ -1,15 +1,28 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/init_app.R -\name{init_app} -\alias{init_app} +% Please edit documentation in R/create_dashboard.R +\name{init_base_app} +\alias{init_base_app} \title{Initialize a Shiny App Project Structure} \usage{ -init_app(path = ".") +init_base_app( + path = "./", + google_analytics_key = "XXXXXXXXX", + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = + "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) } \arguments{ \item{path}{A character string specifying the root directory where the app structure should be created. Defaults to the current working directory (\code{"."}).} + +\item{feedback_form_url}{} } \value{ No return value. The function is called for @@ -27,3 +40,4 @@ init_app("myShinyApp") # Creates structure in 'myShinyApp' directory } } +\keyword{internal} diff --git a/man/init_commit_hooks.Rd b/man/init_commit_hooks.Rd index 31d10f76..96af74e6 100644 --- a/man/init_commit_hooks.Rd +++ b/man/init_commit_hooks.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/init_app.R +% Please edit documentation in R/create_dashboard.R \name{init_commit_hooks} \alias{init_commit_hooks} \title{Initialize Git Pre-Commit Hook for a Shiny App} diff --git a/man/init_global.Rd b/man/init_global.Rd new file mode 100644 index 00000000..db95d50d --- /dev/null +++ b/man/init_global.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_dashboard.R +\name{init_global} +\alias{init_global} +\title{Initialise global.R} +\usage{ +init_global( + path = "./", + google_analytics_key = "XXXXXXXXX", + dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", + site_title = "Dashboard name", + parent_pub_name = "Publication name", + parent_publication = + "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + team_email = "team.name@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dashboard-name", + feedback_form_url = "" +) +} +\arguments{ +\item{feedback_form_url}{} +} +\description{ +Initialise global.R +} +\keyword{internal} diff --git a/man/init_server.Rd b/man/init_server.Rd new file mode 100644 index 00000000..a5ea4f91 --- /dev/null +++ b/man/init_server.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_dashboard.R +\name{init_server} +\alias{init_server} +\title{Initialise ui.R} +\usage{ +init_server(path = ".", team_email = "team.name@education.gov.uk") +} +\description{ +Initialise ui.R +} +\keyword{internal} diff --git a/man/init_ui.Rd b/man/init_ui.Rd new file mode 100644 index 00000000..66630c5d --- /dev/null +++ b/man/init_ui.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_dashboard.R +\name{init_ui} +\alias{init_ui} +\title{Initialise ui.R} +\usage{ +init_ui(path = ".", team_email = "team.name@education.gov.uk") +} +\description{ +Initialise ui.R +} +\keyword{internal} diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd index 8f0cc460..c8d57aec 100644 --- a/man/init_workflow.Rd +++ b/man/init_workflow.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/init_app.R +% Please edit documentation in R/create_dashboard.R \name{init_workflow} \alias{init_workflow} \title{Initialize GitHub Actions Workflow for Shiny App Deployment} From 302f760a1b90e28c0d76a8d9b6a6639c5d333e42 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 9 Apr 2025 12:42:27 +0100 Subject: [PATCH 06/15] Cleaning up some code in init_base_app --- R/create_dashboard.R | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/R/create_dashboard.R b/R/create_dashboard.R index be2b8e23..1ab4c9d8 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -83,11 +83,7 @@ init_base_app <- function( repo_name = "https://github.com/dfe-analytical-services/dashboard-name", feedback_form_url = "" ) { - # Define the full paths - files <- c("server.R") - dirs <- c("data", "tests/testthat") - - init_global( + global_string <- init_global( path = path, google_analytics_key = google_analytics_key, dashboard_url = dashboard_url, @@ -98,23 +94,17 @@ init_base_app <- function( repo_name = repo_name, feedback_form_url = feedback_form_url ) - init_ui( + ui_string <- init_ui( path = path, team_email = team_email ) - - # Create files - for (file in files) { - file_path <- file.path(path, file) - if (!file.exists(file_path)) { - file.create(file_path) - message("Created file: ", file_path) - } else { - message("File already exists: ", file_path) - } - } + server_string <- init_server( + path = path + ) # Create directories + # Define the full paths + dirs <- c("data", "tests/testthat") for (dir in dirs) { dir_path <- file.path(path, dir) if (!dir.exists(dir_path)) { From d3367e3177ba8f4dda5dc633d681d5155c83dea8 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 9 Apr 2025 17:33:08 +0100 Subject: [PATCH 07/15] Some tidying up of create database functions --- DESCRIPTION | 1 + R/create_dashboard.R | 154 +++++++++++++++++++------------ R/custom_disconnect_message.R | 64 ++++++++----- man/create_dashboard.Rd | 40 ++++++-- man/custom_disconnect_message.Rd | 10 -- man/init_base_app.Rd | 23 +++-- man/init_global.Rd | 20 +++- man/init_server.Rd | 15 ++- man/init_ui.Rd | 11 +++ 9 files changed, 225 insertions(+), 113 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 0e1b57cc..4c012760 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,6 +16,7 @@ Depends: R (>= 2.10) Imports: dplyr, + dfeR, checkmate, glue, htmltools, diff --git a/R/create_dashboard.R b/R/create_dashboard.R index 1ab4c9d8..2d0503a8 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -5,14 +5,22 @@ #' 2. Installing a Git pre-commit hook. #' 3. Setting up a GitHub Actions workflow for deployment. #' -#' @param path -#' @param google_analytics_key -#' @param dashboard_url -#' @param site_title -#' @param parent_pub_name -#' @param parent_publication -#' @param team_email -#' @param repo_name +#' @param path The root directory where the app should be created. String, default: `"."`. +#' @param google_analytics_key 10 digit Google Analytics key if available. String, default: +#' `"XXXXXXXXXX"` +#' @param publication_name The name of the parent publication. String, default: +#' `"Publication name"` +#' @param publication_link Full URL for the publication on Explore Education. String, default: ` +#' "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name"` +#' Statistics +#' @param dashboard_title Site title for the dashboard. String, default: `"Shiny template"` +#' @param dashboard_link Full URL of the dashboard. String, default: +#' `"https://department-for-education.shinyapps.io/shiny-template/"` +#' @param team_email Email address for support contact. String, default: +#' `"explore.statistics@@education.gov.uk"` +#' @param repo_name The repository URL, must be a valid URL for the dfe-analytical-services GitHub +#' area or the dfe-gov-uk Azure DevOps. String, default: +#' `"https://github.com/dfe-analytical-services/dfeshiny"` #' @param feedback_form_url #' #' @details This function runs `init_app()`, `init_commit_hooks()`, and @@ -22,31 +30,45 @@ #' @return No return value. The function initializes the complete template. #' @examples #' \dontrun{ -#' init_template() -#' init_template(dashboard_name = "my-dashboard") +#' create_dashboard() #' } #' @export create_dashboard <- function( path = "./", - google_analytics_key = 'XXXXXXXXX', - dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", - site_title = "Dashboard name", + dashboard_title = "dfeshiny template", + google_analytics_key = "XXXXXXXXX", + dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", parent_pub_name = "Publication name", - parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", - team_email = "team.name@education.gov.uk", - repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + parent_publication = paste0( + "https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name" + ), + team_email = "explore.statistics@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dfeshiny", + feedback_form_url = "", + verbose = FALSE ) { message("Initializing the DFE Shiny template...") # Step 1: set up basic app structure - init_base_app() + init_base_app( + path = path, + google_analytics_key = google_analytics_key, + dashboard_url = dashboard_url, + site_title = site_title, + parent_pub_name = parent_pub_name, + parent_publication = parent_publication, + team_email = team_email, + repo_name = repo_name, + feedback_form_url = feedback_form_url, + verbose = verbose + ) # Step 2: Install Git pre-commit hooks init_commit_hooks() # Step 3: Setup GitHub Actions workflow - init_workflow(dashboard_name = dashboard_name) + init_workflow(dashboard_name = site_title) message("DFE Shiny template setup completed successfully.") } @@ -57,9 +79,6 @@ create_dashboard <- function( #' including:`global.R`, `ui.R`, `server.R`, a `data/` folder, #' and a `tests/testthat/` folder. #' -#' @param path A character string specifying the root directory -#' where the app structure should be created. Defaults to the current -#' working directory (`"."`). #' @inheritParams create_dashboard #' #' @return No return value. The function is called for @@ -68,22 +87,41 @@ create_dashboard <- function( #' #' @examples #' \dontrun{ -#' init_app() # Creates structure in current directory -#' init_app("myShinyApp") # Creates structure in 'myShinyApp' directory +#' init_base_app() # Creates structure in current directory #' } #' init_base_app <- function( path = "./", - google_analytics_key = 'XXXXXXXXX', + google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", parent_pub_name = "Publication name", - parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + parent_publication = paste0( + "https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name" + ), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + feedback_form_url = "", + verbose = FALSE ) { - global_string <- init_global( + # Create directories + dirs <- c("data", "R/footer_pages", "tests/testthat") + for (dir in dirs) { + dir_path <- file.path(path, dir) + if (!dir.exists(dir_path)) { + dir.create(dir_path, recursive = TRUE) + dfeR::toggle_message("Created directory: ", dir_path, verbose = verbose) + } else { + dfeR::toggle_message( + "Directory already exists: ", + dir_path, + verbose = verbose + ) + } + } + + init_global( path = path, google_analytics_key = google_analytics_key, dashboard_url = dashboard_url, @@ -94,49 +132,36 @@ init_base_app <- function( repo_name = repo_name, feedback_form_url = feedback_form_url ) - ui_string <- init_ui( + init_ui( path = path, team_email = team_email ) - server_string <- init_server( + init_server( path = path ) - - # Create directories - # Define the full paths - dirs <- c("data", "tests/testthat") - for (dir in dirs) { - dir_path <- file.path(path, dir) - if (!dir.exists(dir_path)) { - dir.create(dir_path, recursive = TRUE) - message("Created directory: ", dir_path) - } else { - message("Directory already exists: ", dir_path) - } - } } #' Initialise global.R #' -#' @param google_analytics_key -#' @param site_title -#' @param parent_pub_name -#' @param parent_publication -#' @param team_email -#' @param repo_name -#' @param feedback_form_url +#' @inheritParams create_dashboard #' -#' @returns +#' @returns NULL #' @keywords internal #' #' @examples +#' \dontrun{ +#' init_global() +#' } init_global <- function( path = "./", - google_analytics_key = 'XXXXXXXXX', + google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", parent_pub_name = "Publication name", - parent_publication = "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + parent_publication = paste0( + "https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name" + ), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", feedback_form_url = "" @@ -193,7 +218,8 @@ init_global <- function( "# Source any scripts here. Scripts may be needed to process data before it gets", "# to the server file or to hold custom functions to keep the main files shorter.", "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - + "lapply(list.files(\"R/footer_pages/\", full.names = TRUE), source)", + "", "# Set global variables ========================================================", paste0("site_title <- \"", site_title, "\""), paste0("parent_pub_name <- \"", parent_pub_name, "\""), @@ -213,16 +239,20 @@ init_global <- function( sink(file.path(path, "global.R")) globalr_script |> cat() sink() + return(NULL) } #' Initialise ui.R #' #' @inheritParams create_dashboard #' -#' @returns +#' @returns NULL #' @keywords internal #' #' @examples +#' \dontrun{ +#' init_ui() +#' } init_ui <- function(path = ".", team_email = "team.name@education.gov.uk") { uir_script <- paste( c( @@ -354,17 +384,20 @@ init_ui <- function(path = ".", team_email = "team.name@education.gov.uk") { sink(file.path(path, "ui.R")) uir_script |> cat() sink() - return(uir_script) + return(NULL) } -#' Initialise ui.R +#' Initialise server.R #' #' @inheritParams create_dashboard #' -#' @returns +#' @returns NULL #' @keywords internal #' #' @examples +#' \dontrun{ +#' init_server() +#' } init_server <- function( path = ".", team_email = "team.name@education.gov.uk" @@ -406,7 +439,8 @@ init_server <- function( "observeEvent(input$dashboard, nav_select(\"pages\", \"dashboard\"))", "observeEvent(input$footnotes, nav_select(\"pages\", \"footnotes\"))", "observeEvent(input$support, nav_select(\"pages\", \"support\"))", - "observeEvent(input$accessibility_statement,nav_select(\"pages\", \"accessibility_statement\"))", + "observeEvent(", + "input$accessibility_statement,nav_select(\"pages\", \"accessibility_statement\"))", "observeEvent(input$cookies_statement,nav_select(\"pages\", \"cookies_statement\")", ")", "", @@ -421,7 +455,7 @@ init_server <- function( "", "# Update title ==============================================================", "# This changes the title based on the tab selections and is important for accessibility", - "# If on the main dashboard it uses the active tab from left_nav, else it uses the page input", + "# On the main dashboard it uses the active tab from left_nav, else it uses the page input", "observe({", "if (input$pages == \"dashboard\") {", "change_window_title(", diff --git a/R/custom_disconnect_message.R b/R/custom_disconnect_message.R index ea81611c..878d107f 100644 --- a/R/custom_disconnect_message.R +++ b/R/custom_disconnect_message.R @@ -8,12 +8,6 @@ #' @param reset the text to appear that will reset the page when clicked #' @param links A vector of possible URLs for the public site. Should mostly just be a single URL, #' but can be two URLs if an overflow site has been set up -#' @param publication_name The parent publication name -#' @param publication_link The link to the publication on Explore Education -#' Statistics -#' @param dashboard_title Title of the dashboard -#' @param support_contact Email address for support contact, defaults to -#' explore.statistics@@education.gov.uk #' @param custom_refresh Custom refresh link, defaults to refreshing the page, main value is if you #' have bookmarking enabled and want the refresh to send to the initial view instead of reloading #' any bookmarks @@ -51,24 +45,32 @@ #' custom_refresh = "https://department-for-education.shinyapps.io/my-dashboard" #' ) custom_disconnect_message <- function( - refresh = "refresh page (attempting to keep your last known selections)", - reset = "reset page (removing any previous selections)", - dashboard_title = NULL, - links = NULL, - publication_name = NULL, - publication_link = NULL, - support_contact = "explore.statistics@education.gov.uk", - custom_refresh = NULL, - custom_reset = NULL) { + refresh = "refresh page (attempting to keep your last known selections)", + reset = "reset page (removing any previous selections)", + dashboard_title = NULL, + links = NULL, + publication_name = NULL, + publication_link = NULL, + support_contact = "explore.statistics@education.gov.uk", + custom_refresh = NULL, + custom_reset = NULL +) { # Check links are valid - if (FALSE %in% validate_dashboard_url(links) || - "https://department-for-education.shinyapps.io/" %in% links) { # nolint: [indentation_linter] + if ( + FALSE %in% + validate_dashboard_url(links) || + "https://department-for-education.shinyapps.io/" %in% links + ) { + # nolint: [indentation_linter] stop("You have entered an invalid site link in the links argument.") } if (!is.null(custom_refresh)) { is_valid_refresh <- function(refresh) { - startsWith(stringr::str_trim(refresh), "https://department-for-education.shinyapps.io/") + startsWith( + stringr::str_trim(refresh), + "https://department-for-education.shinyapps.io/" + ) } if (is_valid_refresh(custom_refresh) == FALSE) { @@ -83,7 +85,10 @@ custom_disconnect_message <- function( if (!is.null(custom_reset)) { is_valid_reset <- function(reset) { - startsWith(stringr::str_trim(reset), "https://department-for-education.shinyapps.io/") + startsWith( + stringr::str_trim(reset), + "https://department-for-education.shinyapps.io/" + ) } if (is_valid_reset(custom_reset) == FALSE) { @@ -109,10 +114,15 @@ custom_disconnect_message <- function( startsWith(stringr::str_trim(link), pub_prefix) } - if (TRUE %in% is_valid_publication_link(publication_link) == FALSE || - publication_link %in% pub_prefix) { # nolint: [indentation_linter] - stop("You have entered an invalid publication link in the publication_link - argument.") + if ( + TRUE %in% is_valid_publication_link(publication_link) == FALSE || + publication_link %in% pub_prefix + ) { + # nolint: [indentation_linter] + stop( + "You have entered an invalid publication link in the publication_link + argument." + ) } } @@ -204,7 +214,10 @@ custom_disconnect_message <- function( ". Apologies for the inconvenience." ) }, - if (!is.null(publication_name) && grepl("explore-education-statistics", publication_link)) { + if ( + !is.null(publication_name) && + grepl("explore-education-statistics", publication_link) + ) { tags$p( "The data used in this dashboard can also be viewed or downloaded via the ", dfeshiny::external_link( @@ -236,7 +249,8 @@ custom_disconnect_message <- function( tags$div(id = "ss-overlay", style = "display: none;"), tags$head(htmltools::tags$style( glue::glue( - .open = "{{", .close = "}}", + .open = "{{", + .close = "}}", "#custom-disconnect-dialog a { display: {{ if (refresh == '') 'none' else 'inline' }} !important; color: #1d70b8 !important; diff --git a/man/create_dashboard.Rd b/man/create_dashboard.Rd index a96e753e..ea472aeb 100644 --- a/man/create_dashboard.Rd +++ b/man/create_dashboard.Rd @@ -6,19 +6,44 @@ \usage{ create_dashboard( path = "./", + dashboard_title = "dfeshiny template", google_analytics_key = "XXXXXXXXX", - dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", - site_title = "Dashboard name", + dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", parent_pub_name = "Publication name", parent_publication = - "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", - team_email = "team.name@education.gov.uk", - repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name"), + team_email = "explore.statistics@education.gov.uk", + repo_name = "https://github.com/dfe-analytical-services/dfeshiny", + feedback_form_url = "", + verbose = FALSE ) } \arguments{ +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{dashboard_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} + +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} + +\item{team_email}{Email address for support contact. String, default: +\code{"explore.statistics@education.gov.uk"}} + +\item{repo_name}{The repository URL, must be a valid URL for the dfe-analytical-services GitHub +area or the dfe-gov-uk Azure DevOps. String, default: +\code{"https://github.com/dfe-analytical-services/dfeshiny"}} + \item{feedback_form_url}{} + +\item{publication_name}{The name of the parent publication. String, default: +\code{"Publication name"}} + +\item{publication_link}{Full URL for the publication on Explore Education. String, default: \code{ "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name"} +Statistics} + +\item{dashboard_link}{Full URL of the dashboard. String, default: +\code{"https://department-for-education.shinyapps.io/shiny-template/"}} } \value{ No return value. The function initializes the complete template. @@ -38,7 +63,6 @@ in sequence to set up a working environment for a Shiny application. } \examples{ \dontrun{ -init_template() -init_template(dashboard_name = "my-dashboard") +create_dashboard() } } diff --git a/man/custom_disconnect_message.Rd b/man/custom_disconnect_message.Rd index a3dd4846..988467ea 100644 --- a/man/custom_disconnect_message.Rd +++ b/man/custom_disconnect_message.Rd @@ -21,19 +21,9 @@ custom_disconnect_message( \item{reset}{the text to appear that will reset the page when clicked} -\item{dashboard_title}{Title of the dashboard} - \item{links}{A vector of possible URLs for the public site. Should mostly just be a single URL, but can be two URLs if an overflow site has been set up} -\item{publication_name}{The parent publication name} - -\item{publication_link}{The link to the publication on Explore Education -Statistics} - -\item{support_contact}{Email address for support contact, defaults to -explore.statistics@education.gov.uk} - \item{custom_refresh}{Custom refresh link, defaults to refreshing the page, main value is if you have bookmarking enabled and want the refresh to send to the initial view instead of reloading any bookmarks} diff --git a/man/init_base_app.Rd b/man/init_base_app.Rd index 67e3b1e2..f5976cc1 100644 --- a/man/init_base_app.Rd +++ b/man/init_base_app.Rd @@ -11,16 +11,26 @@ init_base_app( site_title = "Dashboard name", parent_pub_name = "Publication name", parent_publication = - "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name"), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + feedback_form_url = "", + verbose = FALSE ) } \arguments{ -\item{path}{A character string specifying the root directory -where the app structure should be created. Defaults to the current -working directory (\code{"."}).} +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} + +\item{team_email}{Email address for support contact. String, default: +\code{"explore.statistics@education.gov.uk"}} + +\item{repo_name}{The repository URL, must be a valid URL for the dfe-analytical-services GitHub +area or the dfe-gov-uk Azure DevOps. String, default: +\code{"https://github.com/dfe-analytical-services/dfeshiny"}} \item{feedback_form_url}{} } @@ -35,8 +45,7 @@ and a \verb{tests/testthat/} folder. } \examples{ \dontrun{ -init_app() # Creates structure in current directory -init_app("myShinyApp") # Creates structure in 'myShinyApp' directory +init_base_app() # Creates structure in current directory } } diff --git a/man/init_global.Rd b/man/init_global.Rd index db95d50d..72e1f9f7 100644 --- a/man/init_global.Rd +++ b/man/init_global.Rd @@ -11,16 +11,34 @@ init_global( site_title = "Dashboard name", parent_pub_name = "Publication name", parent_publication = - "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name", + paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", + "publication-name"), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", feedback_form_url = "" ) } \arguments{ +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} + +\item{team_email}{Email address for support contact. String, default: +\code{"explore.statistics@education.gov.uk"}} + +\item{repo_name}{The repository URL, must be a valid URL for the dfe-analytical-services GitHub +area or the dfe-gov-uk Azure DevOps. String, default: +\code{"https://github.com/dfe-analytical-services/dfeshiny"}} + \item{feedback_form_url}{} } \description{ Initialise global.R } +\examples{ +\dontrun{ +init_global() +} +} \keyword{internal} diff --git a/man/init_server.Rd b/man/init_server.Rd index a5ea4f91..f45a6946 100644 --- a/man/init_server.Rd +++ b/man/init_server.Rd @@ -2,11 +2,22 @@ % Please edit documentation in R/create_dashboard.R \name{init_server} \alias{init_server} -\title{Initialise ui.R} +\title{Initialise server.R} \usage{ init_server(path = ".", team_email = "team.name@education.gov.uk") } +\arguments{ +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{team_email}{Email address for support contact. String, default: +\code{"explore.statistics@education.gov.uk"}} +} \description{ -Initialise ui.R +Initialise server.R +} +\examples{ +\dontrun{ +init_server() +} } \keyword{internal} diff --git a/man/init_ui.Rd b/man/init_ui.Rd index 66630c5d..136ba246 100644 --- a/man/init_ui.Rd +++ b/man/init_ui.Rd @@ -6,7 +6,18 @@ \usage{ init_ui(path = ".", team_email = "team.name@education.gov.uk") } +\arguments{ +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{team_email}{Email address for support contact. String, default: +\code{"explore.statistics@education.gov.uk"}} +} \description{ Initialise ui.R } +\examples{ +\dontrun{ +init_ui() +} +} \keyword{internal} From f65df6452c0fd15f4aae825bab0ef610ac860450 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 9 Apr 2025 17:36:36 +0100 Subject: [PATCH 08/15] Adding create dashboard to pkgdown --- _pkgdown.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index 41b467cb..e4ad0656 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -6,6 +6,10 @@ template: pkgdown-nav-height: 81.4468px reference: +- title: Creating a dashboard template + contents: + - create_dashboard + - starts_with("init") - title: Bookmarks contents: - set_bookmark_include @@ -15,10 +19,6 @@ reference: - title: Connectivity contents: - custom_disconnect_message -- title: Initialisation functions - desc: One time functions used to set up or update standardised scripts and workflows needed for your dashboard - contents: - - starts_with("init") - title: Links contents: - external_link From 796862e7700e4d059f72926e6df52dda1ba95e4a Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Fri, 25 Apr 2025 14:28:27 +0100 Subject: [PATCH 09/15] Updates to how init global, ui and server pull in code, plus added dfe_content_links --- .Rbuildignore | 1 + .github/workflows/deploy-shiny.yaml | 18 ++ NAMESPACE | 1 + R/analytics.R | 23 +- R/create_dashboard.R | 338 +++++----------------------- R/dfe_content_links.R | 36 +++ inst/global_template.r | 53 +++++ inst/server_template.r | 68 ++++++ inst/ui_template.r | 120 ++++++++++ man/create_dashboard.Rd | 6 +- man/dfe_contents_links.Rd | 14 ++ man/init_analytics.Rd | 4 +- man/init_base_app.Rd | 2 + man/init_commit_hooks.Rd | 5 +- man/init_global.Rd | 5 +- man/init_server.Rd | 5 +- man/init_ui.Rd | 5 +- man/init_workflow.Rd | 7 +- 18 files changed, 409 insertions(+), 302 deletions(-) create mode 100644 .github/workflows/deploy-shiny.yaml create mode 100644 R/dfe_content_links.R create mode 100644 inst/global_template.r create mode 100644 inst/server_template.r create mode 100644 inst/ui_template.r create mode 100644 man/dfe_contents_links.Rd diff --git a/.Rbuildignore b/.Rbuildignore index f4e8e2ba..22ad5a67 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -8,3 +8,4 @@ ^pkgdown$ ^.lintr$ ^data-raw$ +^init_test$ diff --git a/.github/workflows/deploy-shiny.yaml b/.github/workflows/deploy-shiny.yaml new file mode 100644 index 00000000..358ca660 --- /dev/null +++ b/.github/workflows/deploy-shiny.yaml @@ -0,0 +1,18 @@ +name: Deploy Dashboard +on: + push: + branches: + - main + - development + pull_request: + branches: + - main + +jobs: + deploy: + uses: dfe-analytical-services/dfeshiny/.github/workflows/dashboard_deploy_template.yaml@main + with: + parameter_file: deploy-parameters.yaml + secrets: + SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }} + SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }} diff --git a/NAMESPACE b/NAMESPACE index fd7eb774..ceb652b0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,6 +8,7 @@ export(cookies_panel_server) export(cookies_panel_ui) export(create_dashboard) export(custom_disconnect_message) +export(dfe_contents_links) export(dfe_cookies_script) export(dfe_reactable) export(external_link) diff --git a/R/analytics.R b/R/analytics.R index c5238f2d..9c026f9f 100644 --- a/R/analytics.R +++ b/R/analytics.R @@ -8,6 +8,7 @@ #' @param ga_code The Google Analytics code for the dashboard #' @param create_file Boolean TRUE or FALSE, default is TRUE, false will return #' the HTML in the console and is used mainly for testing or comparisons +#' @inheritParams create_dashboard #' #' @importFrom magrittr %>% #' @return NULL @@ -17,7 +18,11 @@ #' if (interactive()) { #' init_analytics(ga_code = "0123456789") #' } -init_analytics <- function(ga_code, create_file = TRUE) { +init_analytics <- function( + ga_code, + path = "./", + create_file = TRUE +) { if (!is.logical(create_file)) { stop("create_file must always be TRUE or FALSE") } @@ -117,8 +122,10 @@ dashboard. } else { if (file.exists("google-analytics.html")) { message("Analytics file already exists.") - message("If you have any customisations in that file, make sure you've - backed those up before over-writing.") + message( + "If you have any customisations in that file, make sure you've + backed those up before over-writing." + ) user_input <- readline( prompt = "Are you happy to overwrite the existing analytics script (y/N) " ) |> @@ -132,10 +139,16 @@ dashboard. write_out <- TRUE } if (write_out) { - cat(html_script_with_id, file = "google-analytics.html", sep = "\n") + cat( + html_script_with_id, + file = file.path(path, "google-analytics.html"), + sep = "\n" + ) message("") message("Google analytics script created as google-analytics.html.") - message("You'll need to add the following line to your ui.R script to start using analytics:") + message( + "You'll need to add the following line to your ui.R script to start using analytics:" + ) message("") message("tags$head(includeHTML((google-analytics.html))),") } else { diff --git a/R/create_dashboard.R b/R/create_dashboard.R index 2d0503a8..fc296189 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -13,7 +13,7 @@ #' @param publication_link Full URL for the publication on Explore Education. String, default: ` #' "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name"` #' Statistics -#' @param dashboard_title Site title for the dashboard. String, default: `"Shiny template"` +#' @param site_title Site title for the dashboard. String, default: `"Shiny template"` #' @param dashboard_link Full URL of the dashboard. String, default: #' `"https://department-for-education.shinyapps.io/shiny-template/"` #' @param team_email Email address for support contact. String, default: @@ -35,8 +35,8 @@ #' @export create_dashboard <- function( path = "./", - dashboard_title = "dfeshiny template", - google_analytics_key = "XXXXXXXXX", + site_title = "dfeshiny template", + google_analytics_key = "XXXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", parent_pub_name = "Publication name", parent_publication = paste0( @@ -50,7 +50,7 @@ create_dashboard <- function( ) { message("Initializing the DFE Shiny template...") - # Step 1: set up basic app structure + # Set up basic app structure init_base_app( path = path, google_analytics_key = google_analytics_key, @@ -64,11 +64,20 @@ create_dashboard <- function( verbose = verbose ) - # Step 2: Install Git pre-commit hooks - init_commit_hooks() + # Install Git pre-commit hooks + init_commit_hooks(path = path) - # Step 3: Setup GitHub Actions workflow - init_workflow(dashboard_name = site_title) + # Set up GitHub Actions workflow + init_workflow( + path = path, + site_title = site_title + ) + + # Set up Google Analytics + init_analytics( + path = path, + ga_code = google_analytics_key + ) message("DFE Shiny template setup completed successfully.") } @@ -130,14 +139,16 @@ init_base_app <- function( parent_publication = parent_publication, team_email = team_email, repo_name = repo_name, - feedback_form_url = feedback_form_url + feedback_form_url = feedback_form_url, + verbose = verbose ) init_ui( path = path, - team_email = team_email + verbose = verbose ) init_server( - path = path + path = path, + verbose = verbose ) } @@ -164,63 +175,12 @@ init_global <- function( ), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + feedback_form_url = "", + verbose = FALSE ) { globalr_script <- paste( c( - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "# This is the global file.", - "# Use it to store functions, library calls, source files etc.", - "# Moving these out of the server file and into here improves performance as the", - "# global file is run only once when the app launches and stays consistent", - "# across users whereas the server and UI files are constantly interacting and", - "# responsive to user input.", - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "", - "# Library calls ===============================================================", - "shhh <- suppressPackageStartupMessages # It's a library, so shhh!", - - "## Core shiny and R packages --------------------------------------------------", - "shhh(library(shiny))", - "shhh(library(bslib))", - "shhh(library(shinytitle))", - "shhh(library(metathis))", - - "## Custom packages ------------------------------------------------------------", - "shhh(library(dfeR))", - "shhh(library(dfeshiny))", - "shhh(library(shinyGovstyle))", - "shhh(library(afcolours))", - - "## Creating charts and tables--------------------------------------------------", - "shhh(library(ggplot2))", - "shhh(library(ggiraph))", - - "## Data and string manipulation -----------------------------------------------", - "shhh(library(dplyr))", - "shhh(library(stringr))", - - "## Data downloads -------------------------------------------------------------", - "shhh(library(data.table))", - - "## Testing dependencies -------------------------------------------------------", - "# These are not needed for the app itself but including them here keeps them in", - "# renv but avoids the app needlessly loading them, saving on load time.", - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "if (FALSE) {", - " shhh(library(shinytest2))", - " shhh(library(testthat))", - " shhh(library(lintr))", - " shhh(library(styler))", - "}", - - "# Source R scripts ============================================================", - "# Source any scripts here. Scripts may be needed to process data before it gets", - "# to the server file or to hold custom functions to keep the main files shorter.", - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "lapply(list.files(\"R/footer_pages/\", full.names = TRUE), source)", - "", - "# Set global variables ========================================================", + readLines("inst/global_template.r"), paste0("site_title <- \"", site_title, "\""), paste0("parent_pub_name <- \"", parent_pub_name, "\""), paste0("parent_publication <- \"", parent_publication, "\""), @@ -236,9 +196,12 @@ init_global <- function( ), collapse = "\n" ) - sink(file.path(path, "global.R")) - globalr_script |> cat() - sink() + globalr_script |> + cat(file = file.path(path, "global.R")) + dfeR::toggle_message( + "create_dashboard: global.R created", + verbose = verbose + ) return(NULL) } @@ -253,137 +216,17 @@ init_global <- function( #' \dontrun{ #' init_ui() #' } -init_ui <- function(path = ".", team_email = "team.name@education.gov.uk") { - uir_script <- paste( - c( - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "# This is the ui file. Use it to call elements created in your server file into", - "# the app, and define where they are placed, and define any user inputs.", - "#", - "# Other elements like charts, navigation bars etc. are completely up to you to", - "# decide what goes in. However, every element should meet accessibility", - "# requirements and user needs.", - "#", - "# This is the user-interface definition of a Shiny web application. You can", - "# run the application by clicking 'Run App' above.", - "#", - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "", - "ui <- function(input, output, session) {", - " page_fluid(", - "# Metadata for app ========================================================", - "tags$html(lang = \"en\"),", - "tags$head(HTML(paste0(\"\", site_title, \"\"))), # set in global.R", - "tags$head(tags$link(rel = \"shortcut icon\", href = \"dfefavicon.png\")),", - "# Add meta description for search engines", - "metathis::meta() %>%", - "meta_general(", - "application_name = site_title,", - "description = \"Interactive tool for exploring data\",", - "robots = \"index,follow\",", - "generator = \"R Shiny\",", - "subject = \"education\",", - "rating = \"General\",", - "referrer = \"no-referrer\"", - "),", - "", - "# Required to make the title update based on tab changes", - "shinytitle::use_shiny_title(),", - - "## Custom CSS -------------------------------------------------------------", - "tags$head(", - "tags$link(", - "rel = \"stylesheet\",", - "type = \"text/css\",", - "href = \"dfe_shiny_gov_style.css\"", - ")", - "),", - "", - "## Custom disconnect function ---------------------------------------------", - "dfeshiny::custom_disconnect_message(", - "links = site_primary,", - "publication_name = parent_pub_name,", - "publication_link = parent_publication", - "),", - "tags$head(includeHTML((\"google-analytics.html\"))),", - "shinyjs::useShinyjs(),", - "dfeshiny::dfe_cookies_script(),", - "dfeshiny::cookies_banner_ui(", - "name = site_title", - "),", - "", - "## Header -----------------------------------------------------------------", - "dfeshiny::header(", - "header = site_title,", - "),", - "", - "## Beta banner ------------------------------------------------------------", - "shinyGovstyle::banner(", - "\"gds_phase_banner\",", - "\"Alpha\",", - "paste0(", - paste0( - "\"This dashboard is being developed, contact", - team_email, - " with any feedback\"" - ), - ")", - "),", - "", - "# Page navigation =========================================================", - "# This switches between the supporting pages in the footer and the main dashboard", - "gov_main_layout(", - "bslib::navset_hidden(", - "id = \"pages\",", - "nav_panel(", - "\"dashboard\",", - "## Main dashboard ---------------------------------------------------", - "layout_columns(", - "# Override default wrapping breakpoints to avoid text overlap", - "col_widths = breakpoints(sm = c(4, 8), md = c(3, 9), lg = c(2, 9)),", - "## Left navigation ------------------------------------------------", - "dfe_contents_links(", - "links_list = c(", - "\"Panel 1\",", - "\"User guide\"", - ")", - "),", - "## Dashboard panels -----------------------------------------------", - "bslib::navset_hidden(", - "id = \"left_nav\",", - "nav_panel(", - "\"panel_1\",", - "prov_breakdowns_ui(id = \"panel_1\")", - "),", - "nav_panel(\"user_guide\", user_guide())", - ")", - ")", - "),", - "## Footer pages -------------------------------------------------------", - "nav_panel(\"footnotes\", footnotes_page()),", - "nav_panel(\"support\", support_page()),", - "nav_panel(\"accessibility_statement\", accessibility_page()),", - "nav_panel(\"cookies_statement\", cookies_page())", - ")", - "),", - "", - "# Footer ==================================================================", - "dfe_footer(", - "links_list = c(", - "\"Footnotes\",", - "\"Support\",", - "\"Accessibility statement\",", - "\"Cookies statement\"", - ")", - ")", - ")", - "}" - ), - collapse = "\n" +init_ui <- function( + path = ".", + verbose = FALSE +) { + uir_script <- readLines("inst/ui_template.r") |> + paste(collapse = "\n") + uir_script |> cat(file = file.path(path, "ui.R")) + dfeR::toggle_message( + "create_dashboard: ui.R created", + verbose = verbose ) - sink(file.path(path, "ui.R")) - uir_script |> cat() - sink() return(NULL) } @@ -400,81 +243,15 @@ init_ui <- function(path = ".", team_email = "team.name@education.gov.uk") { #' } init_server <- function( path = ".", - team_email = "team.name@education.gov.uk" + verbose = FALSE ) { - serverr_script <- paste( - c( - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "# This is the server file.", - "# Use it to create interactive elements like tables, charts and text for your", - "# app.", - "#", - "# Anything you create in the server file won't appear in your app until you call", - "# it in the UI file. This server script gives examples of plots and value boxes", - "#", - "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", - "", - "server <- function(input, output, session) {", - "# Manage cookie consent", - "output$cookies_status <- dfeshiny::cookies_banner_server(", - "input_cookies = shiny::reactive(input$cookies),", - "parent_session = session,", - "google_analytics_key = google_analytics_key", - ")", - "", - "dfeshiny::cookies_panel_server(", - "input_cookies = shiny::reactive(input$cookies),", - "google_analytics_key = google_analytics_key", - ")", - "", - "# Navigation ================================================================", - "## Main content left navigation ---------------------------------------------", - "observeEvent(", - "input$panel_1,", - "nav_select(\"left_nav\", \"panel_1\")", - ")", - "observeEvent(input$user_guide, nav_select(\"left_nav\", \"user_guide\"))", - "", - "## Footer links -------------------------------------------------------------", - "observeEvent(input$dashboard, nav_select(\"pages\", \"dashboard\"))", - "observeEvent(input$footnotes, nav_select(\"pages\", \"footnotes\"))", - "observeEvent(input$support, nav_select(\"pages\", \"support\"))", - "observeEvent(", - "input$accessibility_statement,nav_select(\"pages\", \"accessibility_statement\"))", - "observeEvent(input$cookies_statement,nav_select(\"pages\", \"cookies_statement\")", - ")", - "", - "## Back links to main dashboard ---------------------------------------------", - "observeEvent(input$footnotes_to_dashboard, nav_select(\"pages\", \"dashboard\"))", - "observeEvent(input$support_to_dashboard, nav_select(\"pages\", \"dashboard\"))", - "observeEvent(input$cookies_to_dashboard, nav_select(\"pages\", \"dashboard\"))", - "observeEvent(", - "input$accessibility_to_dashboard,", - "nav_select(\"pages\", \"dashboard\")", - ")", - "", - "# Update title ==============================================================", - "# This changes the title based on the tab selections and is important for accessibility", - "# On the main dashboard it uses the active tab from left_nav, else it uses the page input", - "observe({", - "if (input$pages == \"dashboard\") {", - "change_window_title(", - "title = paste0(site_title, \" - \", gsub(\"_\", \" \", input$left_nav))", - ")", - "} else {", - "change_window_title(", - "title = paste0(site_title, \" - \", gsub(\"_\", \" \", input$pages))", - ")", - "}", - "})", - "", - "}" - ), - collapse = "\n" + serverr_script <- readLines("inst/server_template.r") |> + paste(collapse = "\n") + serverr_script |> cat(file = file.path(path, "server.R")) + dfeR::toggle_message( + "create_dashboard: server.R created", + verbose = verbose ) - sink(file.path(path, "server.R")) - serverr_script |> cat() - sink() return(serverr_script) } @@ -491,13 +268,15 @@ init_server <- function( #' is not a Git repository, it stops with an error message. #' The downloaded script ensures best practices before committing changes. #' +#' @inheritParams create_dashboard +#' #' @return No return value. The function installs the pre-commit hook. #' @examples #' \dontrun{ #' init_commit_hooks() #' } #' @export -init_commit_hooks <- function() { +init_commit_hooks <- function(path = "./") { # Define the Git pre-commit hook file URL hook_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.hooks/pre-commit.R" @@ -509,12 +288,12 @@ init_commit_hooks <- function() { } # Define the destination path for the pre-commit hook - hook_path <- ".git/hooks/pre-commit" + hook_path <- file.path(path, ".git/hooks/pre-commit") # Download and write the file tryCatch( { - download.file(hook_url, hook_path, mode = "wb") + utils::download.file(hook_url, hook_path, mode = "wb") Sys.chmod(hook_path, mode = "755") # Make it executable message("Pre-commit hook installed successfully.") }, @@ -530,8 +309,7 @@ init_commit_hooks <- function() { #' It ensures that the `.github/workflows/` directory exists, downloads a #' deployment workflow file, and creates a configuration YAML file. #' -#' @param dashboard_name A character string specifying the dashboard name. -#' default value is `"dfe-shiny-template"`. +#' @inheritParams create_dashboard #' #' @details If the `.github/workflows/` directory does not exist, it is created. #' The function then downloads the deployment workflow file and places it inside @@ -545,7 +323,7 @@ init_commit_hooks <- function() { #' init_workflow(dashboard_name = "my-custom-dashboard") #' } #' @export -init_workflow <- function(dashboard_name) { +init_workflow <- function(site_title, path = "./") { # Define paths workflows_dir <- ".github/workflows" workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") @@ -563,7 +341,7 @@ init_workflow <- function(dashboard_name) { # Download and save the workflow file tryCatch( { - download.file(workflow_url, workflow_file, mode = "wb") + utils::download.file(workflow_url, workflow_file, mode = "wb") message("GitHub Actions workflow file downloaded successfully.") }, error = function(e) { @@ -574,12 +352,12 @@ init_workflow <- function(dashboard_name) { # Create the deployment configuration YAML file yaml_content <- sprintf( "dashboard_name: %s\ndeploy_target: shinyapps\n", - dashboard_name + site_title ) tryCatch( { - writeLines(yaml_content, config_file) + writeLines(yaml_content, file.path(path, config_file)) message("Deployment configuration file created successfully.") }, error = function(e) { diff --git a/R/dfe_content_links.R b/R/dfe_content_links.R new file mode 100644 index 00000000..e3e22723 --- /dev/null +++ b/R/dfe_content_links.R @@ -0,0 +1,36 @@ +#' Content links +#' +#' @description +#' Content links for the right hand navigation list panel +#' +#' @param links_list List of links for the navigation panel +#' +#' @returns +#' @export +#' +#' @examples +dfe_contents_links <- function(links_list) { + # Add the HTML around the link and make an id by snake casing + create_sidelink <- function(link_text) { + tags$li( + "—", + actionLink( + tolower(gsub(" ", "_", link_text)), + link_text, + `data-value` = link_text, + class = "contents_link" + ) + ) + } + + # The HTML div to be returned + tags$div( + style = "position: sticky; top: 0.5rem; padding: 0.25rem;", # Make it stick! + h2("Contents"), + tags$ul( + id = "contents_links", + style = "list-style-type: none; padding-left: 0; font-size: 1rem;", # remove the circle bullets + lapply(links_list, create_sidelink) + ) + ) +} diff --git a/inst/global_template.r b/inst/global_template.r new file mode 100644 index 00000000..d89c8ffa --- /dev/null +++ b/inst/global_template.r @@ -0,0 +1,53 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# This is the global file. +# Use it to store functions, library calls, source files etc. +# Moving these out of the server file and into here improves performance as the +# global file is run only once when the app launches and stays consistent +# across users whereas the server and UI files are constantly interacting and +# responsive to user input. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Library calls =============================================================== +shhh <- suppressPackageStartupMessages # It's a library, so shhh! + +## Core shiny and R packages -------------------------------------------------- +shhh(library(shiny)) +shhh(library(bslib)) +shhh(library(shinytitle)) +shhh(library(metathis)) + +## Custom packages ------------------------------------------------------------ +shhh(library(dfeR)) +shhh(library(dfeshiny)) +shhh(library(shinyGovstyle)) +shhh(library(afcolours)) + +## Creating charts and tables-------------------------------------------------- +shhh(library(ggplot2)) +shhh(library(ggiraph)) + +## Data and string manipulation ----------------------------------------------- +shhh(library(dplyr)) +shhh(library(stringr)) + +## Data downloads ------------------------------------------------------------- +shhh(library(data.table)) + +## Testing dependencies ------------------------------------------------------- +# These are not needed for the app itself but including them here keeps them in +# renv but avoids the app needlessly loading them, saving on load time. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +if (FALSE) { + shhh(library(shinytest2)) + shhh(library(testthat)) + shhh(library(lintr)) + shhh(library(styler)) +} + +# Source R scripts ============================================================ +# Source any scripts here. Scripts may be needed to process data before it gets +# to the server file or to hold custom functions to keep the main files shorter. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +lapply(list.files("R/footer_pages/", full.names = TRUE), source) + +# Set global variables ======================================================== diff --git a/inst/server_template.r b/inst/server_template.r new file mode 100644 index 00000000..1e733a4b --- /dev/null +++ b/inst/server_template.r @@ -0,0 +1,68 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# This is the server file. +# Use it to create interactive elements like tables, charts and text for your +# app. +# +# Anything you create in the server file won't appear in your app until you call +# it in the UI file. This server script gives examples of plots and value boxes +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +server <- function(input, output, session) { + # Manage cookie consent + output$cookies_status <- dfeshiny::cookies_banner_server( + input_cookies = shiny::reactive(input$cookies), + parent_session = session, + google_analytics_key = google_analytics_key + ) + + dfeshiny::cookies_panel_server( + input_cookies = shiny::reactive(input$cookies), + google_analytics_key = google_analytics_key + ) + + # Navigation ================================================================ + ## Main content left navigation --------------------------------------------- + observeEvent( + input$panel_1, + nav_select("left_nav", "panel_1") + ) + observeEvent(input$user_guide, nav_select("left_nav", "user_guide")) + + ## Footer links ------------------------------------------------------------- + observeEvent(input$dashboard, nav_select("pages", "dashboard")) + observeEvent(input$footnotes, nav_select("pages", "footnotes")) + observeEvent(input$support, nav_select("pages", "support")) + observeEvent( + input$accessibility_statement, + nav_select("pages", "accessibility_statement") + ) + observeEvent( + input$cookies_statement, + nav_select("pages", "cookies_statement") + ) + + ## Back links to main dashboard --------------------------------------------- + observeEvent(input$footnotes_to_dashboard, nav_select("pages", "dashboard")) + observeEvent(input$support_to_dashboard, nav_select("pages", "dashboard")) + observeEvent(input$cookies_to_dashboard, nav_select("pages", "dashboard")) + observeEvent( + input$accessibility_to_dashboard, + nav_select("pages", "dashboard") + ) + + # Update title ============================================================== + # This changes the title based on the tab selections and is important for accessibility + # On the main dashboard it uses the active tab from left_nav, else it uses the page input + observe({ + if (input$pages == "dashboard") { + change_window_title( + title = paste0(site_title, " - ", gsub("_", " ", input$left_nav)) + ) + } else { + change_window_title( + title = paste0(site_title, " - ", gsub("_", " ", input$pages)) + ) + } + }) +} diff --git a/inst/ui_template.r b/inst/ui_template.r new file mode 100644 index 00000000..21d936f5 --- /dev/null +++ b/inst/ui_template.r @@ -0,0 +1,120 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# This is the ui file. Use it to call elements created in your server file into +# the app, and define where they are placed, and define any user inputs. +# +# Other elements like charts, navigation bars etc. are completely up to you to +# decide what goes in. However, every element should meet accessibility +# requirements and user needs. +# +# This is the user-interface definition of a Shiny web application. You can +# run the application by clicking 'Run App' above. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ui <- function(input, output, session) { + page_fluid( + # Metadata for app ======================================================== + tags$html(lang = "en"), + tags$head(HTML(paste0("", site_title, ""))), # set in global.R + tags$head(tags$link(rel = "shortcut icon", href = "dfefavicon.png")), + # Add meta description for search engines + metathis::meta() %>% + meta_general( + application_name = site_title, + description = "Interactive tool for exploring data", + robots = "index,follow", + generator = "R Shiny", + subject = "education", + rating = "General", + referrer = "no-referrer" + ), + + # Required to make the title update based on tab changes + shinytitle::use_shiny_title(), + + ## Custom CSS ------------------------------------------------------------- + tags$head( + tags$link( + rel = "stylesheet", + type = "text/css", + href = "dfe_shiny_gov_style.css" + ) + ), + + ## Custom disconnect function --------------------------------------------- + dfeshiny::custom_disconnect_message( + links = site_primary, + publication_name = parent_pub_name, + publication_link = parent_publication + ), + tags$head(includeHTML(("google-analytics.html"))), + shinyjs::useShinyjs(), + dfeshiny::dfe_cookies_script(), + dfeshiny::cookies_banner_ui( + name = site_title + ), + + ## Header ----------------------------------------------------------------- + dfeshiny::header( + header = site_title + ), + + ## Beta banner ------------------------------------------------------------ + shinyGovstyle::banner( + "gds_phase_banner", + "Alpha", + paste0( + "This dashboard is being developed, contact", + team_email, + " with any feedback" + ) + ), + + # Page navigation ========================================================= + # This switches between the supporting pages in the footer and the main dashboard + gov_main_layout( + bslib::navset_hidden( + id = "pages", + nav_panel( + "dashboard", + ## Main dashboard --------------------------------------------------- + layout_columns( + # Override default wrapping breakpoints to avoid text overlap + col_widths = breakpoints(sm = c(4, 8), md = c(3, 9), lg = c(2, 9)), + ## Left navigation ------------------------------------------------ + dfe_contents_links( + links_list = c( + "Panel 1", + "User guide" + ) + ), + ## Dashboard panels ----------------------------------------------- + bslib::navset_hidden( + id = "left_nav", + nav_panel( + "panel_1", + prov_breakdowns_ui(id = "panel_1") + ), + nav_panel("user_guide", user_guide()) + ) + ) + ), + ## Footer pages ------------------------------------------------------- + nav_panel("footnotes", footnotes_page()), + nav_panel("support", support_page()), + nav_panel("accessibility_statement", accessibility_page()), + nav_panel("cookies_statement", cookies_page()) + ) + ), + + # Footer ================================================================== + dfe_footer( + links_list = c( + "Footnotes", + "Support", + "Accessibility statement", + "Cookies statement" + ) + ) + ) +} diff --git a/man/create_dashboard.Rd b/man/create_dashboard.Rd index ea472aeb..621475dc 100644 --- a/man/create_dashboard.Rd +++ b/man/create_dashboard.Rd @@ -6,8 +6,8 @@ \usage{ create_dashboard( path = "./", - dashboard_title = "dfeshiny template", - google_analytics_key = "XXXXXXXXX", + site_title = "dfeshiny template", + google_analytics_key = "XXXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", parent_pub_name = "Publication name", parent_publication = @@ -22,7 +22,7 @@ create_dashboard( \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} -\item{dashboard_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} diff --git a/man/dfe_contents_links.Rd b/man/dfe_contents_links.Rd new file mode 100644 index 00000000..fa8f050a --- /dev/null +++ b/man/dfe_contents_links.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/dfe_content_links.R +\name{dfe_contents_links} +\alias{dfe_contents_links} +\title{Content links} +\usage{ +dfe_contents_links(links_list) +} +\arguments{ +\item{links_list}{List of links for the navigation panel} +} +\description{ +Content links for the right hand navigation list panel +} diff --git a/man/init_analytics.Rd b/man/init_analytics.Rd index 01dcdc05..e0bb219f 100644 --- a/man/init_analytics.Rd +++ b/man/init_analytics.Rd @@ -4,11 +4,13 @@ \alias{init_analytics} \title{init_analytics} \usage{ -init_analytics(ga_code, create_file = TRUE) +init_analytics(ga_code, path = "./", create_file = TRUE) } \arguments{ \item{ga_code}{The Google Analytics code for the dashboard} +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} + \item{create_file}{Boolean TRUE or FALSE, default is TRUE, false will return the HTML in the console and is used mainly for testing or comparisons} } diff --git a/man/init_base_app.Rd b/man/init_base_app.Rd index f5976cc1..0aa4334b 100644 --- a/man/init_base_app.Rd +++ b/man/init_base_app.Rd @@ -25,6 +25,8 @@ init_base_app( \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} diff --git a/man/init_commit_hooks.Rd b/man/init_commit_hooks.Rd index 96af74e6..7417e94d 100644 --- a/man/init_commit_hooks.Rd +++ b/man/init_commit_hooks.Rd @@ -4,7 +4,10 @@ \alias{init_commit_hooks} \title{Initialize Git Pre-Commit Hook for a Shiny App} \usage{ -init_commit_hooks() +init_commit_hooks(path = "./") +} +\arguments{ +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} } \value{ No return value. The function installs the pre-commit hook. diff --git a/man/init_global.Rd b/man/init_global.Rd index 72e1f9f7..24657b00 100644 --- a/man/init_global.Rd +++ b/man/init_global.Rd @@ -15,7 +15,8 @@ init_global( "publication-name"), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "" + feedback_form_url = "", + verbose = FALSE ) } \arguments{ @@ -24,6 +25,8 @@ init_global( \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} diff --git a/man/init_server.Rd b/man/init_server.Rd index f45a6946..008bc0ef 100644 --- a/man/init_server.Rd +++ b/man/init_server.Rd @@ -4,13 +4,10 @@ \alias{init_server} \title{Initialise server.R} \usage{ -init_server(path = ".", team_email = "team.name@education.gov.uk") +init_server(path = ".", verbose = FALSE) } \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} - -\item{team_email}{Email address for support contact. String, default: -\code{"explore.statistics@education.gov.uk"}} } \description{ Initialise server.R diff --git a/man/init_ui.Rd b/man/init_ui.Rd index 136ba246..8773009d 100644 --- a/man/init_ui.Rd +++ b/man/init_ui.Rd @@ -4,13 +4,10 @@ \alias{init_ui} \title{Initialise ui.R} \usage{ -init_ui(path = ".", team_email = "team.name@education.gov.uk") +init_ui(path = ".", verbose = FALSE) } \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} - -\item{team_email}{Email address for support contact. String, default: -\code{"explore.statistics@education.gov.uk"}} } \description{ Initialise ui.R diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd index c8d57aec..9f8b7c3b 100644 --- a/man/init_workflow.Rd +++ b/man/init_workflow.Rd @@ -4,11 +4,12 @@ \alias{init_workflow} \title{Initialize GitHub Actions Workflow for Shiny App Deployment} \usage{ -init_workflow(dashboard_name) +init_workflow(site_title, path = "./") } \arguments{ -\item{dashboard_name}{A character string specifying the dashboard name. -default value is \code{"dfe-shiny-template"}.} +\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} + +\item{path}{The root directory where the app should be created. String, default: \code{"."}.} } \value{ No return value. The function sets up the workflow and configuration. From 1d2baa2901ddba1f14314beda97808b6cef6840b Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Fri, 25 Apr 2025 14:31:20 +0100 Subject: [PATCH 10/15] Updated content links docs --- NAMESPACE | 2 +- R/dfe_content_links.R | 5 +++-- inst/ui_template.r | 2 +- man/{dfe_contents_links.Rd => dfe_content_links.Rd} | 9 ++++++--- 4 files changed, 11 insertions(+), 7 deletions(-) rename man/{dfe_contents_links.Rd => dfe_content_links.Rd} (66%) diff --git a/NAMESPACE b/NAMESPACE index ceb652b0..c3125ecd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,7 +8,7 @@ export(cookies_panel_server) export(cookies_panel_ui) export(create_dashboard) export(custom_disconnect_message) -export(dfe_contents_links) +export(dfe_content_links) export(dfe_cookies_script) export(dfe_reactable) export(external_link) diff --git a/R/dfe_content_links.R b/R/dfe_content_links.R index e3e22723..b7d0cdeb 100644 --- a/R/dfe_content_links.R +++ b/R/dfe_content_links.R @@ -5,11 +5,12 @@ #' #' @param links_list List of links for the navigation panel #' -#' @returns +#' @returns NULL #' @export #' #' @examples -dfe_contents_links <- function(links_list) { +#' dfe_content_links(c("Data", "Information")) +dfe_content_links <- function(links_list) { # Add the HTML around the link and make an id by snake casing create_sidelink <- function(link_text) { tags$li( diff --git a/inst/ui_template.r b/inst/ui_template.r index 21d936f5..6b9f6db2 100644 --- a/inst/ui_template.r +++ b/inst/ui_template.r @@ -82,7 +82,7 @@ ui <- function(input, output, session) { # Override default wrapping breakpoints to avoid text overlap col_widths = breakpoints(sm = c(4, 8), md = c(3, 9), lg = c(2, 9)), ## Left navigation ------------------------------------------------ - dfe_contents_links( + dfe_content_links( links_list = c( "Panel 1", "User guide" diff --git a/man/dfe_contents_links.Rd b/man/dfe_content_links.Rd similarity index 66% rename from man/dfe_contents_links.Rd rename to man/dfe_content_links.Rd index fa8f050a..593daf19 100644 --- a/man/dfe_contents_links.Rd +++ b/man/dfe_content_links.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/dfe_content_links.R -\name{dfe_contents_links} -\alias{dfe_contents_links} +\name{dfe_content_links} +\alias{dfe_content_links} \title{Content links} \usage{ -dfe_contents_links(links_list) +dfe_content_links(links_list) } \arguments{ \item{links_list}{List of links for the navigation panel} @@ -12,3 +12,6 @@ dfe_contents_links(links_list) \description{ Content links for the right hand navigation list panel } +\examples{ +dfe_content_links(c("Data", "Information")) +} From 936e5658d6967a748b3bab0fe7400100f7880818 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Tue, 29 Apr 2025 08:48:01 +0100 Subject: [PATCH 11/15] ui_template updates --- inst/ui_template.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/ui_template.r b/inst/ui_template.r index 6b9f6db2..1fcc622a 100644 --- a/inst/ui_template.r +++ b/inst/ui_template.r @@ -93,7 +93,7 @@ ui <- function(input, output, session) { id = "left_nav", nav_panel( "panel_1", - prov_breakdowns_ui(id = "panel_1") + dashboard_page(id = "panel_1") ), nav_panel("user_guide", user_guide()) ) From e755b65465b4129bb8934ffb7f2bc7584ca41655 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Fri, 2 May 2025 12:47:22 +0100 Subject: [PATCH 12/15] Adjusting parameter definitions --- R/cookies.R | 31 +++++++++++++++++++++---------- R/create_dashboard.R | 13 +++++-------- R/custom_disconnect_message.R | 6 ++++++ R/dfe_content_links.R | 6 +++--- man/cookies_banner_server.Rd | 4 ++-- man/cookies_banner_ui.Rd | 7 +++++-- man/cookies_panel_server.Rd | 4 ++-- man/cookies_panel_ui.Rd | 4 ++-- man/create_dashboard.Rd | 11 +---------- man/custom_disconnect_message.Rd | 10 ++++++++++ man/init_base_app.Rd | 2 +- man/init_global.Rd | 2 +- man/init_server.Rd | 2 ++ man/init_ui.Rd | 2 ++ 14 files changed, 63 insertions(+), 41 deletions(-) diff --git a/R/cookies.R b/R/cookies.R index 90a72ca5..c8cfae94 100644 --- a/R/cookies.R +++ b/R/cookies.R @@ -85,14 +85,25 @@ dfe_cookies_script <- function() { #' #' @param id Shiny tag shared with cookies_banner_server(), can be any string set #' by the user as long as it matches the id in the cookies_banner_server() +#' @inheritParams create_dashboard #' @param name Name of the dashboard on which the cookie authorisation is being -#' applied +#' applied (deprecated, replaced by site_title) #' #' @family cookies #' @return shiny::tags$div() #' @export #' @inherit cookies examples -cookies_banner_ui <- function(id = "cookies_banner", name = "DfE R-Shiny dashboard template") { +cookies_banner_ui <- function( + id = "cookies_banner", + site_title = "DfE R-Shiny dashboard template", + name = NULL + ) { + if(!is.null(name) & site_title == "DfE R-Shiny dashboard template"){ + warning( + "The use of name as a parameter in cookies_banner_ui is deprecated. Please use site_title." + ) + site_title <- name + } shiny::tags$div( id = shiny::NS(id, "cookies_div"), class = "govuk-cookie-banner", @@ -107,7 +118,7 @@ cookies_banner_ui <- function(id = "cookies_banner", name = "DfE R-Shiny dashboa class = "govuk-grid-column-two-thirds", shiny::tags$h2( class = "govuk-cookie-banner__heading govuk-heading-m", - name + site_title ), shiny::tags$div( class = "govuk-cookie-banner__content", @@ -157,12 +168,11 @@ cookies_banner_ui <- function(id = "cookies_banner", name = "DfE R-Shiny dashboa #' be `reactive(input$cookies)`) #' @param parent_session This should be the R Shiny app session, expect it to #' always be `parent_session = session` -#' @param google_analytics_key Provide the GA 10 digit key of the form -#' "ABCDE12345" #' @param cookies_link_panel name of the navigation panel that the cookie banner #' provides a link to, usually "cookies_panel_ui" #' @param cookies_nav_id ID of the navigation panel the cookie panel page is #' within, defaults to "navlistPanel" +#' @inheritParams create_dashboard #' #' @family cookies #' @return NULL @@ -341,15 +351,17 @@ Shiny.addCustomMessageHandler('analytics-consent', function(msg){ #' #' @param id Shiny tag shared with cookies_panel_server(), can be any string set by #' the user as long as it matches the id in the cookies_panel_server() -#' @param google_analytics_key Provide the GA 10 digit key of the form -#' "ABCDE12345" +#' @inheritParams create_dashboard #' #' @family cookies #' @return a HTML div, containing standard cookies content for a public R #' Shiny dashboard in DfE #' @export #' @inherit cookies examples -cookies_panel_ui <- function(id = "cookies_panel", google_analytics_key = NULL) { +cookies_panel_ui <- function( + id = "cookies_panel", + google_analytics_key = NULL + ) { shiny::tags$div( style = "margin-top: 50px; margin-bottom: 50px;", shiny::tags$h1("Cookies"), @@ -439,8 +451,7 @@ cookies_panel_ui <- function(id = "cookies_panel", google_analytics_key = NULL) #' the user as long as it matches the id in the cookies_panel_ui() #' @param input_cookies The cookie input passed from cookies.js (should always #' be `reactive(input$cookies)`) -#' @param google_analytics_key Provide the GA 10 digit key of the form -#' "ABCDE12345" +#' @inheritParams create_dashboard #' #' @family cookies #' @export diff --git a/R/create_dashboard.R b/R/create_dashboard.R index fc296189..ed0d631d 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -8,20 +8,17 @@ #' @param path The root directory where the app should be created. String, default: `"."`. #' @param google_analytics_key 10 digit Google Analytics key if available. String, default: #' `"XXXXXXXXXX"` -#' @param publication_name The name of the parent publication. String, default: -#' `"Publication name"` -#' @param publication_link Full URL for the publication on Explore Education. String, default: ` -#' "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name"` -#' Statistics -#' @param site_title Site title for the dashboard. String, default: `"Shiny template"` -#' @param dashboard_link Full URL of the dashboard. String, default: -#' `"https://department-for-education.shinyapps.io/shiny-template/"` +#' @param site_title Site title for the dashboard. String, default: `"dfeshiny template"` #' @param team_email Email address for support contact. String, default: #' `"explore.statistics@@education.gov.uk"` #' @param repo_name The repository URL, must be a valid URL for the dfe-analytical-services GitHub #' area or the dfe-gov-uk Azure DevOps. String, default: #' `"https://github.com/dfe-analytical-services/dfeshiny"` #' @param feedback_form_url +#' @param dashboard_url +#' @param parent_pub_name +#' @param parent_publication +#' @param verbose #' #' @details This function runs `init_app()`, `init_commit_hooks()`, and #' `init_workflow()` diff --git a/R/custom_disconnect_message.R b/R/custom_disconnect_message.R index 878d107f..74b6fad2 100644 --- a/R/custom_disconnect_message.R +++ b/R/custom_disconnect_message.R @@ -8,6 +8,12 @@ #' @param reset the text to appear that will reset the page when clicked #' @param links A vector of possible URLs for the public site. Should mostly just be a single URL, #' but can be two URLs if an overflow site has been set up +#' @param publication_name The parent publication name +#' @param publication_link The link to the publication on Explore Education +#' Statistics +#' @param dashboard_title Title of the dashboard +#' @param support_contact Email address for support contact, defaults to +#' explore.statistics@@education.gov.uk #' @param custom_refresh Custom refresh link, defaults to refreshing the page, main value is if you #' have bookmarking enabled and want the refresh to send to the initial view instead of reloading #' any bookmarks diff --git a/R/dfe_content_links.R b/R/dfe_content_links.R index b7d0cdeb..f6e60e06 100644 --- a/R/dfe_content_links.R +++ b/R/dfe_content_links.R @@ -14,8 +14,8 @@ dfe_content_links <- function(links_list) { # Add the HTML around the link and make an id by snake casing create_sidelink <- function(link_text) { tags$li( - "—", - actionLink( + "-", + shiny::actionLink( tolower(gsub(" ", "_", link_text)), link_text, `data-value` = link_text, @@ -27,7 +27,7 @@ dfe_content_links <- function(links_list) { # The HTML div to be returned tags$div( style = "position: sticky; top: 0.5rem; padding: 0.25rem;", # Make it stick! - h2("Contents"), + shiny::tags$h2("Contents"), tags$ul( id = "contents_links", style = "list-style-type: none; padding-left: 0; font-size: 1rem;", # remove the circle bullets diff --git a/man/cookies_banner_server.Rd b/man/cookies_banner_server.Rd index 52188cd0..fac4b95c 100644 --- a/man/cookies_banner_server.Rd +++ b/man/cookies_banner_server.Rd @@ -23,8 +23,8 @@ be \code{reactive(input$cookies)})} \item{parent_session}{This should be the R Shiny app session, expect it to always be \code{parent_session = session}} -\item{google_analytics_key}{Provide the GA 10 digit key of the form -"ABCDE12345"} +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} \item{cookies_link_panel}{name of the navigation panel that the cookie banner provides a link to, usually "cookies_panel_ui"} diff --git a/man/cookies_banner_ui.Rd b/man/cookies_banner_ui.Rd index cbae8af7..14206264 100644 --- a/man/cookies_banner_ui.Rd +++ b/man/cookies_banner_ui.Rd @@ -6,15 +6,18 @@ \usage{ cookies_banner_ui( id = "cookies_banner", - name = "DfE R-Shiny dashboard template" + site_title = "DfE R-Shiny dashboard template", + name = NULL ) } \arguments{ \item{id}{Shiny tag shared with cookies_banner_server(), can be any string set by the user as long as it matches the id in the cookies_banner_server()} +\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} + \item{name}{Name of the dashboard on which the cookie authorisation is being -applied} +applied (deprecated, replaced by site_title)} } \value{ shiny::tags$div() diff --git a/man/cookies_panel_server.Rd b/man/cookies_panel_server.Rd index 223b7206..43879b04 100644 --- a/man/cookies_panel_server.Rd +++ b/man/cookies_panel_server.Rd @@ -17,8 +17,8 @@ the user as long as it matches the id in the cookies_panel_ui()} \item{input_cookies}{The cookie input passed from cookies.js (should always be \code{reactive(input$cookies)})} -\item{google_analytics_key}{Provide the GA 10 digit key of the form -"ABCDE12345"} +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} } \description{ Create the server module of DfE R-Shiny cookies dashboard panel to be used diff --git a/man/cookies_panel_ui.Rd b/man/cookies_panel_ui.Rd index 11345b9f..03c7cfbd 100644 --- a/man/cookies_panel_ui.Rd +++ b/man/cookies_panel_ui.Rd @@ -10,8 +10,8 @@ cookies_panel_ui(id = "cookies_panel", google_analytics_key = NULL) \item{id}{Shiny tag shared with cookies_panel_server(), can be any string set by the user as long as it matches the id in the cookies_panel_server()} -\item{google_analytics_key}{Provide the GA 10 digit key of the form -"ABCDE12345"} +\item{google_analytics_key}{10 digit Google Analytics key if available. String, default: +\code{"XXXXXXXXXX"}} } \value{ a HTML div, containing standard cookies content for a public R diff --git a/man/create_dashboard.Rd b/man/create_dashboard.Rd index 621475dc..a03fbc9b 100644 --- a/man/create_dashboard.Rd +++ b/man/create_dashboard.Rd @@ -34,16 +34,7 @@ create_dashboard( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} -\item{feedback_form_url}{} - -\item{publication_name}{The name of the parent publication. String, default: -\code{"Publication name"}} - -\item{publication_link}{Full URL for the publication on Explore Education. String, default: \code{ "https://explore-education-statistics.service.gov.uk/find-statistics/publication-name"} -Statistics} - -\item{dashboard_link}{Full URL of the dashboard. String, default: -\code{"https://department-for-education.shinyapps.io/shiny-template/"}} +\item{verbose}{} } \value{ No return value. The function initializes the complete template. diff --git a/man/custom_disconnect_message.Rd b/man/custom_disconnect_message.Rd index 988467ea..a3dd4846 100644 --- a/man/custom_disconnect_message.Rd +++ b/man/custom_disconnect_message.Rd @@ -21,9 +21,19 @@ custom_disconnect_message( \item{reset}{the text to appear that will reset the page when clicked} +\item{dashboard_title}{Title of the dashboard} + \item{links}{A vector of possible URLs for the public site. Should mostly just be a single URL, but can be two URLs if an overflow site has been set up} +\item{publication_name}{The parent publication name} + +\item{publication_link}{The link to the publication on Explore Education +Statistics} + +\item{support_contact}{Email address for support contact, defaults to +explore.statistics@education.gov.uk} + \item{custom_refresh}{Custom refresh link, defaults to refreshing the page, main value is if you have bookmarking enabled and want the refresh to send to the initial view instead of reloading any bookmarks} diff --git a/man/init_base_app.Rd b/man/init_base_app.Rd index 0aa4334b..ad05853c 100644 --- a/man/init_base_app.Rd +++ b/man/init_base_app.Rd @@ -34,7 +34,7 @@ init_base_app( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} -\item{feedback_form_url}{} +\item{verbose}{} } \value{ No return value. The function is called for diff --git a/man/init_global.Rd b/man/init_global.Rd index 24657b00..d52b122d 100644 --- a/man/init_global.Rd +++ b/man/init_global.Rd @@ -34,7 +34,7 @@ init_global( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} -\item{feedback_form_url}{} +\item{verbose}{} } \description{ Initialise global.R diff --git a/man/init_server.Rd b/man/init_server.Rd index 008bc0ef..ca90413f 100644 --- a/man/init_server.Rd +++ b/man/init_server.Rd @@ -8,6 +8,8 @@ init_server(path = ".", verbose = FALSE) } \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{verbose}{} } \description{ Initialise server.R diff --git a/man/init_ui.Rd b/man/init_ui.Rd index 8773009d..7489260d 100644 --- a/man/init_ui.Rd +++ b/man/init_ui.Rd @@ -8,6 +8,8 @@ init_ui(path = ".", verbose = FALSE) } \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} + +\item{verbose}{} } \description{ Initialise ui.R From fcca0b3ff9a2b87e9fd0a3048c2e489e0fbfbade Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 7 May 2025 13:27:53 +0100 Subject: [PATCH 13/15] Unifying a few parameters between create dashboard and other functions --- R/a11y_panel.R | 98 +++++++++++++++++++++++++--------------- R/create_dashboard.R | 44 +++++++++--------- R/support_panel.R | 31 +++++++------ man/cookies_banner_ui.Rd | 2 +- man/create_dashboard.Rd | 14 ++++-- man/init_base_app.Rd | 14 ++++-- man/init_global.Rd | 14 ++++-- man/init_workflow.Rd | 2 +- 8 files changed, 133 insertions(+), 86 deletions(-) diff --git a/R/a11y_panel.R b/R/a11y_panel.R index 0e4c1cd6..cc7015d2 100644 --- a/R/a11y_panel.R +++ b/R/a11y_panel.R @@ -9,7 +9,6 @@ #' [GDS model accessibility statement](https://www.gov.uk/guidance/model-accessibility-statement) #' #' @param dashboard_title Title of the host dashboard -#' @param dashboard_url URL for the host dashboard #' @param issues_contact URL for the GitHub Issues log or contact e-mail address #' for users to flag accessibility issues #' @param publication_name The parent publication name (optional) @@ -23,6 +22,7 @@ #' @param date_reviewed Date the statement was last reviewed #' @param date_template_reviewed Date the underlying template was reviewed #' (default: 12th March 2024) +#' @inheritParams create_dashboard #' #' @return shiny$tags$div element containing the HTML tags and content for the standard #' accessibility statement @@ -40,25 +40,26 @@ #' publication_name = "LA and school expenditure" #' ) a11y_panel <- function( - dashboard_title, - dashboard_url, - date_tested, - date_prepared, - date_reviewed, - date_template_reviewed = "12 March 2024", - issues_contact = NULL, - publication_name = NULL, - publication_slug = NULL, - non_accessible_components = c( - "Keyboard navigation through the interactive charts is currently limited", - "Alternative text in interactive charts is limited to titles" - ), - specific_issues = c( - "Charts have non-accessible components that are inaccessible for keyboard users.", - "Chart tooltips are not compatible with screen reader use.", - "Some decorative images are not labelled appropriately as yet.", - "Some links are not appropriately labelled." - )) { + dashboard_title, + dashboard_url, + date_tested, + date_prepared, + date_reviewed, + date_template_reviewed = "12 March 2024", + issues_contact = NULL, + publication_name = NULL, + publication_slug = NULL, + non_accessible_components = c( + "Keyboard navigation through the interactive charts is currently limited", + "Alternative text in interactive charts is limited to titles" + ), + specific_issues = c( + "Charts have non-accessible components that are inaccessible for keyboard users.", + "Chart tooltips are not compatible with screen reader use.", + "Some decorative images are not labelled appropriately as yet.", + "Some links are not appropriately labelled." + ) +) { # Validate inputs date_tested <- validate_date(date_tested) date_prepared <- validate_date(date_prepared) @@ -67,22 +68,31 @@ a11y_panel <- function( validate_dashboard_url(dashboard_url) if ( lubridate::interval( - lubridate::dmy(date_prepared), lubridate::dmy(date_reviewed) - ) / lubridate::days(1) < 0 + lubridate::dmy(date_prepared), + lubridate::dmy(date_reviewed) + ) / + lubridate::days(1) < + 0 ) { stop("date_reviewed should be later than date_prepared") } if ( lubridate::interval( - lubridate::dmy(date_tested), lubridate::dmy(date_reviewed) - ) / lubridate::days(1) < 0 + lubridate::dmy(date_tested), + lubridate::dmy(date_reviewed) + ) / + lubridate::days(1) < + 0 ) { stop("date_reviewed should be later than date_tested") } if ( lubridate::interval( - lubridate::dmy(date_template_reviewed), lubridate::dmy(date_reviewed) - ) / lubridate::days(1) < 0 + lubridate::dmy(date_template_reviewed), + lubridate::dmy(date_reviewed) + ) / + lubridate::days(1) < + 0 ) { warning( "The template has been through a review more recently than your dashboard, please get in ", @@ -101,10 +111,14 @@ a11y_panel <- function( } } if (is.null(publication_name) && !is.null(publication_slug)) { - stop("Error: If publication_name is provided, then so should publication_slug.") + stop( + "Error: If publication_name is provided, then so should publication_slug." + ) } if (!is.null(publication_name) && is.null(publication_slug)) { - stop("Error: If publication_slug is provided, then so should publication_name.") + stop( + "Error: If publication_slug is provided, then so should publication_name." + ) } shiny::tags$div( style = "margin-top: 50px; margin-bottom: 50px", @@ -140,17 +154,23 @@ a11y_panel <- function( (including the most recent versions of JAWS, NVDA and VoiceOver)" ) )), - shiny::tags$p("We've also made the website text as simple as possible to understand."), + shiny::tags$p( + "We've also made the website text as simple as possible to understand." + ), shiny::tags$p( external_link(href = "https://mcmw.abilitynet.org.uk/", "AbilityNet"), " has advice on making your device easier to use if you have a disability." ), shiny::tags$h2("How accessible this website is"), if (all(is.null(non_accessible_components))) { - shiny::tags$p("This website is fully compliant with accessibility standards.") + shiny::tags$p( + "This website is fully compliant with accessibility standards." + ) } else { shiny::tagList( - shiny::tags$p("We know some parts of this website are not fully accessible:"), + shiny::tags$p( + "We know some parts of this website are not fully accessible:" + ), shiny::tags$div(tags$ol( tagList(lapply(non_accessible_components, shiny::tags$li)) )) @@ -177,9 +197,11 @@ a11y_panel <- function( ) ) }, - shiny::tags$p("We're always looking to improve the accessibility of this website. + shiny::tags$p( + "We're always looking to improve the accessibility of this website. If you find any problems not listed on this page or think we're not meeting - accessibility requirements, contact us:"), + accessibility requirements, contact us:" + ), shiny::tags$ul(tags$li( shiny::tags$a( href = "mailto:explore.statistics@education.gov.uk", @@ -227,8 +249,10 @@ a11y_panel <- function( " due to the non-compliances listed below." ), shiny::tags$h3("Non accessible content"), - shiny::tags$p("The content listed below is non-accessible for the following reasons. - We will address these issues to ensure our content is accessible."), + shiny::tags$p( + "The content listed below is non-accessible for the following reasons. + We will address these issues to ensure our content is accessible." + ), shiny::tags$div(tags$ol( tagList(lapply(specific_issues, shiny::tags$li)) )) @@ -261,7 +285,9 @@ a11y_panel <- function( shiny::tags$li("charts, maps, and tables") )), shiny::tags$p( - "This specific website was was last tested on ", date_tested, " against ", + "This specific website was was last tested on ", + date_tested, + " against ", external_link( href = "https://www.w3.org/TR/WCAG22/", "Accessibility Guidelines WCAG2.2" diff --git a/R/create_dashboard.R b/R/create_dashboard.R index ed0d631d..4e53eb06 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -14,10 +14,10 @@ #' @param repo_name The repository URL, must be a valid URL for the dfe-analytical-services GitHub #' area or the dfe-gov-uk Azure DevOps. String, default: #' `"https://github.com/dfe-analytical-services/dfeshiny"` -#' @param feedback_form_url -#' @param dashboard_url -#' @param parent_pub_name -#' @param parent_publication +#' @param form_url URL for a feedback form for the dashboard +#' @param dashboard_url URL for the host dashboard +#' @param publication_name The parent publication name +#' @param publication_link #' @param verbose #' #' @details This function runs `init_app()`, `init_commit_hooks()`, and @@ -35,14 +35,14 @@ create_dashboard <- function( site_title = "dfeshiny template", google_analytics_key = "XXXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", - parent_pub_name = "Publication name", - parent_publication = paste0( + publication_name = "Publication name", + publication_link = paste0( "https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name" ), team_email = "explore.statistics@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dfeshiny", - feedback_form_url = "", + form_url = "", verbose = FALSE ) { message("Initializing the DFE Shiny template...") @@ -53,11 +53,11 @@ create_dashboard <- function( google_analytics_key = google_analytics_key, dashboard_url = dashboard_url, site_title = site_title, - parent_pub_name = parent_pub_name, - parent_publication = parent_publication, + publication_name = publication_name, + publication_link = publication_link, team_email = team_email, repo_name = repo_name, - feedback_form_url = feedback_form_url, + form_url = form_url, verbose = verbose ) @@ -101,14 +101,14 @@ init_base_app <- function( google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", - parent_pub_name = "Publication name", - parent_publication = paste0( + publication_name = "Publication name", + publication_link = paste0( "https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name" ), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "", + form_url = "", verbose = FALSE ) { # Create directories @@ -132,11 +132,11 @@ init_base_app <- function( google_analytics_key = google_analytics_key, dashboard_url = dashboard_url, site_title = site_title, - parent_pub_name = parent_pub_name, - parent_publication = parent_publication, + publication_name = publication_name, + publication_link = publication_link, team_email = team_email, repo_name = repo_name, - feedback_form_url = feedback_form_url, + form_url = form_url, verbose = verbose ) init_ui( @@ -165,25 +165,25 @@ init_global <- function( google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", - parent_pub_name = "Publication name", - parent_publication = paste0( + publication_name = "Publication name", + publication_link = paste0( "https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name" ), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "", + form_url = "", verbose = FALSE ) { globalr_script <- paste( c( readLines("inst/global_template.r"), paste0("site_title <- \"", site_title, "\""), - paste0("parent_pub_name <- \"", parent_pub_name, "\""), - paste0("parent_publication <- \"", parent_publication, "\""), + paste0("publication_name <- \"", publication_name, "\""), + paste0("publication_link <- \"", publication_link, "\""), paste0("team_email <- \"", team_email, "\""), paste0("repo_name <- \"", repo_name, "\""), - paste0("feedback_form_url <- \"", feedback_form_url, "\""), + paste0("form_url <- \"", form_url, "\""), "## Set the URLs that the site will be published to", paste0("site_primary <- \"", dashboard_url, "\""), diff --git a/R/support_panel.R b/R/support_panel.R index 97ee7368..50992a83 100644 --- a/R/support_panel.R +++ b/R/support_panel.R @@ -8,17 +8,16 @@ #' dfe-analytical-services GitHub area or the dfe-gov-uk Azure DevOps #' @param ees_publication Whether the parent publication is hosted on Explore #' Education Statistics -#' @param publication_name The parent publication name #' @param publication_slug The parent publication slug on Explore Education #' Statistics #' @param alt_href Alternative link to the parent publication (if not hosted on #' Explore Education Statistics) -#' @param form_url URL for a feedback form for the dashboard #' @param custom_data_info A single text string or a `shiny::tagList()` object #' for custom text to go under the "Find out more information on the data" heading. #' @param extra_text Add extra paragraphs to the page before the "Contact us" section. #' Use `dfeshiny::section_tags()` to specify the heading and body. #' Look at examples to see how to add one or multiple sections. +#' @inheritParams create_dashboard #' #' @return a HTML div, containing standard support content for a public R Shiny #' dashboard in DfE @@ -132,15 +131,16 @@ #' ) #' ) support_panel <- function( - team_email = "", - repo_name = "", - ees_publication = TRUE, - publication_name = NULL, - publication_slug = "", - alt_href = NULL, - form_url = NULL, - custom_data_info = NULL, - extra_text = NULL) { + team_email = "", + repo_name = "", + ees_publication = TRUE, + publication_name = NULL, + publication_slug = "", + alt_href = NULL, + form_url = NULL, + custom_data_info = NULL, + extra_text = NULL +) { if (is_valid_dfe_email(team_email) == FALSE) { stop( "You have entered an invalid email in the team_email argument. @@ -210,7 +210,8 @@ support_panel <- function( href = paste0("mailto:", team_email), link_text = team_email, add_warning = FALSE - ), "." + ), + "." ) ), shiny::tags$h2("Find more information on the data"), @@ -240,7 +241,8 @@ support_panel <- function( dfeshiny::external_link( href = paste0( "https://explore-education-statistics.service.gov.uk/find-statistics/", # nolint: [line_length_linter] - publication_slug, "/data-guidance" + publication_slug, + "/data-guidance" ), link_text = "data guidance" ), @@ -248,7 +250,8 @@ support_panel <- function( dfeshiny::external_link( href = paste0( "https://explore-education-statistics.service.gov.uk/find-statistics/", # nolint: [line_length_linter] - publication_slug, "#explore-data-and-files" + publication_slug, + "#explore-data-and-files" ), link_text = "tools to access and interrogate the underlying data" ), diff --git a/man/cookies_banner_ui.Rd b/man/cookies_banner_ui.Rd index 14206264..c06e69ba 100644 --- a/man/cookies_banner_ui.Rd +++ b/man/cookies_banner_ui.Rd @@ -14,7 +14,7 @@ cookies_banner_ui( \item{id}{Shiny tag shared with cookies_banner_server(), can be any string set by the user as long as it matches the id in the cookies_banner_server()} -\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"dfeshiny template"}} \item{name}{Name of the dashboard on which the cookie authorisation is being applied (deprecated, replaced by site_title)} diff --git a/man/create_dashboard.Rd b/man/create_dashboard.Rd index a03fbc9b..5d863104 100644 --- a/man/create_dashboard.Rd +++ b/man/create_dashboard.Rd @@ -9,24 +9,28 @@ create_dashboard( site_title = "dfeshiny template", google_analytics_key = "XXXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dfeshiny-template/", - parent_pub_name = "Publication name", - parent_publication = + publication_name = "Publication name", + publication_link = paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name"), team_email = "explore.statistics@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dfeshiny", - feedback_form_url = "", + form_url = "", verbose = FALSE ) } \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} -\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"dfeshiny template"}} \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} +\item{dashboard_url}{URL for the host dashboard} + +\item{publication_name}{The parent publication name} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -34,6 +38,8 @@ create_dashboard( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} +\item{form_url}{URL for a feedback form for the dashboard} + \item{verbose}{} } \value{ diff --git a/man/init_base_app.Rd b/man/init_base_app.Rd index ad05853c..522ba2ad 100644 --- a/man/init_base_app.Rd +++ b/man/init_base_app.Rd @@ -9,13 +9,13 @@ init_base_app( google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", - parent_pub_name = "Publication name", - parent_publication = + publication_name = "Publication name", + publication_link = paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name"), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "", + form_url = "", verbose = FALSE ) } @@ -25,7 +25,11 @@ init_base_app( \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} -\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{dashboard_url}{URL for the host dashboard} + +\item{site_title}{Site title for the dashboard. String, default: \code{"dfeshiny template"}} + +\item{publication_name}{The parent publication name} \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -34,6 +38,8 @@ init_base_app( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} +\item{form_url}{URL for a feedback form for the dashboard} + \item{verbose}{} } \value{ diff --git a/man/init_global.Rd b/man/init_global.Rd index d52b122d..7bc420cd 100644 --- a/man/init_global.Rd +++ b/man/init_global.Rd @@ -9,13 +9,13 @@ init_global( google_analytics_key = "XXXXXXXXX", dashboard_url = "https://department-for-education.shinyapps.io/dashboard-name/", site_title = "Dashboard name", - parent_pub_name = "Publication name", - parent_publication = + publication_name = "Publication name", + publication_link = paste0("https://explore-education-statistics.service.gov.uk/find-statistics/", "publication-name"), team_email = "team.name@education.gov.uk", repo_name = "https://github.com/dfe-analytical-services/dashboard-name", - feedback_form_url = "", + form_url = "", verbose = FALSE ) } @@ -25,7 +25,11 @@ init_global( \item{google_analytics_key}{10 digit Google Analytics key if available. String, default: \code{"XXXXXXXXXX"}} -\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{dashboard_url}{URL for the host dashboard} + +\item{site_title}{Site title for the dashboard. String, default: \code{"dfeshiny template"}} + +\item{publication_name}{The parent publication name} \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -34,6 +38,8 @@ init_global( area or the dfe-gov-uk Azure DevOps. String, default: \code{"https://github.com/dfe-analytical-services/dfeshiny"}} +\item{form_url}{URL for a feedback form for the dashboard} + \item{verbose}{} } \description{ diff --git a/man/init_workflow.Rd b/man/init_workflow.Rd index 9f8b7c3b..afca33ff 100644 --- a/man/init_workflow.Rd +++ b/man/init_workflow.Rd @@ -7,7 +7,7 @@ init_workflow(site_title, path = "./") } \arguments{ -\item{site_title}{Site title for the dashboard. String, default: \code{"Shiny template"}} +\item{site_title}{Site title for the dashboard. String, default: \code{"dfeshiny template"}} \item{path}{The root directory where the app should be created. String, default: \code{"."}.} } From f4154929ee0748957fa469c2e0a849e1d6c49794 Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 7 May 2025 13:53:34 +0100 Subject: [PATCH 14/15] Updated paths in workflow and commit hooks inits --- .github/workflows/deploy-shiny.yaml | 18 ------------------ R/create_dashboard.R | 12 ++++++++---- 2 files changed, 8 insertions(+), 22 deletions(-) delete mode 100644 .github/workflows/deploy-shiny.yaml diff --git a/.github/workflows/deploy-shiny.yaml b/.github/workflows/deploy-shiny.yaml deleted file mode 100644 index 358ca660..00000000 --- a/.github/workflows/deploy-shiny.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: Deploy Dashboard -on: - push: - branches: - - main - - development - pull_request: - branches: - - main - -jobs: - deploy: - uses: dfe-analytical-services/dfeshiny/.github/workflows/dashboard_deploy_template.yaml@main - with: - parameter_file: deploy-parameters.yaml - secrets: - SHINYAPPS_SECRET: ${{ secrets.SHINYAPPS_SECRET }} - SHINYAPPS_TOKEN: ${{ secrets.SHINYAPPS_TOKEN }} diff --git a/R/create_dashboard.R b/R/create_dashboard.R index 4e53eb06..3360f40a 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -286,6 +286,10 @@ init_commit_hooks <- function(path = "./") { # Define the destination path for the pre-commit hook hook_path <- file.path(path, ".git/hooks/pre-commit") + if (!dir.exists(hook_path)) { + dir.create(hook_path, recursive = TRUE) + message(hook_path, " directory created.") + } # Download and write the file tryCatch( @@ -322,9 +326,9 @@ init_commit_hooks <- function(path = "./") { #' @export init_workflow <- function(site_title, path = "./") { # Define paths - workflows_dir <- ".github/workflows" + workflows_dir <- file.path(path, ".github/workflows") workflow_file <- file.path(workflows_dir, "deploy-shiny.yaml") - config_file <- "deployment-config.yaml" + config_file <- file.path(path, "deployment-config.yaml") # Define GitHub workflow file URL workflow_url <- "https://raw.githubusercontent.com/dfe-analytical-services/shiny-template/main/.github/workflows/deploy-shiny.yaml" @@ -332,7 +336,7 @@ init_workflow <- function(site_title, path = "./") { # Ensure the .github/workflows directory exists if (!dir.exists(workflows_dir)) { dir.create(workflows_dir, recursive = TRUE) - message(".github/workflows directory created.") + message(workflows_dir, " directory created.") } # Download and save the workflow file @@ -354,7 +358,7 @@ init_workflow <- function(site_title, path = "./") { tryCatch( { - writeLines(yaml_content, file.path(path, config_file)) + writeLines(yaml_content, config_file) message("Deployment configuration file created successfully.") }, error = function(e) { From 73da3c4af8c7885c7f3f4cd0bfcf5c3ab084c7fc Mon Sep 17 00:00:00 2001 From: Rich Bielby Date: Wed, 7 May 2025 14:08:16 +0100 Subject: [PATCH 15/15] Added to docs for create dashboard --- R/create_dashboard.R | 4 ++-- man/create_dashboard.Rd | 4 +++- man/init_base_app.Rd | 4 +++- man/init_global.Rd | 4 +++- man/init_server.Rd | 2 +- man/init_ui.Rd | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/R/create_dashboard.R b/R/create_dashboard.R index 3360f40a..7dbdbafb 100644 --- a/R/create_dashboard.R +++ b/R/create_dashboard.R @@ -17,8 +17,8 @@ #' @param form_url URL for a feedback form for the dashboard #' @param dashboard_url URL for the host dashboard #' @param publication_name The parent publication name -#' @param publication_link -#' @param verbose +#' @param publication_link URL link to the parent publication +#' @param verbose RUn in verbose mode #' #' @details This function runs `init_app()`, `init_commit_hooks()`, and #' `init_workflow()` diff --git a/man/create_dashboard.Rd b/man/create_dashboard.Rd index 5d863104..56c7ebba 100644 --- a/man/create_dashboard.Rd +++ b/man/create_dashboard.Rd @@ -31,6 +31,8 @@ create_dashboard( \item{publication_name}{The parent publication name} +\item{publication_link}{URL link to the parent publication} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -40,7 +42,7 @@ area or the dfe-gov-uk Azure DevOps. String, default: \item{form_url}{URL for a feedback form for the dashboard} -\item{verbose}{} +\item{verbose}{RUn in verbose mode} } \value{ No return value. The function initializes the complete template. diff --git a/man/init_base_app.Rd b/man/init_base_app.Rd index 522ba2ad..0d0bb0de 100644 --- a/man/init_base_app.Rd +++ b/man/init_base_app.Rd @@ -31,6 +31,8 @@ init_base_app( \item{publication_name}{The parent publication name} +\item{publication_link}{URL link to the parent publication} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -40,7 +42,7 @@ area or the dfe-gov-uk Azure DevOps. String, default: \item{form_url}{URL for a feedback form for the dashboard} -\item{verbose}{} +\item{verbose}{RUn in verbose mode} } \value{ No return value. The function is called for diff --git a/man/init_global.Rd b/man/init_global.Rd index 7bc420cd..509f25a0 100644 --- a/man/init_global.Rd +++ b/man/init_global.Rd @@ -31,6 +31,8 @@ init_global( \item{publication_name}{The parent publication name} +\item{publication_link}{URL link to the parent publication} + \item{team_email}{Email address for support contact. String, default: \code{"explore.statistics@education.gov.uk"}} @@ -40,7 +42,7 @@ area or the dfe-gov-uk Azure DevOps. String, default: \item{form_url}{URL for a feedback form for the dashboard} -\item{verbose}{} +\item{verbose}{RUn in verbose mode} } \description{ Initialise global.R diff --git a/man/init_server.Rd b/man/init_server.Rd index ca90413f..4c50a576 100644 --- a/man/init_server.Rd +++ b/man/init_server.Rd @@ -9,7 +9,7 @@ init_server(path = ".", verbose = FALSE) \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} -\item{verbose}{} +\item{verbose}{RUn in verbose mode} } \description{ Initialise server.R diff --git a/man/init_ui.Rd b/man/init_ui.Rd index 7489260d..baebaae1 100644 --- a/man/init_ui.Rd +++ b/man/init_ui.Rd @@ -9,7 +9,7 @@ init_ui(path = ".", verbose = FALSE) \arguments{ \item{path}{The root directory where the app should be created. String, default: \code{"."}.} -\item{verbose}{} +\item{verbose}{RUn in verbose mode} } \description{ Initialise ui.R