2 App Structure
2.1 Read the required documentation
Before learning how the app is structured you need to have a basic comprehension of Shiny and the Golem framework. Please read the following:
-
Mastering Shiny: A comprehensive book on Shiny. It contains almost all the information you need to interact with the Shiny part of Teachvatory. I recommend starting with Chapters 1 to 4 if you have not had any experience with Shiny before. If you already know some Shiny, feel free to skip those chapters.
- Chapters 1 to 8 (Required)
- Chapter 10 (Required)
- Chapters 12 (Required)
- Chapter 13 and 14 (Recommended)
- Chapters 19 and 20 (Required).
-
Engineering Production-Grade Shiny Apps: This is the book to understand our app’s structure. Teachvatory is built using the Golem Framework, which is explained in detail in this book. Do not continue reading the documentation before learning about Golem - it would make your learning process much harder. To understand Teachvatory you won’t need to read all the chapters - with the following list you will be ok:
- Chapters 3 and 4: Introduce Golem. (Required)
- Chapter 8: Explains how to create a Golem app from scratch. Although we will not be creating a new application, I think it is important that you understand what each configuration file does. (Required)
- Chapter 10: Explains how to develop your app using Golem’s functions. (Required)
Once you have read the required chapters we are ready to go into our app’s structure.
2.2 Teachvatory code structure
Teachvatory follows the Golem Framework. This means that all the files are organized and named following the Golem conventions (which, at the same time, follows the .R package conventions). (If you have not read Chapter 4 of Engineering Production-Grade Shiny apps yet, this is a good time to do it).
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── R
│ ├── _disable_autoload.R
│ ├── app_config.R
│ ├── app_server.R
│ ├── app_ui.R
│ ├── fct_driveaccess.R
│ ├── fct_polishedauth.R
│ ├── globalvars.R
│ ├── mod_conventions.R
│ ├── mod_metrics.R
│ ├── mod_metrics_fct_logic.R
│ ├── mod_quiz.R
│ ├── mod_quiz_questionviz.R
│ ├── mod_quiz_questionviz_fct_graphs.R
│ ├── mod_quiz_questionviz_fct_uidynamic.R
│ ├── mod_quiz_fct_logic.R
│ ├── mod_roster.R
│ └── run_app.R
├── README.Rmd
├── README.md
├── app.R
├── config.yml
├── dev
│ ├── 01_start.R
│ ├── 02_dev.R
│ ├── 03_deploy.R
│ ├── googledrive_auth.R
│ └── run_dev.R
├── inst
│ ├── app
│ │ └── www
│ │ ├── favicon.ico
│ │ └── img
│ │ ├── logo_dark_background.png
│ │ ├── logo_white_background.png
│ │ ├── logosymbol_dark_background.png
│ │ └── logosymbol_white_background.png
│ └── golem-config.yml
├── man
│ ├── chart_multiplechoise_multiple.Rd
│ ├── (...)
├── rsconnect
│ └── shinyapps.io
│ └── gonzalojara
│ └── teachvatory.dcf
├── teachvatory.Rproj
└── tests
├── testthat
│ ├── test-mod_quiz_questionviz.R
│ └── (...)
└── testthat.R
2.2.1 ./
DESCRIPTIONcontains the package information such as title, description, author, and app version. No need to change it.LICENSEand theLICENSE.mdfiles define the app licences. No need to change them.NAMESPACEis an autogenerated file that contains the packages dependecies. You should never edit it by hand. The file is automatically updated when a new package is added withusethis::use_package("package-name")and referenced in the app usingimportorpackage-name::func().README.mdandREADME.rmdare used to create a landing page at the GitHub page.-
./config.ymlcontains the private variables that are needed in the app. It also allows to use.Rwhen preceding the expresion with!expr. In this example, the app is calling for the private variablesPOLISED_APP_NAMEandPOLISHED_API_KEYthat are defined in our.Renvironfile.default: polished_app_name: !expr Sys.getenv("POLISHED_APP_NAME") polished_api_key: !expr Sys.getenv("POLISHED_API_KEY")
2.2.2 .R/
All the .R files that defines the application logic are located in the R/ folder. Inside these files you will find the content of your modules (created with golem::add_modules()), and the utilitarian and business functions (created with golem::add_utils()and golem::add_fct()).
-
_disable_autoload.Ris an autogerated file to disable the autoload of shinyapps.io. No need to change it. -
app_config.Rcontains the mechanics for golem. You do not need to modify this file. -
app_server.Ris the main server configuration. In this file the app handles the user interaction with the navigation bars, load the MasterQuiz metadata, and the Roster file. It is also where the app call to the modules’ server function. -
app_ui.Ris the main UI configuration. In this file you can change the dashboard left, right, top, and bottom navigation bar. It also calls the modules’ UIs. -
fct_driveraccess.Randfct_polishedauthcontains functions to interact with Google Drive Files and the Polished authentication systems, respectively. (Note that because these are business-specific functions, the.Rfiles start withfct_). -
global_vars.Rdefines variables that are used in the app like the Dashboard URL, or the name used in the quizes to identify a student. You should never put private variables, like the API keys, here. -
mod_conventions.R,mod_metrics.R,mod_quiz.R, andmod_roster.Rare the main modules of the app. These modules contains the UI and server functions for each of the sections that you see in the left navigation bar. -
mod_metrics_fct_logic.Randmod_quiz_fct_logic.Rare two business-specific functions used inmod_metrics.Randmod_quiz.R, respectively. -
mod_quiz_questinviz.Ris a module that is called inside themod_quiz.Rmodule. You can think of this as a second-level module. This module takes care of the questions’ visualizations. -
mod_quiz_questionviz_fct_graphs.Randmod_quiz_questionviz_fct_uidynamic.Rare two business-specific files with functions that are used to create the graphs and UI for themod_quiz_questionviz.Rmodule. We could have put all the functions into one_fctfile, or all of them insidemod_quiz_questionviz.R, and the functionality would have remained the same. Instead, we decide to break the code into different files so it would be easier to change and add functionalities. -
run_app.Rcontains therun_app()function that is called when a new user connects to the app. You should not change this file unless you want to edit the authentication system or edit the login page.
2.2.3 dev/
The files in this folder are never called by the app. Instead, these files are meant to keep code that you will find yourself needing often when developing the app locally. You are not required to run any of these files; they serve only as a place to keep code and not forget them.
-
01_start.Rcontains configuration code that you need to run when you first create a Golem app. -
02_dev.Rcontains code that you will need to run when developing the app, like the function to create new modules, or_fctand_utils. -
03_deploy.Rcontains code that you will need to run when deploying the app. -
googledrive_auth.Ris a configuration file that you will need to run whenever you want to change the.secretsof the app needed to connect to the Google Files API. -
run_dev.Rcontains the block of code that you need to run to start the app locally.
2.2.4 inst/
In this folder you will find the golem_config.yml file and the public resources.
-
app/www/is where you put resourcer that will need to be accesed on the web, like pictures. -
golem_config.ymlis a file to define variables for golem. We do not use this file for keeping variables as we use./config.ymlin the root folder instead.
2.2.5 man/
These files are automatically generated when building the app. These files contain the functions descriptions created using the roxygen2 convention.
Example:
#' Get sheetnames of file in course directory
#'
#' @description Filter a `directory` (dribble) by `filter` and returns
#' the sheetnames of the file.
#'
#' @param directory A dribble of files in a directory
#' @param filter A string of the file to open
#'
#' @return A list of sheetnames or `c("")` if fail.
#'
#' @import dplyr stringr googlesheets4 googledrive
get_sheetnames <- function(directory, filter) {
tryCatch(
{
filter_path <- directory %>%
filter(name == filter)
metadata <- googlesheets4::gs4_get(filter_path %>% head(1))
return(metadata[["sheets"]]$name)
},
error = function(e) {
return(c(""))
}
)
}By using this structure when defining a function, the app will autogenerate a file get_sheetnames.Rd with the description above of the function. This is useful for keeping a clean documentation.