diff --git a/R/ZZZ.R b/R/ZZZ.R index 5803c243..f6cd9c49 100644 --- a/R/ZZZ.R +++ b/R/ZZZ.R @@ -9,11 +9,26 @@ utils::globalVariables(c( ".env" )) +#' Get RTT specialties data +#' +#' Reads the RTT specialties CSV file from the app data directory. +#' +#' @return A tibble containing RTT specialty codes and names. +#' @noRd rtt_specialties <- function() { app_sys("app", "data", "rtt_specialties.csv") |> readr::read_csv(col_types = "cc") } +#' Sanitize input names +#' +#' Converts input names to a standardized format by converting to lowercase, +#' replacing whitespace/underscores with hyphens, and removing invalid characters. +#' +#' @param .x A character vector of input names to sanitize. +#' +#' @return A character vector of sanitized input names. +#' @noRd sanitize_input_name <- function(.x) { .x |> stringr::str_to_lower() |> @@ -27,6 +42,16 @@ if (FALSE) { .env <- NULL } +#' Convert markdown file to HTML +#' +#' Reads a markdown file from the app directory and converts it to HTML. +#' +#' @param ... Character vectors specifying subdirectory and file(s) within the +#' app package. Passed to \code{app_sys()}. +#' +#' @return An HTML object containing the rendered markdown, or NULL if the file +#' doesn't exist. +#' @noRd md_file_to_html <- function(...) { file <- app_sys(...) @@ -37,6 +62,15 @@ md_file_to_html <- function(...) { shiny::HTML(markdown::mark_html(file, output = FALSE, template = FALSE)) } +#' Load parameters from JSON file +#' +#' Reads model parameters from a JSON file and handles backward compatibility +#' for old parameter structures. +#' +#' @param file Path to the JSON file containing parameters. +#' +#' @return A list containing the model parameters. +#' @noRd load_params <- function(file) { p <- jsonlite::read_json(file, simplifyVector = TRUE) @@ -52,6 +86,16 @@ load_params <- function(file) { p } +#' Get parameters directory path +#' +#' Constructs the file path to the parameters directory for a given user and +#' dataset, creating the directory if it doesn't exist. +#' +#' @param user Username or NULL for default. +#' @param dataset Dataset identifier. +#' +#' @return Character string containing the path to the parameters directory. +#' @noRd params_path <- function(user, dataset) { path <- file.path( get_golem_config("params_data_path"), @@ -65,6 +109,16 @@ params_path <- function(user, dataset) { path } +#' Get parameters filename +#' +#' Constructs the full file path for a scenario parameters file. +#' +#' @param user Username or NULL for default. +#' @param dataset Dataset identifier. +#' @param scenario Scenario name. +#' +#' @return Character string containing the full path to the parameters file. +#' @noRd params_filename <- function(user, dataset, scenario) { file.path( params_path(user, dataset), @@ -72,11 +126,28 @@ params_filename <- function(user, dataset, scenario) { ) } -# check to see whether the app is running locally or in production +#' Check if app is running locally +#' +#' Determines whether the app is running in a local development environment +#' or in production based on environment variables. +#' +#' @return Logical indicating if the app is running locally (TRUE) or in +#' production (FALSE). +#' @noRd is_local <- function() { Sys.getenv("SHINY_PORT") == "" || !getOption("golem.app.prod", TRUE) } +#' Encrypt a filename +#' +#' Encrypts a filename using AES-CBC encryption with HMAC for integrity. +#' +#' @param filename Character string containing the filename to encrypt. +#' @param key_b64 Base64-encoded encryption key. Defaults to the +#' NHP_ENCRYPT_KEY environment variable. +#' +#' @return Base64-encoded string containing the encrypted filename with HMAC. +#' @noRd encrypt_filename <- function( filename, key_b64 = Sys.getenv("NHP_ENCRYPT_KEY") @@ -91,6 +162,16 @@ encrypt_filename <- function( openssl::base64_encode(c(hm, ct)) } +#' Get parameters schema text +#' +#' Downloads and reads the JSON schema for model parameters from the GitHub +#' Pages site. +#' +#' @param app_version Version of the app to get the schema for. Defaults to the +#' INPUTS_DATA_VERSION environment variable or "dev" if not set. +#' +#' @return Character string containing the JSON schema text. +#' @noRd get_params_schema_text <- function( app_version = Sys.getenv("INPUTS_DATA_VERSION", "dev") ) { @@ -109,6 +190,14 @@ get_params_schema_text <- function( paste(readLines(tf), collapse = "\n") } +#' Create parameters schema object +#' +#' Creates a JSON schema validator object from schema text. +#' +#' @param schema_text Character string containing the JSON schema definition. +#' +#' @return A jsonvalidate json_schema object. +#' @noRd create_params_schema <- function(schema_text) { jsonvalidate::json_schema$new(schema_text) } diff --git a/R/fct_age_pyramid.R b/R/fct_age_pyramid.R index 1244363c..ca1bdd36 100644 --- a/R/fct_age_pyramid.R +++ b/R/fct_age_pyramid.R @@ -1,3 +1,12 @@ +#' Create an age pyramid plot +#' +#' Generates a population pyramid visualization showing age and sex distribution. +#' +#' @param age_data A data frame containing age group, sex, and population count data. +#' Expected columns: age_group, sex (1=Males, 2=Females), and n (count). +#' +#' @return A ggplot2 object representing the age pyramid. +#' @noRd age_pyramid <- function(age_data) { age_data |> dplyr::mutate( diff --git a/R/fct_population_growth.R b/R/fct_population_growth.R index 1c3049ca..752abad4 100644 --- a/R/fct_population_growth.R +++ b/R/fct_population_growth.R @@ -1,3 +1,12 @@ +#' Get population growth options +#' +#' Retrieves the available population growth projection options for a given dataset +#' from the golem configuration. +#' +#' @param dataset Dataset identifier used to retrieve dataset-specific configuration. +#' +#' @return A named list of population growth projection values. +#' @noRd get_population_growth_options <- function(dataset) { projections <- get_golem_config( "population_projections", diff --git a/R/fct_reduce_values.R b/R/fct_reduce_values.R deleted file mode 100644 index e3c98460..00000000 --- a/R/fct_reduce_values.R +++ /dev/null @@ -1,36 +0,0 @@ -reduce_values <- function(values, target) { - # ensure values are valid - stopifnot( - "values must be between 0 and 1" = all(values >= 0, values <= 1) - ) - - # start of including all of the non-target items which are greater than 0 - include <- values[values > 0] |> - names() |> - stringr::str_subset(stringr::fixed(target), TRUE) - - # create a recursive function to reduce the values until sum(values) <= 1 - fn <- function(values, include) { - # get the sum of the values - s <- sum(values) - # if the sum is less than or equal to 1 we are ok - if (s <= 1) { - return(values) - } - # work out the amount over - over <- s - 1 - # how many values can we reduce - n <- length(include) - # figure out how much to reduce the values by - # - use either the smallest value in the list, - # - or equally reduce all of the values - r <- pmin(min(values[include]), over / n) - # update the values - values[include] <- values[include] - r - # recurse: remove items that are now 0 - fn(values, include[values[include] > 0]) - } - - # run the function - fn(values, include) -} diff --git a/R/golem_utils_ui.R b/R/golem_utils_ui.R index e93868eb..4d6fef35 100644 --- a/R/golem_utils_ui.R +++ b/R/golem_utils_ui.R @@ -151,7 +151,7 @@ undisplay <- function(tag) { # if not already hidden if ( !is.null(tag$attribs$style) && - !grepl("display:\\s+none", tag$attribs$style) + !grepl("display:\\s+none", tag$attribs$style) # fmt: skip ) { tag$attribs$style <- paste( "display: none;", @@ -167,7 +167,7 @@ undisplay <- function(tag) { display <- function(tag) { if ( !is.null(tag$attribs$style) && - grepl("display:\\s+none", tag$attribs$style) + grepl("display:\\s+none", tag$attribs$style) # fmt: skip ) { tag$attribs$style <- gsub( "(\\s)*display:(\\s)*none(\\s)*(;)*(\\s)*", diff --git a/R/mod_baseline_adjustment_ui.R b/R/mod_baseline_adjustment_ui.R index 67d20432..7ee71eb9 100644 --- a/R/mod_baseline_adjustment_ui.R +++ b/R/mod_baseline_adjustment_ui.R @@ -4,15 +4,26 @@ #' #' @param id,input,output,session Internal parameters for {shiny}. #' -#' @noRd -#' #' @importFrom shiny NS tagList +#' +#' @noRd mod_baseline_adjustment_ui <- function(id) { ns <- shiny::NS(id) specs <- rtt_specialties() |> dplyr::mutate(sanitized_code = sanitize_input_name(.data[["code"]])) + # Create baseline adjustment table UI + # + # Internal helper function to create a gt table with baseline values, + # adjustment sliders, and computed parameters for different specialties. + # + # @param at Activity type (e.g., "ip", "op", "aae"). + # @param g Group identifier (e.g., "elective", "non-elective"). + # @param df Data frame containing specialty information (default: specs). + # + # @return A gt table object with baseline adjustment controls. + # @noRd create_table <- function(at, g, df = specs) { df |> dplyr::mutate( diff --git a/R/mod_expat_repat_server.R b/R/mod_expat_repat_server.R index 1fe6ed29..d3a1a569 100644 --- a/R/mod_expat_repat_server.R +++ b/R/mod_expat_repat_server.R @@ -32,6 +32,15 @@ mod_expat_repat_server <- function( # helpers ---- + # Extract expatriation/repatriation data + # + # Internal helper function to filter expatriation/repatriation data based + # on selected activity type, subgroup, and specialty/type. + # + # @param dat Data frame containing expatriation/repatriation data. + # + # @return Filtered data frame based on input selections. + # @noRd extract_expat_repat_data <- function(dat) { # TODO: techdebt # we should rename the dropdowns diff --git a/R/mod_expat_repat_ui.R b/R/mod_expat_repat_ui.R index ef985e86..2c3eb75d 100644 --- a/R/mod_expat_repat_ui.R +++ b/R/mod_expat_repat_ui.R @@ -4,12 +4,24 @@ #' #' @param id,input,output,session Internal parameters for {shiny}. #' -#' @noRd -#' #' @importFrom shiny NS tagList +#' +#' @noRd mod_expat_repat_ui <- function(id) { ns <- shiny::NS(id) + # Generate parameter controls + # + # Internal helper function to create UI controls for expatriation/repatriation + # parameters including a checkbox and slider. + # + # @param type Parameter type identifier (e.g., "expat", "repat_local"). + # @param min Minimum value for the slider. + # @param max Maximum value for the slider. + # @param values Initial values for the slider range. + # + # @return A shiny fluidRow containing the parameter controls. + # @noRd generate_param_controls <- function(type, min, max, values) { shiny::fluidRow( col_3( diff --git a/R/mod_expat_repat_utils.R b/R/mod_expat_repat_utils.R index d3210712..69fa3081 100644 --- a/R/mod_expat_repat_utils.R +++ b/R/mod_expat_repat_utils.R @@ -1,3 +1,17 @@ +#' Create expatriation/repatriation trend plot +#' +#' Generates a line plot showing trends in expatriation or repatriation rates +#' over time with an optional prediction interval. +#' +#' @param df A data frame containing financial year (fyear) and percentage (pcnt) data. +#' @param include Logical indicating whether to include the prediction interval. +#' @param values Numeric vector of length 2 with lower and upper prediction interval bounds. +#' @param start_year The baseline financial year to highlight. +#' @param title Title for the y-axis. +#' @param scale Scaling factor for determining y-axis limits (default: 10). +#' +#' @return A ggplot2 object representing the trend plot. +#' @noRd mod_expat_repat_trend_plot <- function( df, include, @@ -53,6 +67,18 @@ mod_expat_repat_trend_plot <- function( ) } +#' Create local provider split visualization +#' +#' Generates a stacked bar chart showing the distribution of activity across +#' different local providers. +#' +#' @param df A data frame containing provider and count data. +#' @param providers Named vector mapping provider names to codes. +#' @param dataset The current dataset/provider identifier. +#' @param start_year The financial year for the data. +#' +#' @return A ggplot2 object representing the provider split. +#' @noRd mod_expat_repat_local_split_plot <- function( df, providers, @@ -113,6 +139,15 @@ mod_expat_repat_local_split_plot <- function( ggplot2::theme(legend.position = "none") } +#' Create non-local activity volume plot +#' +#' Generates a bar chart showing the number of spells delivered to non-local +#' ICB residents over time. +#' +#' @param df A data frame containing financial year (fyear) and count (n) data. +#' +#' @return A ggplot2 object representing the volume plot. +#' @noRd mod_expat_repat_nonlocal_n <- function(df) { df |> ggplot2::ggplot( @@ -144,6 +179,15 @@ mod_expat_repat_nonlocal_n <- function(df) { } +#' Create non-local ICB geographic map +#' +#' Generates an interactive leaflet map showing the geographic distribution +#' of non-local ICB activity. +#' +#' @param df A spatial data frame containing ICB boundaries and activity percentages. +#' +#' @return A leaflet map object. +#' @noRd mod_expat_repat_nonlocal_icb_map <- function(df) { # nolint start: object_usage_linter pal <- leaflet::colorNumeric( diff --git a/R/mod_mitigators_rates_boxplot.R b/R/mod_mitigators_rates_boxplot.R index d50556ca..9ab6c88a 100644 --- a/R/mod_mitigators_rates_boxplot.R +++ b/R/mod_mitigators_rates_boxplot.R @@ -1,3 +1,15 @@ +#' Create a boxplot of rates data +#' +#' Generates a boxplot visualization with beeswarm points showing the +#' distribution of rates data. +#' +#' @param trend_data A data frame containing rate data with columns for rate +#' and is_peer indicator. +#' @param plot_range Numeric vector of length 2 specifying y-axis limits. +#' @param interval ggplot2 layer to add interval visualization. +#' +#' @return A ggplot2 object representing the rates boxplot. +#' @noRd rates_boxplot <- function(trend_data, plot_range, interval) { trend_data |> ggplot2::ggplot(ggplot2::aes(x = "", y = .data$rate)) + diff --git a/R/mod_mitigators_rates_trend_plot.R b/R/mod_mitigators_rates_trend_plot.R index a61eb955..552ef07d 100644 --- a/R/mod_mitigators_rates_trend_plot.R +++ b/R/mod_mitigators_rates_trend_plot.R @@ -1,3 +1,19 @@ +#' Create a rates trend plot +#' +#' Generates a line plot showing trends in rates over time with the baseline +#' year highlighted. +#' +#' @param trend_data A data frame containing rate data with columns for fyear +#' (financial year) and rate. +#' @param baseline_year The baseline financial year to highlight. +#' @param plot_range Numeric vector of length 2 specifying y-axis limits. +#' @param y_axis_title Title for the y-axis. +#' @param x_axis_title Title for the x-axis. +#' @param number_format Function to format axis numbers. +#' @param interval ggplot2 layer to add interval visualization. +#' +#' @return A ggplot2 object representing the rates trend plot. +#' @noRd rates_trend_plot <- function( trend_data, baseline_year, diff --git a/R/mod_mitigators_server.R b/R/mod_mitigators_server.R index 7a9b05c4..9d1f084d 100644 --- a/R/mod_mitigators_server.R +++ b/R/mod_mitigators_server.R @@ -71,6 +71,14 @@ mod_mitigators_server <- function( ) }) + # Get default rate interval + # + # Internal helper function to return the default rate interval values. + # + # @param rate Rate value (unused in current implementation). + # + # @return Numeric vector of length 2 with default interval (0.95, 1). + # @noRd get_default <- function(rate) { c(0.95, 1) } @@ -613,6 +621,16 @@ mod_mitigators_server <- function( ) * scale + # Convert number to formatted string + # + # Internal helper function to format numeric values based on whether + # they represent percentages. + # + # @param value Numeric value to format. + # @param config Configuration list containing y_axis_title. + # + # @return Formatted character string. + # @noRd convert_number <- function(value, config) { converted <- scales::number(value, 0.001) is_percent <- stringr::str_detect(config$y_axis_title, "%") diff --git a/R/mod_non_demographic_adjustment_utils.R b/R/mod_non_demographic_adjustment_utils.R index 3f7420e9..a23e6919 100644 --- a/R/mod_non_demographic_adjustment_utils.R +++ b/R/mod_non_demographic_adjustment_utils.R @@ -1,3 +1,12 @@ +#' Create non-demographic adjustment table +#' +#' Generates a formatted gt table displaying non-demographic adjustment factors +#' for different activity types. +#' +#' @param non_demographic_adjustment A list containing variant type and adjustment values. +#' +#' @return A gt table object. +#' @noRd mod_non_demographic_adjustment_table <- function(non_demographic_adjustment) { title <- switch( non_demographic_adjustment[["variant"]], diff --git a/R/mod_run_model_api_calls.R b/R/mod_run_model_api_calls.R index a913b449..84abb8b8 100644 --- a/R/mod_run_model_api_calls.R +++ b/R/mod_run_model_api_calls.R @@ -1,4 +1,15 @@ -# recursive future promise +#' Submit model run to API +#' +#' Submits model parameters to the NHP API for processing and monitors the +#' submission status. Uses promises for asynchronous execution. +#' +#' @param params_json JSON string containing model parameters. +#' @param app_version Version of the app to use for the model run. +#' @param status Reactive function to update status messages. +#' @param results_url Reactive function to update the results URL. +#' +#' @return A promise that resolves when submission is complete. +#' @noRd mod_run_model_submit <- function( params_json, app_version, @@ -77,6 +88,17 @@ mod_run_model_submit <- function( ) } +#' Check model run container status +#' +#' Recursively polls the API to check the status of a running model container +#' and updates progress information. +#' +#' @param id Container ID to check status for. +#' @param status Reactive function to update status messages. +#' @param error_counter Number of remaining error attempts before giving up (default: 10). +#' +#' @return A promise that resolves when the model run completes or fails. +#' @noRd mod_run_model_check_container_status <- function( id, status, diff --git a/R/mod_run_model_fix_params.R b/R/mod_run_model_fix_params.R index 26ac917e..4ff5bd5d 100644 --- a/R/mod_run_model_fix_params.R +++ b/R/mod_run_model_fix_params.R @@ -1,3 +1,13 @@ +#' Fix and validate model parameters +#' +#' Ensures model parameters are in the correct format by filling in missing +#' time profiles, removing invalid mitigators, and reordering parameters. +#' +#' @param p List containing model parameters. +#' @param schema_text JSON schema text for validation. +#' +#' @return A cleaned and validated parameters list. +#' @noRd mod_run_model_fix_params <- function(p, schema_text) { # the time profiles may be empty, ensure that's not the case tpm <- p[["time_profile_mappings"]] @@ -40,6 +50,16 @@ mod_run_model_fix_params <- function(p, schema_text) { # these with NULL's as # toJSON(NULL) == "{}" # nolint end + + # Recursively nullify empty list elements + # + # Internal helper function to replace empty lists with NULL values for + # proper JSON serialization (empty objects instead of empty arrays). + # + # @param .x A list to process. + # + # @return The list with empty elements replaced by NULL. + # @noRd recursive_nullify <- function(.x) { for (i in names(.x)) { if (length(.x[[i]]) == 0) { diff --git a/R/mod_run_model_remove_invalid_mitigators.R b/R/mod_run_model_remove_invalid_mitigators.R index 6e6d1716..288ac95c 100644 --- a/R/mod_run_model_remove_invalid_mitigators.R +++ b/R/mod_run_model_remove_invalid_mitigators.R @@ -1,3 +1,13 @@ +#' Remove invalid mitigators from parameters +#' +#' Validates parameters against the JSON schema and removes any mitigators +#' that don't conform to the schema. +#' +#' @param p List containing model parameters. +#' @param schema_text JSON schema text for validation. +#' +#' @return Parameters list with invalid mitigators removed. +#' @noRd mod_run_model_remove_invalid_mitigators <- function(p, schema_text) { schema <- create_params_schema(schema_text) @@ -22,6 +32,16 @@ mod_run_model_remove_invalid_mitigators <- function(p, schema_text) { } ) + # Remove item from nested list structure + # + # Internal helper function to recursively remove an item from a nested list + # structure following a specified path. + # + # @param x A list structure. + # @param path Character vector representing the path to the item to remove. + # + # @return The list with the specified item removed. + # @noRd remove_item <- function(x, path) { if (length(path) < 1) { return(x) diff --git a/R/mod_waiting_list_imbalances_utils.R b/R/mod_waiting_list_imbalances_utils.R index 4b36218d..4f199381 100644 --- a/R/mod_waiting_list_imbalances_utils.R +++ b/R/mod_waiting_list_imbalances_utils.R @@ -1,3 +1,13 @@ +#' Create waiting list imbalances table +#' +#' Generates a formatted gt table displaying waiting list baseline counts and +#' parameter changes by specialty and activity type. +#' +#' @param df A data frame containing specialty data with columns for tretspef, +#' activity_type, count, and param. +#' +#' @return A gt table object. +#' @noRd mod_waiting_list_imbalances_table <- function(df) { rtt_specialties() |> dplyr::inner_join(df, c(code = "tretspef")) |>