diff --git a/NAMESPACE b/NAMESPACE index 5ae87f8..2be2d25 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export("%>%") +export(create_app_daily_session_chart) export(create_app_daily_usage_chart) export(create_app_ranking) export(create_app_ranking_table) @@ -34,6 +35,7 @@ export(sort_users_by_role) import(apexcharter) import(dplyr) import(echarts4r) +import(lubridate) import(purrr) import(toastui) import(visNetwork) diff --git a/R/helpers-charts.R b/R/helpers-charts.R index 94a3d3c..e250ad1 100644 --- a/R/helpers-charts.R +++ b/R/helpers-charts.R @@ -16,16 +16,23 @@ #' @import echarts4r #' @importFrom shiny validate need is.reactive create_calendar_chart <- function( - calendar_data, - title, - subtitle = NULL, - start_date = NULL, - end_date = NULL, - callback = NULL + calendar_data, + title, + subtitle = NULL, + start_date = NULL, + end_date = NULL, + callback = NULL ) { Date <- Freq <- NULL + tryCatch({ + session <- get("session", parent.frame(2)) + ns <- session$ns + }, error = function(e) { + ns <- identity + }) + renderEcharts4r({ validate(need(nrow(calendar_data()) > 0, "No calendar data found ...")) if (is.reactive(calendar_data)) calendar_data <- calendar_data() @@ -51,7 +58,16 @@ create_calendar_chart <- function( ) %>% e_title(title, subtitle) %>% e_tooltip() %>% - e_legend(show = FALSE) + e_legend(show = FALSE) %>% + e_on( + list(), + sprintf( + "function(e) { + Shiny.setInputValue('%s', e.data.value[0], {priority: 'event'}); + }", + ns("selected_date") + ) + ) if (!is.null(callback)) { calendar_chart %>% htmlwidgets::onRender(callback) @@ -70,13 +86,64 @@ create_calendar_chart <- function( #' See \url{https://echarts4r.john-coene.com/articles/chart_types.html#calendar-1}. #'. #' @param app_usage Returned by \link{get_app_daily_usage}. +#' @param ... Pass down any param to \link{create_calendar_chart}. #' @return A calendar chart displaying daily app usage. #' @export -create_app_daily_usage_chart <- function(app_usage) { - create_calendar_chart(app_usage, "Overall app usage") +create_app_daily_usage_chart <- function(app_usage, ...) { + create_calendar_chart(app_usage, "Overall app usage", "units: user sessions/day", ...) } +#' Generic calendar chart generator +#' +#' @param calendar_data Calendar chart data. +#' @param title Chart title. +#' @param subtitle Chart subtitle. +#' @param start_date Default to minimum calendar_data date. Could also be +#' an input value with Shiny. +#' @param end_date Default to maximum calendar_data date. Could also be +#' an input value with Shiny. +#' @param callback JS function to pass to \link[htmlwidgets]{onRender}. This is +#' useful to access the widget API on the R side at render time +#' and add events on the fly. +#' +#' @return An echarts4r line chart +#' @export +create_app_daily_session_chart <- function( + calendar_data, + title = "Cumulated daily usage", + subtitle = "time units: minutes", + start_date = NULL, + end_date = NULL, + callback = NULL +) { + + cum_dur <- NULL + + renderEcharts4r({ + validate(need(nrow(calendar_data()) > 0, "No calendar data found ...")) + if (is.reactive(calendar_data)) calendar_data <- calendar_data() + if (is.null(start_date)) start_date <- min(calendar_data$Date) + if (is.null(end_date)) end_date <- max(calendar_data$Date) + if (is.reactive(start_date)) start_date <- start_date() + if (is.reactive(end_date)) end_date <- end_date() + if (is.reactive(title)) title <- title() + + usage_chart <- calendar_data %>% + filter(.data$Date >= start_date & .data$Date <= end_date) %>% + e_charts(Date) %>% + e_line(cum_dur) %>% + e_title(title, subtitle) %>% + e_tooltip() %>% + e_legend() + + if (!is.null(callback)) { + usage_chart %>% htmlwidgets::onRender(callback) + } else { + usage_chart + } + }) +} #' Daily app consumption for selected user @@ -111,10 +178,10 @@ create_user_daily_consumption_chart <- function(usage) { #' @importFrom rlang .data #' @importFrom shiny req is.reactive create_cumulated_duration_per_user <- function( - apps_usage, - start_date = NULL, - end_date = NULL, - selected_app) { + apps_usage, + start_date = NULL, + end_date = NULL, + selected_app) { username <- cum_duration <- NULL @@ -128,8 +195,8 @@ create_cumulated_duration_per_user <- function( apps_usage %>% filter( .data$started >= start_date & - .data$started <= end_date & - .data$app_name == !!selected_app() + .data$started <= end_date & + .data$app_name == !!selected_app() ) %>% group_by(.data$username) %>% summarise(cum_duration = as.numeric(round(sum(.data$duration) / 3600, 1))) %>% @@ -165,10 +232,10 @@ create_cumulated_duration_per_user <- function( #' @importFrom rlang .data #' @importFrom shiny req is.reactive create_cumulated_hits_per_user <- function( - apps_usage, - start_date = NULL, - end_date = NULL, - selected_app + apps_usage, + start_date = NULL, + end_date = NULL, + selected_app ) { username <- NULL @@ -183,8 +250,8 @@ create_cumulated_hits_per_user <- function( apps_usage %>% filter( .data$started >= start_date & - .data$started <= end_date & - .data$app_name == !!selected_app() + .data$started <= end_date & + .data$app_name == !!selected_app() ) %>% group_by(.data$username) %>% summarise(n = n()) %>% # prefer summarize over sort to remove grouping diff --git a/R/helpers-data.R b/R/helpers-data.R index 808b84b..c35c88f 100644 --- a/R/helpers-data.R +++ b/R/helpers-data.R @@ -3,15 +3,15 @@ #' @param app app_name to filter. #' @param logs Given by RSC database. #' -#' @return A vector containing dates of usage for -#' the given app. +#' @return A tibble containing dates of usage for +#' the given app as well as the correponding session duration. #' @import dplyr #' @export #' @importFrom rlang .data get_rsc_app_dates <- function(app, logs) { logs %>% filter(.data$app_name == !!app) %>% - pull(.data$started) + select(.data$started, .data$duration) } @@ -22,7 +22,7 @@ get_rsc_app_dates <- function(app, logs) { #' @param logs Given by RSC database. #' #' @return A 3 columns tibble with app name, usage and date of usage (nested tibble). -#' @import dplyr purrr +#' @import dplyr purrr lubridate #' @export #' @importFrom rlang .data get_rsc_apps_usage <- function(logs) { @@ -31,7 +31,6 @@ get_rsc_apps_usage <- function(logs) { tmp_apps_usage <- logs %>% group_by(.data$app_name) %>% count(sort = TRUE) - # handle dates. It's quite heavy but we need for # each app the dates of usage and a count for each date. # Reason why we use table(). We also need to nest them @@ -44,19 +43,29 @@ get_rsc_apps_usage <- function(logs) { get_rsc_app_dates, logs ) %>% - map(tibble::as_tibble) %>% map( ~ { - tbl <- ..1 %>% + dat_in <- ..1 %>% # Be careful, RSC provides datetime format but # this is too specific to count at the scale of a day. # We must floor to the corresponding day. - mutate(value = lubridate::floor_date(value, "day")) %>% + mutate(started = floor_date(.data$started, "day")) + + tbl <- dat_in %>% + select(-.data$duration) %>% table() %>% tibble::as_tibble() names(tbl) <- c("Date", "Freq") - tbl + + # Create duration table + cumulated_durations <- do.call(rbind.data.frame, map(tbl$Date, ~ { + dat_in %>% + filter(started == as_datetime(..1)) %>% + summarise(cum_dur = minute(seconds_to_period(sum(.data$duration, na.rm = TRUE)))) + })) + + cbind(tbl, cumulated_durations) } ) %>% map(nest_by, .key = "calendar_data") %>% @@ -270,7 +279,7 @@ get_user_daily_consumption <- function(content, users, apps, selected_user) { grouped_by_date <- reactive({ req(nrow(events()) > 0) events() %>% - mutate(floored_started = lubridate::floor_date(.data$started, "day")) %>% + mutate(floored_started = floor_date(.data$started, "day")) %>% group_by(.data$floored_started) %>% count(sort = TRUE) %>% select(Date = .data$floored_started, Freq = .data$n) @@ -284,6 +293,10 @@ get_user_daily_consumption <- function(content, users, apps, selected_user) { #' See \link{create_app_ranking_table}. #' #' @inheritParams merge_rsc_data +#' @param start_date Default to minimum calendar_data date. Could also be +#' an input value with Shiny. +#' @param end_date Default to maximum calendar_data date. Could also be +#' an input value with Shiny. #' #' @return A list containing: `[[1]]` merged data between app usage and users data. #' `[[2]]`: data to be digested by \link{create_app_ranking_table}. @@ -291,9 +304,21 @@ get_user_daily_consumption <- function(content, users, apps, selected_user) { #' @import dplyr #' @importFrom rlang .data quo eval_tidy #' @importFrom shiny reactive is.reactive -create_app_ranking <- function(content, users, apps) { +create_app_ranking <- function(content, users, apps, start_date = NULL, end_date = NULL) { tmp <- quo({ rsc_data_merged <- merge_rsc_data(content, users, apps) + if (is.null(start_date)) start_date <- min(rsc_data_merged$apps_usage_merged$started) + # Note: this might be surprising but some end date are not available in ended so + # we have to take the max of the start date. + if (is.null(end_date)) end_date <- max(rsc_data_merged$apps_usage_merged$started) + if (is.reactive(start_date)) start_date <- start_date() + if (is.reactive(end_date)) end_date <- end_date() + + rsc_data_merged[[3]] <- rsc_data_merged[[3]] %>% + filter( + .data$started >= start_date & + .data$started <= end_date + ) processed_rsc_apps_usage <- rsc_data_merged[[3]] %>% get_rsc_apps_usage() %>% @@ -308,7 +333,8 @@ create_app_ranking <- function(content, users, apps) { list(rsc_data_merged[[3]], processed_rsc_apps_usage) }) - if (is.reactive(users) || is.reactive(content) || is.reactive(apps)) { + if (is.reactive(users) || is.reactive(content) || is.reactive(apps) || + is.reactive(start_date) || is.reactive(end_date)) { if (is.reactive(users)) user <- users() if (is.reactive(content)) content <- content() if (is.reactive(apps)) apps <- apps() @@ -396,15 +422,22 @@ create_dev_ranking <- function(users, content) { #' Sort RStudio Connect users by role #' #' Users are grouped by user_role to check the -#' server role repartition. +#' server role repartition. Using start_date and end_date allows +#' to filter data given a specific time range. #' #' @param users Get from \link[connectapi]{get_users}. +#' @param start_date Date filter. +#' @param end_date Date filter. #' #' @return A tibble with user grouped by role. #' @export #' @importFrom rlang .data -sort_users_by_role <- function(users) { +sort_users_by_role <- function(users, start_date = NULL, end_date = NULL) { + if (is.null(start_date)) start_date <- min(users$created_time) + if (is.null(end_date)) end_date <- max(users$created_time) + users %>% + filter(.data$created_time >= start_date & .data$created_time <= end_date) %>% group_by(.data$user_role) %>% summarize(n = n()) %>% mutate(Percentage = round(n / sum(n) * 100)) @@ -415,12 +448,17 @@ sort_users_by_role <- function(users) { #' #' #' @param content Get from \link[connectapi]{get_content}. +#' @inheritParams sort_users_by_role #' #' @return A tibble with content grouped by access type. #' @export #' @importFrom rlang .data -sort_content_by_access <- function(content) { +sort_content_by_access <- function(content, start_date = NULL, end_date = NULL) { + if (is.null(start_date)) start_date <- min(content$created_time) + if (is.null(end_date)) end_date <- max(content$created_time) + content %>% + filter(.data$created_time >= start_date & .data$created_time <= end_date) %>% group_by(.data$access_type) %>% summarize(n = n()) %>% mutate(Percentage = round(n / sum(n) * 100)) @@ -432,13 +470,21 @@ sort_content_by_access <- function(content) { #' #' #' @param content Get from \link[connectapi]{get_content}. +#' @inheritParams sort_users_by_role #' #' @return A tibble with content grouped by R version. #' @export #' @importFrom rlang .data -sort_content_by_rversion <- function(content) { +sort_content_by_rversion <- function(content, start_date = NULL, end_date = NULL) { + if (is.null(start_date)) start_date <- min(content$created_time) + if (is.null(end_date)) end_date <- max(content$created_time) + content %>% - filter(!is.na(.data$r_version)) %>% + filter( + !is.na(.data$r_version) & + .data$created_time >= start_date & + .data$created_time <= end_date + ) %>% group_by(.data$r_version) %>% summarize(n = n()) %>% mutate(Percentage = round(n / sum(n) * 100, 1)) @@ -464,12 +510,17 @@ sort_content_by_pyversion <- function(content) { #' #' #' @param content Get from \link[connectapi]{get_content}. +#' @inheritParams sort_users_by_role #' #' @return A tibble with content grouped by app mode. #' @export #' @importFrom rlang .data -sort_content_by_appmode <- function(content) { +sort_content_by_appmode <- function(content, start_date = NULL, end_date = NULL) { + if (is.null(start_date)) start_date <- min(content$created_time) + if (is.null(end_date)) end_date <- max(content$created_time) + content %>% + filter(.data$created_time >= start_date & .data$created_time <= end_date) %>% group_by(.data$app_mode) %>% summarize(n = n()) %>% mutate(Percentage = round(n / sum(n) * 100, 1)) diff --git a/R/helpers-tables.R b/R/helpers-tables.R index f70654d..c6660be 100644 --- a/R/helpers-tables.R +++ b/R/helpers-tables.R @@ -74,13 +74,13 @@ create_table_sparkline <- function(table) { column = "calendar_data", renderer = function(data) { data$Month <- data$Date %>% purrr::map(~ { - lubridate::month(..1, label = TRUE) + month(..1, label = TRUE) }) %>% unlist() %>% as.character() data$Month_code <- data$Date %>% purrr::map_dbl(~ { - lubridate::month(..1) + month(..1) }) # gather by month since it is too laggy @@ -116,5 +116,6 @@ create_table_sparkline <- function(table) { #' usage. #' @export create_app_ranking_table <- function(ranking, pagination = 10, height = NULL) { + if (is.reactive(ranking)) ranking <- ranking() ranking[[2]] %>% generate_table(sparkline = TRUE, pagination, height) } diff --git a/inst/examples/shiny/app.R b/inst/examples/shiny/app.R new file mode 100644 index 0000000..4404840 --- /dev/null +++ b/inst/examples/shiny/app.R @@ -0,0 +1,313 @@ +library(shiny) +library(connectapi) # Tested with 0.1.0.9031 +library(connectViz) +library(dplyr) +library(bslib) +library(echarts4r) +library(toastui) +library(visNetwork) + +rsc_client <- create_rsc_client() + +# TO DO: refresh this in the background +apps_usage <- rsc_client %>% get_usage_shiny(limit = Inf) +rsc_content <- rsc_client %>% get_content() +# Remove locked users? +rsc_users <- rsc_client %>% get_users(limit = Inf) %>% + filter(locked == FALSE) +publishers <- rsc_users %>% filter(user_role == "publisher") +shiny_apps <- rsc_content %>% filter(app_mode == "shiny") + +general_metrics <- list( + "Onboarded Users" = nrow(rsc_users), + "Publishers" = nrow(publishers), + "Deployments" = nrow(rsc_content), + "Shiny Apps" = nrow(shiny_apps) +) + +general_metrics_cards <- purrr::map( + seq_along(general_metrics), + function(i) { + value_box( + theme_color = "secondary", + value = general_metrics[[i]], + title = names(general_metrics)[[i]] + ) + } +) + +developers_apps_ranking <- create_dev_ranking(rsc_users, rsc_content) +max_app <- developers_apps_ranking %>% pull(n_apps) %>% max() + +ui <- page_navbar( + title = "Shiny apps usage", + sidebar = tagList( + dateRangeInput( + "date_range", + "Select the app usage range:", + start = min(rsc_content[["created_time"]]), + end = Sys.Date() + ), + span( + "About usage data", + tooltip( + icon("info-circle"), + "Important: with a standard Posit Connect API key, you can ONLY see the content + YOU OWN. Admin API key has access to ALL data." + ) + ) + ), + nav_panel( + "General metrics", + layout_columns( + fill = FALSE, + !!!general_metrics_cards + ), + layout_columns( + col_widths = rep(6, 4), + card( + card_header("User roles"), + full_screen = TRUE, + min_height = "400px", + echarts4rOutput("roles_chart"), + ), + card( + card_header("Content access type"), + full_screen = TRUE, + min_height = "400px", + echarts4rOutput("content_access"), + ), + card( + card_header("R versions"), + full_screen = TRUE, + min_height = "400px", + echarts4rOutput("r_versions"), + ), + card( + card_header("Content type"), + full_screen = TRUE, + min_height = "400px", + echarts4rOutput("content_type"), + ) + ) + ), + nav_panel( + "App data", + h3("Apps ranking"), + card( + full_screen = TRUE, + min_height = "400px", + datagridOutput("apps_ranking_chart") + ), + h3("Single app usage"), + card( + full_screen = TRUE, + min_height = "1200px", + layout_sidebar( + sidebar = sidebar( + width = 150, + selectInput( + "selected_app", + "Select an application", + choices = NULL + ) + ), + echarts4rOutput("daily_usage_chart"), + dataTableOutput("daily_usage_table"), + echarts4rOutput("daily_sessions_chart"), + p("User consumption"), + echarts4rOutput("cumulated_duration_per_user_chart"), + echarts4rOutput("cumulated_hits_per_user_chart"), + + ) + ) + ), + nav_panel( + "Consumer data", + card( + full_screen = TRUE, + min_height = "400px", + card_header("Consumer ranking"), + layout_sidebar( + sidebar = sidebar( + width = 150, + numericInput( + "views_threshold", + "N view threshold", + 1, + min = 0 + ) + ), + echarts4rOutput("consumer_ranking_chart") + ) + ), + card( + full_screen = TRUE, + min_height = "400px", + card_header("Daily app consumption"), + layout_sidebar( + sidebar = sidebar( + width = 150, + selectInput("selected_user", "Select a user", rsc_users$username) + ), + echarts4rOutput("daily_consumption_chart") + ) + ) + ), + nav_panel( + "Developer data", + card( + full_screen = TRUE, + min_height = "400px", + card_header("Developers ranking n deployments (static, shiny, rmd, ...)"), + layout_sidebar( + sidebar = sidebar( + width = 150, + numericInput( + "apps_threshold", + "N app threshold", + round(max_app / 2), + min = 1, + max = max_app + ) + ), + echarts4rOutput("dev_ranking_chart") + ) + ), + card( + full_screen = TRUE, + min_height = "400px", + card_header("Dev projects overview (Shiny apps only)"), + layout_sidebar( + sidebar = sidebar( + width = 150, + selectInput( + "app_developer", + "Select a developer", + developers_apps_ranking$username + ) + ), + visNetworkOutput("dev_projects_network") + ) + ) + ) +) + +server <- function(input, output, session) { + +# Apps ranking ------------------------------------------------------------ + + apps_ranking <- create_app_ranking( + rsc_content, + rsc_users, + apps_usage, + start_date = reactive(input$date_range[1]), + end_date = reactive(input$date_range[2]) + ) + + range_text <- reactive({ + sprintf("between %s and %s", input$date_range[1], input$date_range[2]) + }) + + output$app_usage_title <- renderText({ + sprintf("Shiny Apps usage %s", range_text()) + }) + + output$apps_ranking_chart <- renderDatagrid({ + create_app_ranking_table(apps_ranking) + }) + +# App usage --------------------------------------------------------------- + + daily_app_usage <- get_app_daily_usage(reactive(apps_ranking()[[2]]), reactive(input$selected_app)) + + observeEvent(apps_ranking(), { + updateSelectInput( + session, + "selected_app", + choices = apps_ranking()[[2]]$app_name + ) + }) + + output$daily_usage_chart <- create_app_daily_usage_chart(daily_app_usage) + output$daily_usage_table <- renderDataTable({ + req(input$selected_date) + apps_ranking()[[1]] %>% + mutate( + started = lubridate::as_date(started), + duration = lubridate::minute(lubridate::seconds_to_period(duration)) + ) %>% + filter( + .data$app_name == input$selected_app & + .data$started == input$selected_date + ) %>% + select(username, duration) + }, options = list(colnames = c("duration (in minutes)" = 2), pageLength = 5)) + output$daily_sessions_chart <-create_app_daily_session_chart(daily_app_usage) + + output$cumulated_duration_per_user_chart <- create_cumulated_duration_per_user( + reactive(apps_ranking()[[1]]), + selected_app = reactive(input$selected_app) + ) + output$cumulated_hits_per_user_chart <- create_cumulated_hits_per_user( + reactive(apps_ranking()[[1]]), + selected_app = reactive(input$selected_app) + ) + +# User consumption -------------------------------------------------------- + + consumer_ranking <- create_apps_consumer_ranking(apps_usage, rsc_users) + output$consumer_ranking_chart <- create_apps_consumer_ranking_chart( + consumer_ranking, reactive(input$views_threshold) + ) + + daily_consumption <- get_user_daily_consumption( + rsc_content, + rsc_users, + apps_usage, + reactive(input$selected_user) + ) + + output$daily_consumption_chart <- create_user_daily_consumption_chart(daily_consumption[[2]]) + + +# Developers data --------------------------------------------------------- + + output$dev_ranking_chart <- create_dev_ranking_chart( + developers_apps_ranking, + reactive(input$apps_threshold) + ) + + output$dev_projects_network <- create_dev_project_overview( + rsc_client, reactive(apps_ranking()[[1]]), + reactive(input$app_developer) + ) + + +# General data ------------------------------------------------------------ + output$roles_chart <- renderEcharts4r({ + tmp <- sort_users_by_role(rsc_users, input$date_range[1], input$date_range[2]) + validate(need(nrow(tmp) > 0, "No data found")) + tmp %>% create_pie_chart("user_role") + }) + + output$content_access <- renderEcharts4r({ + tmp <- sort_content_by_access(rsc_content, input$date_range[1], input$date_range[2]) + validate(need(nrow(tmp) > 0, "No data found")) + tmp %>% create_pie_chart("access_type") + }) + + output$r_versions <- renderEcharts4r({ + tmp <- sort_content_by_rversion(rsc_content, input$date_range[1], input$date_range[2]) + validate(need(nrow(tmp) > 0, "No data found")) + tmp %>% create_pie_chart("r_version") + }) + + output$content_type <- renderEcharts4r({ + tmp <- sort_content_by_appmode(rsc_content, input$date_range[1], input$date_range[2]) + validate(need(nrow(tmp) > 0, "No data found")) + tmp %>% create_pie_chart("app_mode") + }) +} + +shinyApp(ui, server) diff --git a/inst/examples/simple-rmd/analysis.Rmd b/inst/examples/simple-rmd/analysis.Rmd index 61e379f..399434d 100644 --- a/inst/examples/simple-rmd/analysis.Rmd +++ b/inst/examples/simple-rmd/analysis.Rmd @@ -68,45 +68,62 @@ Important note: with a basic __publisher__ API key, we can only recover the data #### Most used apps ```{r} -apps_ranking <- create_app_ranking(rsc_content, rsc_users, apps_usage) -card( - full_screen = TRUE, - create_app_ranking_table(apps_ranking), +dateRangeInput( + "date_range", + "Select the app usage range:", + start = Sys.Date() - 10, + end = Sys.Date() +) +apps_ranking <- create_app_ranking( + rsc_content, + rsc_users, + apps_usage, + start_date = reactive(input$date_range[1]), + end_date = reactive(input$date_range[2]) ) + +renderUI({ + card( + full_screen = TRUE, + title = sprintf("Ranking between %s and %s", input$date_range[1], input$date_range[2]), + create_app_ranking_table(apps_ranking), + ) +}) ``` #### Daily app usage ```{r} - -daily_app_usage <- get_app_daily_usage(apps_ranking[[2]], reactive(input$selected_app)) +daily_app_usage <- get_app_daily_usage(apps_ranking()[[2]], reactive(input$selected_app)) ``` ```{r} -card( - full_screen = TRUE, - card_header("App usage"), - layout_sidebar( - sidebar = sidebar( - width = 150, - selectInput( - "selected_app", - "Select an application", - apps_ranking[[2]]$app_name +renderUI({ + card( + full_screen = TRUE, + card_header("App usage"), + layout_sidebar( + sidebar = sidebar( + width = 150, + selectInput( + "selected_app", + "Select an application", + apps_ranking()[[2]]$app_name + ) + ), + p("Daily app usage"), + create_app_daily_usage_chart(daily_app_usage), + create_cumulated_duration_per_user( + apps_ranking()[[1]], + selected_app = reactive(input$selected_app) + ), + create_cumulated_hits_per_user( + apps_ranking()[[1]], + selected_app = reactive(input$selected_app) ) - ), - p("Daily app usage"), - create_app_daily_usage_chart(daily_app_usage), - create_cumulated_duration_per_user( - apps_ranking[[1]], - selected_app = reactive(input$selected_app) - ), - create_cumulated_hits_per_user( - apps_ranking[[1]], - selected_app = reactive(input$selected_app) ) ) -) +}) ``` ### Consumer data @@ -197,7 +214,7 @@ dev_projects_card <- card( ) ), create_dev_project_overview( - rsc_client, apps_ranking[[1]], + rsc_client, apps_ranking()[[1]], reactive(input$app_developer) ) ) diff --git a/man/create_app_daily_session_chart.Rd b/man/create_app_daily_session_chart.Rd new file mode 100644 index 0000000..0524866 --- /dev/null +++ b/man/create_app_daily_session_chart.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/helpers-charts.R +\name{create_app_daily_session_chart} +\alias{create_app_daily_session_chart} +\title{Generic calendar chart generator} +\usage{ +create_app_daily_session_chart( + calendar_data, + title = "Cumulated daily usage", + subtitle = "time units: minutes", + start_date = NULL, + end_date = NULL, + callback = NULL +) +} +\arguments{ +\item{calendar_data}{Calendar chart data.} + +\item{title}{Chart title.} + +\item{subtitle}{Chart subtitle.} + +\item{start_date}{Default to minimum calendar_data date. Could also be +an input value with Shiny.} + +\item{end_date}{Default to maximum calendar_data date. Could also be +an input value with Shiny.} + +\item{callback}{JS function to pass to \link[htmlwidgets]{onRender}. This is +useful to access the widget API on the R side at render time +and add events on the fly.} +} +\value{ +An echarts4r line chart +} +\description{ +Generic calendar chart generator +} diff --git a/man/create_app_daily_usage_chart.Rd b/man/create_app_daily_usage_chart.Rd index 91184f3..0c589f3 100644 --- a/man/create_app_daily_usage_chart.Rd +++ b/man/create_app_daily_usage_chart.Rd @@ -4,10 +4,12 @@ \alias{create_app_daily_usage_chart} \title{Daily app usage chart} \usage{ -create_app_daily_usage_chart(app_usage) +create_app_daily_usage_chart(app_usage, ...) } \arguments{ \item{app_usage}{Returned by \link{get_app_daily_usage}.} + +\item{...}{Pass down any param to \link{create_calendar_chart}.} } \value{ A calendar chart displaying daily app usage. diff --git a/man/create_app_ranking.Rd b/man/create_app_ranking.Rd index f430276..f313947 100644 --- a/man/create_app_ranking.Rd +++ b/man/create_app_ranking.Rd @@ -4,7 +4,7 @@ \alias{create_app_ranking} \title{Process app data for ranking table} \usage{ -create_app_ranking(content, users, apps) +create_app_ranking(content, users, apps, start_date = NULL, end_date = NULL) } \arguments{ \item{content}{Get from \link[connectapi]{get_content}. Can be reactive.} @@ -12,6 +12,12 @@ create_app_ranking(content, users, apps) \item{users}{Get from \link[connectapi]{get_users}. Can be reactive.} \item{apps}{Get from \link[connectapi]{get_usage_shiny}. Can be reactive.} + +\item{start_date}{Default to minimum calendar_data date. Could also be +an input value with Shiny.} + +\item{end_date}{Default to maximum calendar_data date. Could also be +an input value with Shiny.} } \value{ A list containing: \verb{[[1]]} merged data between app usage and users data. diff --git a/man/get_rsc_app_dates.Rd b/man/get_rsc_app_dates.Rd index b2196b7..7a2ae8e 100644 --- a/man/get_rsc_app_dates.Rd +++ b/man/get_rsc_app_dates.Rd @@ -12,8 +12,8 @@ get_rsc_app_dates(app, logs) \item{logs}{Given by RSC database.} } \value{ -A vector containing dates of usage for -the given app. +A tibble containing dates of usage for +the given app as well as the correponding session duration. } \description{ Extract app usage dates diff --git a/man/sort_content_by_access.Rd b/man/sort_content_by_access.Rd index 563718b..4b843ee 100644 --- a/man/sort_content_by_access.Rd +++ b/man/sort_content_by_access.Rd @@ -4,10 +4,14 @@ \alias{sort_content_by_access} \title{Sort RStudio Connect content by access type} \usage{ -sort_content_by_access(content) +sort_content_by_access(content, start_date = NULL, end_date = NULL) } \arguments{ \item{content}{Get from \link[connectapi]{get_content}.} + +\item{start_date}{Date filter.} + +\item{end_date}{Date filter.} } \value{ A tibble with content grouped by access type. diff --git a/man/sort_content_by_appmode.Rd b/man/sort_content_by_appmode.Rd index 3e1a650..b4352ce 100644 --- a/man/sort_content_by_appmode.Rd +++ b/man/sort_content_by_appmode.Rd @@ -4,10 +4,14 @@ \alias{sort_content_by_appmode} \title{Sort RStudio Connect content by app mode} \usage{ -sort_content_by_appmode(content) +sort_content_by_appmode(content, start_date = NULL, end_date = NULL) } \arguments{ \item{content}{Get from \link[connectapi]{get_content}.} + +\item{start_date}{Date filter.} + +\item{end_date}{Date filter.} } \value{ A tibble with content grouped by app mode. diff --git a/man/sort_content_by_rversion.Rd b/man/sort_content_by_rversion.Rd index beafb10..77b517c 100644 --- a/man/sort_content_by_rversion.Rd +++ b/man/sort_content_by_rversion.Rd @@ -4,10 +4,14 @@ \alias{sort_content_by_rversion} \title{Sort RStudio Connect content by R version} \usage{ -sort_content_by_rversion(content) +sort_content_by_rversion(content, start_date = NULL, end_date = NULL) } \arguments{ \item{content}{Get from \link[connectapi]{get_content}.} + +\item{start_date}{Date filter.} + +\item{end_date}{Date filter.} } \value{ A tibble with content grouped by R version. diff --git a/man/sort_users_by_role.Rd b/man/sort_users_by_role.Rd index 48b5b92..bcce3cd 100644 --- a/man/sort_users_by_role.Rd +++ b/man/sort_users_by_role.Rd @@ -4,15 +4,20 @@ \alias{sort_users_by_role} \title{Sort RStudio Connect users by role} \usage{ -sort_users_by_role(users) +sort_users_by_role(users, start_date = NULL, end_date = NULL) } \arguments{ \item{users}{Get from \link[connectapi]{get_users}.} + +\item{start_date}{Date filter.} + +\item{end_date}{Date filter.} } \value{ A tibble with user grouped by role. } \description{ Users are grouped by user_role to check the -server role repartition. +server role repartition. Using start_date and end_date allows +to filter data given a specific time range. }