Files: what is where
The root folder
-
DESCRIPTION
,LICENCE
,NAMESPACE
,LICENSE.md
are metadata files related to R packages
dev
Contains files related to the development of the app.
You should create:
- a folder (e.g.
dev/dev_events
) for event files in the development phase. Change the call torun_app
inrun_dev.R
to indicate the path to this folder - a user database (you can use
create_user_db.R
for this). This too should be indicated inrun_dev.R
01_start.R
, 02_dev.R
and
03_deploy.R
contain useful commands related to app
development. These are files created by the Golem framework.
02_dev.R
is the most useful of these, it can be used to
indicate dependencies to other packages, create new modules etc.
run_dev.R is the script that golem::run_dev()
runs
(note, you should always use this command to run the app when developing
it). It sets up the app for running it while developing the app. Here
you can indicate whether you want the app to run in production or
development mode.
inst
-
golem-config.yml
is a configuration file related to Golem. Note, don’t change the version number by hand here; seedev/02_dev.R
instead. -
inst/app/www/script.js
is a javascript file the app uses. It is added as a head tag to the app html. It is mostly related to the table and fileInput modules. -
inst/user_doc/inst_frontpage
is a file that the login page will use to generate the text paragraphs.
inst/extdata
This folder is home to three important files.
ui_structure.json
Contains the structure of each UI element. Each item in this file has at least the following fields:
-
code_name
is the name used to refer to the widget in the app -
type
is the type of the widget. This is one of the following (listed under each type are the possible fields related to the type):-
selectInput
-
choices
: a list of choices, a category indisplay_names.csv
or"IGNORE"
. See the documentation for the functionget_selectInput_choices
defined infct_ui.R
. -
multiple
: are multiple choices allowed? Defaults tofalse
.
-
-
numericInput
-
min
: The smallest acceptable value (inclusive) -
max
: The largest acceptable value (inclusive) -
step
: If set to 1, only integer values are allowed -
sum_to
,sum_of
: related to the calculation of yield sums inharvest_crop_table
-
-
fileInput
-
filetype
: The type of files that should be accepeted. See Shiny documentation for the fileInput widget. This is not necessarily enforced.
-
-
textInput
-
placeholder
: Code name of placeholder
-
-
textAreaInput
-
placeholder
: Code name of placeholder -
maxlength
: The maximum acceptable length (in characters) of the value
-
-
textOutput
-
dynamic
: If defined, indicates how the text should be adjusted during the execution of app. Seeform_title
for an illustrative (and only) example. -
style
:"label"
if the text should look like a widget label.
-
actionButton
dateInput
dateRangeInput
-
dataTable
-
columns
: The columns of the table in case it has a dynamic row group -
rows
: A list of row groups. There are two types of row groups: dynamic and static. There can be at most one dynamic row group and it comes first. There can be multiple static row groups. For dynamic row groups therow_variable
field indicates the widget which determines the rows of the dynamic row group. For static rows the variable names of the desired widgets are listed undervariables
andhide_labels
can be used to hide the labels of these widgets (labels of the widgets in the dynamic row group are automatically hidden). The name of a static row can be defined inname
.
-
-
Other fields:
-
label
: the code name of the label of the widget (this will be found fromdisplay_names.csv
) -
required
: is it compulsory to fill the widget before the event can be saved? Defaults tofalse
. -
hide_in_event_list
: should this variable be hidden in the event list (when viewing a specific activity type)? Defaults tofalse
. -
condition
: this isn’t specified for single widgets but for groups of widgets. This is the condition (in javascript) which determines whether the widget group in question should be visible or not. This is given to a Shiny element called ConditionalPanel.
man
, vignettes
man
contains the function documentation generated by
Roxygen2, vignettes
contains this vignette.
tests
All tests should be placed under tests/testthat
. The
testthat package is used. Currently automated test are made to check
that changing language works as expected, and that downloading buttons
return a valid file.
R
This is the folder which contains the actual bulk of the application.
run_app.R
defines the function which launches the app.
app_server.R
and app_ui.R
define the server
and UI functions of the main app. fct_
and
utils_
files contain helper functions. Files starting with
mod_
are either modules or files directly related to
modules.
The structure of the app
The structure of the app can be summarised as follows:
- the main app consists of
app_server.R
andapp_ui.R
. The UI includes (in order)- the language and site selectors
- button to download the user instructions for the app
- the title and introduction text
-
the event list module
(
mod_event_list.R
)- the event list includes a table showing a list of events and selectors to filter which events are displayed
- buttons to download the events as a zipped json files or as a flat csv
- buttons to create a new event and to clone an event
-
the form module (
mod_form.R
)- this contains all the widgets for entering information about an event and the save, cancel and delete event buttons
- the default widgets (block, activity, date and description) are
hard-coded in the UI function of the module. The activity-specific
widgets are created by calling the
create_ui
function (defined infct_ui.R
) in that same UI function. - the widgets include standard Shiny widgets as well as table
modules (
mod_table.R
) and fileInput modules (mod_fileInput.R
).
Modules are a tool to make Shiny apps more, well, modular. Each module includes a UI function, which creates user interface components, and a server function which defines how those components should behave.
A module (more specifically, its server function) can be given input values which are usually reactives (reactive is a Shiny term. Reactive expressions can be thought of as functions which store their value and only recalculate it when it is no longer valid.). For example, the language chosen in the main app is passed on to other modules as a reactive expression – when the language is changed by the user, that reactive can be used to access the latest language in the modules. Modules can also return values, and these values are usually reactive as well. For example, the form module returns the values of widgets to the main app server function, which goes on to edit or create a json file based on this information.
The startup process
A few words about the process of starting the app, as that became a
bit more complex recently. The app is started by a call to the
run_app
function, defined in R/run_app.R
. The
app can be started in two modes, production mode or developer mode. This
is controlled by the option golem.app.prod
:
options(golem.app.prod = TRUE) # use production mode and hence user authentication
options(golem.app.prod = FALSE) # skip authentication
# run_app(...)
It is in this run_app.R
file where the app is “wrapped
in shinymanager” to display the authentication UI if the app is in
production mode.
When the app starts, the app_server
server function in
R\app_server.R
is initialised. It is here that the event
list module server is initialised as well. However, calling the server
function of the form module is delayed until a site is specified (either
by logging in to a user account specific to a site or in admin mode
where the site selector is visible). This is done to decrease the time
it takes for the main app UI to be displayed. However, this causes a
small delay in the loading of events in the event list.
The form server is initialised by calling the function
initialise_form
defined within the app_server
function. Furthermore, when the form server function is initialised, it
does not yet initialise the server function of table or fileInput
modules on the form. Instead, they are initialised the first time the
form is shown. Their initialisation happens by sending an initialisation
signal to the form through a reactive (init_signal
), which
is being listened to by the form server function.
Useful resources
- For Shiny: Mastering Shiny and Shiny function reference
- For R packages: R Packages and R package primer
- For R: Advanced R
- For Golem and Shiny app development: Engineering Production-Grade Shiny Apps