diff --git a/NAMESPACE b/NAMESPACE index 61095cdd..6c11b797 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ export("%>%") export(app_startup) export(chartsNav) +export(chartsNavUI) export(chartsTab) export(chartsTabUI) export(detectStandard) @@ -59,6 +60,8 @@ importFrom(magrittr,"%>%") importFrom(purrr,keep) importFrom(purrr,map) importFrom(purrr,map2) +importFrom(purrr,map_lgl) +importFrom(purrr,set_names) importFrom(rlang,.data) importFrom(shiny,dataTableOutput) importFrom(shiny,renderDataTable) @@ -72,6 +75,7 @@ importFrom(shinyjs,hide) importFrom(shinyjs,html) importFrom(shinyjs,removeClass) importFrom(shinyjs,show) +importFrom(shinyjs,toggleClass) importFrom(shinyjs,useShinyjs) importFrom(sortable,add_rank_list) importFrom(sortable,bucket_list) diff --git a/R/app_startup.R b/R/app_startup.R index 5d39ca74..1ae9250a 100644 --- a/R/app_startup.R +++ b/R/app_startup.R @@ -55,18 +55,18 @@ app_startup<-function(domainData=NULL, meta=NULL, charts=NULL, mapping=NULL, aut message("- Dropped ", length(envDrops), " chart(s) with `env` paramter missing or not set to 'safetyGraphics': ",paste(names(envDrops), collapse=", ")) } charts <- charts %>% purrr::keep(~.x$envValid) - + #Drop charts if data for required domain(s) is not found domainDrops <- charts %>% purrr::keep(~(!all(.x$domain %in% names(domainData)))) if(length(domainDrops)>0){ message("- Dropped ", length(domainDrops), " chart(s) with missing data domains: ", paste(names(domainDrops), collapse=", ")) } charts <- charts %>% purrr::keep(~all(.x$domain %in% names(domainData))) - + # sort charts based on order chartOrder <- order(charts %>% map_dbl(~.x$order) %>% unlist()) charts <- charts[chartOrder] - + message("- Initializing app with ",length(charts), " chart(s).") # Set filterDomain to NULL if specified domain doesn't exist diff --git a/R/getChartStatus.R b/R/getChartStatus.R new file mode 100644 index 00000000..6037729e --- /dev/null +++ b/R/getChartStatus.R @@ -0,0 +1,120 @@ +#' Check the status of a chart based on the current mapping +#' +#' Checks a chart's status when column-level chart specifications are provided in chart$dataSpec. +#' Note that safetyGraphicsApp() does not allow a `mapping` value that is not found in `domainData`, +#' so this function only needs to check that an expected parameter exists in `mapping` (not that the +#' specified column is found in the loaded data). +#' +#' @param chart `list` chart object +#' @param mapping `data.frame` current mapping +#' +#' @return `list` Named list with properties: +#' - status `logical` +#' - domains `list` list specifying whether all columns are specified in each domain +#' - columns `list` list that matches the structure of chart$dataSpec and indicates which variables are available. +#' +#' @examples +#' sample_chart <- list( +#' domains=c("aes","dm"), +#' dataSpec=list( +#' aes=c("id_col","custom_col"), +#' dm=c("id_col","test_col") +#' ) +#' ) +#' +#' sample_mapping <- data.frame( +#' domain=c("aes","aes","dm","dm"), +#' text_key=c("id_col","custom_col","id_col","test_col"), +#' current=c("myID","AEcol","myID","dmCol") +#' ) +#' +#' check <- safetyGraphics:::getChartStatus(chart=sample_chart, mapping=sample_mapping) +#' # check$status=TRUE +#' +#' # Add data spec to each chart. +#' charts <- makeChartConfig() %>% +#' map(function(chart) { +#' chart$mapping <- chart$domain %>% +#' map_dfr(function(domain) { +#' do.call( +#' `::`, +#' list( +#' 'safetyCharts', +#' paste0('meta_', domain) +#' ) +#' ) +#' }) %>% +#' distinct(domain, col_key, current = standard_adam) %>% +#' filter(!is.na(current)) %>% +#' select(domain, text_key = col_key, current) +#' +#' chart$dataSpec <- chart$domain %>% +#' map(function(domain) { +#' chart$mapping %>% +#' filter(.data$domain == !!domain) %>% +#' pull(text_key) %>% +#' unique() +#' }) %>% +#' set_names(chart$domain) +#' +#' chart +#' }) +#' +#' checks <- map(charts, ~getChartStatus(.x, .x$mapping)) +#' +#' @importFrom purrr imap map +#' @importFrom rlang set_names +#' +#' @keywords internal +getChartStatus <- function(chart, mapping){ + stopifnot( + "Can't get status since chart does not have dataSpec associated."=hasName(chart, 'dataSpec') + ) + + # check to see whether each individual column has a mapping defined + missingCols<-c() + colStatus <- names(chart$dataSpec) %>% map(function(domain){ + domainMapping <- generateMappingList(settingsDF=mapping, domain=domain) + requiredCols <- chart$dataSpec[[domain]] + colStatus <- requiredCols %>% map(function(col){ + if(hasName(domainMapping,col)){ + status<-case_when( + domainMapping[[col]]=='' ~ FALSE, + is.na(domainMapping[[col]]) ~ FALSE, + is.character(domainMapping[[col]]) ~ TRUE + ) + } else{ + status<-FALSE + } + return(status) + }) %>% set_names(requiredCols) + return(colStatus) + })%>% set_names(names(chart$dataSpec)) + + # check to see whether all columns in a domain were valid + domainStatus <- colStatus %>% + map(~all(unlist(.x))) %>% + set_names(names(colStatus)) + + # check to see whether all columns in all domains were valid + status <- ifelse(all(unlist(domainStatus)),TRUE, FALSE) + + # make a text summary + if(status){ + summary <- "All required mappings found" + }else{ + missingCols <- colStatus %>% imap(function(cols,domain){ + missingDomainCols <- cols %>% imap(function(status, col){ + if(status){ + return(NULL) + }else{ + return(paste0(domain,"$",col)) + } + }) + return(missingDomainCols) + }) + summary<- paste0("Missing Mappings: ",paste(unlist(missingCols),collapse=",")) + } + + return(list(chart=chart$name, columns=colStatus, domains=domainStatus, status=status, summary=summary)) +} diff --git a/R/makeChartSummary.R b/R/makeChartSummary.R index 450b30f9..97882fb8 100644 --- a/R/makeChartSummary.R +++ b/R/makeChartSummary.R @@ -2,12 +2,24 @@ #' @description makes a nicely formatted html summary for a chart object #' #' @param chart list containing chart specifications +#' @param status (optional) chart status from `getChartStatus`. Default is NULL. #' @param showLinks boolean indicating whether to include links #' @param class character to include as class #' #' @export -makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ +makeChartSummary<- function(chart, status=NULL, showLinks=TRUE, class="chart-header"){ + + if(!is.null(status)){ + if(status$status){ + status <- div(class="status", tags$small("Status"), tags$i(class="fa fa-check-circle", style="color: green"),title=status$summary) + }else{ + status <- div(class="status", tags$small("Status"), tags$i(class="fa fa-times-circle", style="color: red"),title=status$summary) + } + }else{ + status <- NULL + } + if(utils::hasName(chart,"links")){ links<-purrr::map2( chart$links, @@ -23,17 +35,20 @@ makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ }else{ links<-NULL } - - labelDiv<-div(tags$small("Chart"),chart$label) - typeDiv<-div(tags$small("Type"), chart$type) - dataDiv<-div(tags$small("Data Domain"), paste(chart$domain,collapse=" ")) + labelDiv<-div(class="name", tags$small("Chart"),chart$label) + typeDiv<-div(class="type", tags$small("Type"), chart$type) + dataDiv<-div(class="domain", tags$small("Data Domain"), paste(chart$domain,collapse=" ")) + + class <- c('chart-summary',class) + if(showLinks){ summary<-div( labelDiv, typeDiv, dataDiv, links, + status, class=class ) } else { @@ -41,6 +56,7 @@ makeChartSummary<- function(chart, showLinks=TRUE, class="chart-header"){ labelDiv, typeDiv, dataDiv, + status, class=class ) } diff --git a/R/mod_chartsNav.R b/R/mod_chartsNav.R index 6904a81e..d2c3fd76 100644 --- a/R/mod_chartsNav.R +++ b/R/mod_chartsNav.R @@ -1,22 +1,65 @@ #' Adds a navbar tab that initializes the Chart Module UI #' -#' @param chart chart metadata -#' @param ns namespace +#' @param id module id +#' @param chart chart metadata #' #' @export #' -chartsNav <- function(chart,ns){ - appendTab( - inputId = "safetyGraphicsApp", - menuName = "Charts", - tab = tabPanel( - title = makeChartSummary(chart, showLinks=FALSE, class="chart-nav"), - value = chart$name, - chartsTabUI( - id=ns(chart$name), - chart=chart - ) +chartsNavUI <- function(id, chart) { + ns <- NS(id) + + panel<-tabPanel( + title = uiOutput(ns("tabTitle")), + value = chart$name, + chartsTabUI( + id=ns("chart"), + chart=chart ) ) -} \ No newline at end of file + + return(panel) +} + +#' Server for a navbar tab +#' +#' @param input Input objects from module namespace +#' @param output Output objects from module namespace +#' @param session An environment that can be used to access information and functionality relating to the session +#' @param chart list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}. +#' @param data named list of current data sets (Reactive). +#' @param mapping tibble capturing the current data mappings (Reactive). +#' +#' @export +#' + +chartsNav<-function(input, output, session, chart, data, mapping){ + ns <- session$ns + + chartStatus <- reactive({ + if(hasName(chart, 'dataSpec')){ + status<-getChartStatus(chart, mapping()) + }else{ + status<-NULL + } + return(status) + }) + + output$tabTitle <- renderUI({ + makeChartSummary( + chart, + status=chartStatus(), + showLinks=FALSE, + class="chart-nav" + ) + }) + + callModule( + module=chartsTab, + id='chart', + chart=chart, + data=data, + mapping=mapping, + status=chartStatus + ) +} diff --git a/R/mod_chartsTab.R b/R/mod_chartsTab.R index 7b274b5f..b27c1b63 100644 --- a/R/mod_chartsTab.R +++ b/R/mod_chartsTab.R @@ -10,7 +10,7 @@ chartsTabUI <- function(id, chart){ ns <- shiny::NS(id) - header<-div(class=ns("header"), makeChartSummary(chart)) + header<- uiOutput(ns("chart-header")) chartWrap<-chart$functions$ui(ns("chart-wrap")) return(list(header, chartWrap)) @@ -24,12 +24,16 @@ chartsTabUI <- function(id, chart){ #' @param chart list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}. #' @param data named list of current data sets (Reactive). #' @param mapping tibble capturing the current data mappings (Reactive). +#' @param status chart status (Reactive) #' #' @export -chartsTab <- function(input, output, session, chart, data, mapping){ +chartsTab <- function(input, output, session, chart, data, mapping, status){ ns <- session$ns - + + # Draw the header + output$`chart-header` <- renderUI({makeChartSummary(chart, status=status())}) + # Initialize chart-specific parameters params <- reactive({ makeChartParams( @@ -56,7 +60,7 @@ chartsTab <- function(input, output, session, chart, data, mapping){ where="beforeEnd", ui=downloadButton(ns("scriptDL"), "R script", class="pull-right btn-xs dl-btn") ) - + mapping_list<-reactive({ mapping_list <- generateMappingList(mapping() %>% filter(.data$domain %in% chart$domain)) if(length(mapping_list)==1){ @@ -93,7 +97,7 @@ chartsTab <- function(input, output, session, chart, data, mapping){ mapping = mapping(), chart = chart ) - + rmarkdown::render( tempReport, output_file = file, diff --git a/R/mod_mappingColumn.R b/R/mod_mappingColumn.R index a08d2f29..b9b7ea25 100644 --- a/R/mod_mappingColumn.R +++ b/R/mod_mappingColumn.R @@ -33,7 +33,7 @@ mappingColumnUI <- function(id, meta, data, mapping=NULL){ col_meta <- meta %>% filter(.data$type=="column") # Exactly one column mapping provided - stopifnot(nrow(col_meta)==1) + stopifnot(msg = nrow(col_meta)==1) col_ui[[1]] <- mappingSelectUI( ns(col_meta$text_key), diff --git a/R/mod_safetyGraphicsServer.R b/R/mod_safetyGraphicsServer.R index 2206fcb1..c7e37d5d 100644 --- a/R/mod_safetyGraphicsServer.R +++ b/R/mod_safetyGraphicsServer.R @@ -14,14 +14,11 @@ #' @import shiny #' @import dplyr #' @importFrom purrr map -#' @importFrom shinyjs html +#' @importFrom shinyjs html toggleClass #' #' @export -safetyGraphicsServer <- function( - input, - output, - session, +safetyGraphicsServer <- function(input, output, session, meta, mapping, domainData, @@ -29,10 +26,22 @@ safetyGraphicsServer <- function( filterDomain, config ) { - #Initialize modules - current_mapping<-callModule(mappingTab, "mapping", meta, domainData) - - # Initialize the filter tab + # Initialize the Home tab + callModule( + homeTab, + "home", + config + ) + + # Initialize the Mapping tab - returns the current mapping as a reactive + current_mapping<-callModule( + mappingTab, + "mapping", + meta, + domainData + ) + + # Initialize the Filter tab - returns list of filtered data as a reactive filtered_data<-callModule( filterTab, "filter", @@ -40,25 +49,35 @@ safetyGraphicsServer <- function( filterDomain=filterDomain, current_mapping=current_mapping ) - - callModule(homeTab, "home", config) - #Initialize Chart UI - Adds subtabs to chart menu - this initializes initializes chart UIs - charts %>% purrr::map(~chartsNav(.x,session$ns)) + # Initialize Charts tab + # Initialize Chart UI - adds subtabs to chart menu and initializes the chart UIs + #charts %>% purrr::map( + # ~chartsNav( + # .x, + # session$ns + # ) + #) - #Initialize Chart Servers - validDomains <- tolower(names(mapping)) - charts %>% purrr::map( + # Initialize Chart Servers + charts %>% purrr::walk( ~callModule( - module=chartsTab, + module=chartsNav, id=.x$name, chart=.x, data=filtered_data, - mapping=current_mapping + mapping=current_mapping ) ) - #Setting tab - callModule(settingsTab, "settings", domains = domainData, metadata=meta, mapping=current_mapping, charts = charts) + # Initialize the Setting tab + callModule( + settingsTab, + "settings", + domains = domainData, + metadata=meta, + mapping=current_mapping, + charts = charts + ) } diff --git a/R/mod_safetyGraphicsUI.R b/R/mod_safetyGraphicsUI.R index c6f7d510..8a307109 100644 --- a/R/mod_safetyGraphicsUI.R +++ b/R/mod_safetyGraphicsUI.R @@ -1,7 +1,7 @@ #' UI for the core safetyGraphics app including Home, Mapping, Filter, Charts and Settings modules. #' -#' #' @param id module ID +#' @param charts list of charts in the format produced by safetyGraphics::makeChartConfig() #' @param meta data frame containing the metadata for use in the app. #' @param domainData named list of data.frames to be loaded in to the app. #' @param mapping data.frame specifying the initial values for each data mapping. If no mapping is provided, the app will attempt to generate one via \code{detectStandard()} @@ -11,7 +11,14 @@ #' #' @export -safetyGraphicsUI <- function(id, meta, domainData, mapping, standards, config) { +safetyGraphicsUI <- function(id, + meta, + mapping, + domainData, + charts, + standards, + config +) { ns<-NS(id) #read css from package @@ -37,6 +44,24 @@ safetyGraphicsUI <- function(id, meta, domainData, mapping, standards, config) { spinner<-NULL } + #Set up ChartNav + #trick for navbar menu: https://stackoverflow.com/questions/34846469/for-loops-lapply-navbarpage-within-in-ui-r + chartList <- charts %>% + purrr::map(function(chart) { + chartsNavUI(ns(chart$name), chart) + }) %>% + unname + + navParams<-c( + list( + title='Charts', + icon=icon("chart-bar") + ), + chartList + ) + + chartNav <- do.call(navbarMenu, navParams) + #app UI using calls to modules ui<-tagList( shinyjs::useShinyjs(), @@ -55,7 +80,7 @@ safetyGraphicsUI <- function(id, meta, domainData, mapping, standards, config) { tabPanel("Home", icon=icon("home"), homeTabUI(ns("home"))), tabPanel("Mapping", icon=icon("map"), mappingTabUI(ns("mapping"), meta, domainData, mapping, standards)), tabPanel("Filtering", icon=icon("filter"), filterTabUI(ns("filter"))), - navbarMenu('Charts', icon=icon("chart-bar")), + chartNav, tabPanel('',icon=icon("cog"), settingsTabUI(ns("settings"))) ), participant_badge diff --git a/R/prepareChart.R b/R/prepareChart.R index 71ffebc4..cc19aecf 100644 --- a/R/prepareChart.R +++ b/R/prepareChart.R @@ -37,6 +37,14 @@ prepareChart <- function(chart){ tolower(chart$env)=="safetygraphics" ) + # check to see if data specifications are provided in domain + if(typeof(chart$domain)=="list"){ + if(!hasName(chart,"dataSpec")){ + chart$dataSpec <- chart$domain + } + chart$domain <- names(chart$domain) + } + #### Bind Workflow functions to chart object #### if(!hasName(chart,"functions")){ diff --git a/R/safetyGraphicsApp.R b/R/safetyGraphicsApp.R index 493ea701..c2b9b91a 100644 --- a/R/safetyGraphicsApp.R +++ b/R/safetyGraphicsApp.R @@ -39,37 +39,35 @@ safetyGraphicsApp <- function( message("Initializing safetyGraphicsApp") config <- app_startup( - domainData=domainData, - meta=meta, - charts=charts, - mapping=mapping, - autoMapping=autoMapping, - filterDomain=filterDomain, - chartSettingsPaths=chartSettingsPaths, - appName=appName, - hexPath=hexPath, - homeTabPath=homeTabPath + domainData = domainData, + meta = meta, + charts = charts, + mapping = mapping, + autoMapping = autoMapping, + filterDomain = filterDomain, + chartSettingsPaths = chartSettingsPaths, + appName = appName, + hexPath = hexPath, + homeTabPath = homeTabPath ) app <- shinyApp( - ui = safetyGraphicsUI( - "sg", - config$meta, - config$domainData, - config$mapping, - config$standards, - config + ui = safetyGraphicsUI(id = "sg", + meta = config$meta, + mapping = config$mapping, + domainData = config$domainData, + charts = config$charts, + standards = config$standards, + config = config ), server = function(input, output, session) { - callModule( - safetyGraphicsServer, - "sg", - config$meta, - config$mapping, - config$domainData, - config$charts, - config$filterDomain, - config + callModule(safetyGraphicsServer, id = 'sg', + meta = config$meta, + mapping = config$mapping, + domainData = config$domainData, + charts = config$charts, + filterDomain = config$filterDomain, + config = config ) } ) diff --git a/R/safetyGraphicsInit.R b/R/safetyGraphicsInit.R index 39762f63..ff7be5ea 100644 --- a/R/safetyGraphicsInit.R +++ b/R/safetyGraphicsInit.R @@ -130,6 +130,7 @@ safetyGraphicsInit <- function(charts=makeChartConfig(), delayTime=1000, maxFile safetyGraphicsUI( "sg", config$meta, + config$charts, config$domainData, config$mapping, config$standards diff --git a/R/detectStandard.R b/R/util-detectStandard.R similarity index 100% rename from R/detectStandard.R rename to R/util-detectStandard.R diff --git a/R/evaluateStandard.R b/R/util-evaluateStandard.R similarity index 100% rename from R/evaluateStandard.R rename to R/util-evaluateStandard.R diff --git a/R/generateMappingList.R b/R/util-generateMappingList.R similarity index 82% rename from R/generateMappingList.R rename to R/util-generateMappingList.R index 97c13abe..53d53374 100644 --- a/R/generateMappingList.R +++ b/R/util-generateMappingList.R @@ -7,17 +7,25 @@ #' @importFrom stringr str_split #' @export -generateMappingList <- function(settingsDF, domain=NULL, pull=FALSE){ +generateMappingList <- function(settingsDF, domain=NULL, pull=FALSE) { + if ('tbl_df' %in% class(settingsDF)) + pull <- TRUE + settingsList <- list() settingsDF$domain_key <- paste0(settingsDF$domain, "--", settingsDF$text_key) domain_keys <- settingsDF$domain_key %>% textKeysToList() - + settingsList<-list() for (i in 1:length(domain_keys) ) { settingsList<-setMappingListValue( key=domain_keys[[i]], - value=ifelse(pull, settingsDF[i,"current"]%>%pull(), settingsDF[i,"current"]), + value=ifelse( + pull, + settingsDF[i,"current"] %>% + pull(), + settingsDF[i,"current"] + ), settings=settingsList, forceCreate=TRUE ) @@ -30,4 +38,4 @@ generateMappingList <- function(settingsDF, domain=NULL, pull=FALSE){ }else{ return(settingsList[[domain]]) } -} \ No newline at end of file +} diff --git a/R/hasColumn.R b/R/util-hasColumn.R similarity index 100% rename from R/hasColumn.R rename to R/util-hasColumn.R diff --git a/R/hasField.R b/R/util-hasField.R similarity index 100% rename from R/hasField.R rename to R/util-hasField.R diff --git a/R/setMappingListValue.R b/R/util-setMappingListValue.R similarity index 99% rename from R/setMappingListValue.R rename to R/util-setMappingListValue.R index 8debec94..344b4c69 100644 --- a/R/setMappingListValue.R +++ b/R/util-setMappingListValue.R @@ -17,7 +17,6 @@ setMappingListValue <- function(key, value, settings, forceCreate=FALSE){ - if(typeof(settings)!="list"){ if(forceCreate){ settings=list() @@ -38,4 +37,4 @@ setMappingListValue <- function(key, value, settings, forceCreate=FALSE){ settings[[firstKey]]<-setMappingListValue(settings = settings[[firstKey]],key = key[2:length(key)], value=value, forceCreate=forceCreate) return(settings) } -} \ No newline at end of file +} diff --git a/R/textKeysToList.R b/R/util-textKeysToList.R similarity index 100% rename from R/textKeysToList.R rename to R/util-textKeysToList.R diff --git a/inst/www/index.css b/inst/www/index.css index ded3585c..9dbe0bb9 100644 --- a/inst/www/index.css +++ b/inst/www/index.css @@ -130,12 +130,12 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > display:inline-block; } -.chart-nav div:not(:first-child){ +.chart-nav div:not(.name){ font-size:0.8em; color: #999; } -.chart-nav div:last-child::before{ +.chart-nav div.domain::before{ content: "/"; } @@ -152,4 +152,9 @@ table.metatable.dataTable tr > td:last-of-type, table.metatable.trdataTable tr > border:1px solid #bee5eb; } +/* Right align chart status */ +div.chart-header div.status{ + float:right; + cursor:help +} diff --git a/man/chartsNav.Rd b/man/chartsNav.Rd index d0197e34..b46e9f65 100644 --- a/man/chartsNav.Rd +++ b/man/chartsNav.Rd @@ -2,15 +2,23 @@ % Please edit documentation in R/mod_chartsNav.R \name{chartsNav} \alias{chartsNav} -\title{Adds a navbar tab that initializes the Chart Module UI} +\title{Server for a navbar tab} \usage{ -chartsNav(chart, ns) +chartsNav(input, output, session, chart, data, mapping) } \arguments{ -\item{chart}{chart metadata} +\item{input}{Input objects from module namespace} -\item{ns}{namespace} +\item{output}{Output objects from module namespace} + +\item{session}{An environment that can be used to access information and functionality relating to the session} + +\item{chart}{list containing a safetyGraphics chart object like those returned by \link{makeChartConfig}.} + +\item{data}{named list of current data sets (Reactive).} + +\item{mapping}{tibble capturing the current data mappings (Reactive).} } \description{ -Adds a navbar tab that initializes the Chart Module UI +Server for a navbar tab } diff --git a/man/chartsNavUI.Rd b/man/chartsNavUI.Rd new file mode 100644 index 00000000..bc3cea1f --- /dev/null +++ b/man/chartsNavUI.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mod_chartsNav.R +\name{chartsNavUI} +\alias{chartsNavUI} +\title{Adds a navbar tab that initializes the Chart Module UI} +\usage{ +chartsNavUI(id, chart) +} +\arguments{ +\item{id}{module id} + +\item{chart}{chart metadata} +} +\description{ +Adds a navbar tab that initializes the Chart Module UI +} diff --git a/man/chartsTab.Rd b/man/chartsTab.Rd index 090efb6c..46d4985b 100644 --- a/man/chartsTab.Rd +++ b/man/chartsTab.Rd @@ -4,7 +4,7 @@ \alias{chartsTab} \title{Server for chart module, designed to be re-used for each chart generated.} \usage{ -chartsTab(input, output, session, chart, data, mapping) +chartsTab(input, output, session, chart, data, mapping, status) } \arguments{ \item{input}{Input objects from module namespace} @@ -18,6 +18,8 @@ chartsTab(input, output, session, chart, data, mapping) \item{data}{named list of current data sets (Reactive).} \item{mapping}{tibble capturing the current data mappings (Reactive).} + +\item{status}{chart status (Reactive)} } \description{ Server for chart module, designed to be re-used for each chart generated. diff --git a/man/getChartStatus.Rd b/man/getChartStatus.Rd new file mode 100644 index 00000000..be1a5a86 --- /dev/null +++ b/man/getChartStatus.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/getChartStatus.R +\name{getChartStatus} +\alias{getChartStatus} +\title{Check the status of a chart based on the current mapping} +\usage{ +getChartStatus(chart, mapping) +} +\arguments{ +\item{chart}{chart object} + +\item{mapping}{the current mapping data.frame} +} +\value{ +a list with \code{status}, \code{domains} and \code{columns} properties +} +\description{ +Checks a chart's status when column-level chart specifications are provided in chart$dataSpec. Note that safetyGraphicsApp() does not allow a \code{mapping} value that is not found in \code{domainData}, so this function only needs to check that an expected parameter exists in \code{mapping} (not that the specified column is found in the loaded data). +} +\details{ +Returns a list, with: +\itemize{ +\item \code{status} (TRUE, FALSE) +\item \code{domains} a list specifying wheter all columns are specified in each domain +\item \code{columns} a list that matches the structure of chart$dataSpec and indicates which variables are available. +} +} +\examples{ +sample_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) +) + +sample_mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","AEcol","myID","dmCol") +) + +check <- safetyGraphics:::getChartStatus(chart=sample_chart, mapping=sample_mapping) +# check$status=TRUE + +} +\keyword{internal} diff --git a/man/makeChartSummary.Rd b/man/makeChartSummary.Rd index e5e0ef9e..1bdda058 100644 --- a/man/makeChartSummary.Rd +++ b/man/makeChartSummary.Rd @@ -4,11 +4,18 @@ \alias{makeChartSummary} \title{html chart summary} \usage{ -makeChartSummary(chart, showLinks = TRUE, class = "chart-header") +makeChartSummary( + chart, + status = NULL, + showLinks = TRUE, + class = "chart-header" +) } \arguments{ \item{chart}{list containing chart specifications} +\item{status}{(optional) chart status from \code{getChartStatus}. Default is NULL.} + \item{showLinks}{boolean indicating whether to include links} \item{class}{character to include as class} diff --git a/man/safetyGraphicsUI.Rd b/man/safetyGraphicsUI.Rd index 5dcc2012..19bdbd6a 100644 --- a/man/safetyGraphicsUI.Rd +++ b/man/safetyGraphicsUI.Rd @@ -4,16 +4,18 @@ \alias{safetyGraphicsUI} \title{UI for the core safetyGraphics app including Home, Mapping, Filter, Charts and Settings modules.} \usage{ -safetyGraphicsUI(id, meta, domainData, mapping, standards, config) +safetyGraphicsUI(id, meta, mapping, domainData, charts, standards, config) } \arguments{ \item{id}{module ID} \item{meta}{data frame containing the metadata for use in the app.} +\item{mapping}{data.frame specifying the initial values for each data mapping. If no mapping is provided, the app will attempt to generate one via \code{detectStandard()}} + \item{domainData}{named list of data.frames to be loaded in to the app.} -\item{mapping}{data.frame specifying the initial values for each data mapping. If no mapping is provided, the app will attempt to generate one via \code{detectStandard()}} +\item{charts}{list of charts in the format produced by safetyGraphics::makeChartConfig()} \item{standards}{a list of information regarding data standards. Each list item should use the format returned by safetyGraphics::detectStandard.} } diff --git a/tests/testthat/test_getChartStatus.R b/tests/testthat/test_getChartStatus.R new file mode 100644 index 00000000..f0586ec4 --- /dev/null +++ b/tests/testthat/test_getChartStatus.R @@ -0,0 +1,92 @@ +context("Tests for the getChartStatus() function") +library(safetyGraphics) +library(safetyCharts) + +# Functional Specification +# [*] chart with no data spec throws error +# [*] status returned correctly for valid chart +# [*] status returned correctly when mapping values for a column are '' and NA +# [*] status returned correctly when dataSpec is not found in mapping + +test_that("chart with no data spec throws error",{ + expect_error(chart=list(domains=c("ae","dm"))) +}) + +test_that("status returned correctly for valid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","AEcol","myID","dmCol") + ) + + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_true(status$status) + expect_true(status$domains$aes) + expect_true(status$domains$dm) + expect_true(status$columns$aes$id_col) + expect_true(status$columns$aes$custom_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +}) + + +test_that("status returned correctly for invalid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c(NA,"","myID","dmCol") + ) + + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_false(status$status) + expect_false(status$domains$aes) + expect_true(status$domains$dm) + expect_false(status$columns$aes$id_col) + expect_false(status$columns$aes$custom_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +}) + + +test_that("status returned correctly for invalid chart",{ + ae_chart <- list( + domains=c("aes","dm"), + dataSpec=list( + aes=c("id_col","custom_col","another_col"), + dm=c("id_col","test_col") + ) + ) + + mapping <- data.frame( + domain=c("aes","aes","dm","dm"), + text_key=c("id_col","custom_col","id_col","test_col"), + current=c("myID","aesCol","myID","dmCol") + ) + ml<-generateMappingList(settingsDF=mapping, domain='aes') + expect_false(hasName(ml,"another_col")) + status<-getChartStatus(chart=ae_chart, mapping=mapping) + expect_false(status$status) + expect_false(status$domains$aes) + expect_true(status$domains$dm) + expect_true(status$columns$aes$id_col) + expect_true(status$columns$aes$custom_col) + expect_false(status$columns$aes$another_col) + expect_true(status$columns$dm$id_col) + expect_true(status$columns$dm$test_col) +})