mirror of
https://github.com/rstudio/shiny.git
synced 2026-04-29 03:00:45 -04:00
feat(reactlog): Add reactlogAddMark() (#4103)
This commit is contained in:
@@ -206,7 +206,7 @@ Collate:
|
|||||||
'version_selectize.R'
|
'version_selectize.R'
|
||||||
'version_strftime.R'
|
'version_strftime.R'
|
||||||
'viewer.R'
|
'viewer.R'
|
||||||
RoxygenNote: 7.3.1
|
RoxygenNote: 7.3.2
|
||||||
Encoding: UTF-8
|
Encoding: UTF-8
|
||||||
Roxygen: list(markdown = TRUE)
|
Roxygen: list(markdown = TRUE)
|
||||||
RdMacros: lifecycle
|
RdMacros: lifecycle
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ export(reactiveVal)
|
|||||||
export(reactiveValues)
|
export(reactiveValues)
|
||||||
export(reactiveValuesToList)
|
export(reactiveValuesToList)
|
||||||
export(reactlog)
|
export(reactlog)
|
||||||
|
export(reactlogAddMark)
|
||||||
export(reactlogReset)
|
export(reactlogReset)
|
||||||
export(reactlogShow)
|
export(reactlogShow)
|
||||||
export(registerInputHandler)
|
export(registerInputHandler)
|
||||||
|
|||||||
6
NEWS.md
6
NEWS.md
@@ -3,13 +3,19 @@
|
|||||||
## New features and improvements
|
## New features and improvements
|
||||||
|
|
||||||
* Added new functions, `useBusyIndicators()` and `busyIndicatorOptions()`, for enabling and customizing busy indication. Busy indicators provide a visual cue to users when the server is busy calculating outputs or otherwise serving requests to the client. When enabled, a spinner is shown on each calculating/recalculating output, and a pulsing banner is shown at the top of the page when the app is otherwise busy. (#4040)
|
* Added new functions, `useBusyIndicators()` and `busyIndicatorOptions()`, for enabling and customizing busy indication. Busy indicators provide a visual cue to users when the server is busy calculating outputs or otherwise serving requests to the client. When enabled, a spinner is shown on each calculating/recalculating output, and a pulsing banner is shown at the top of the page when the app is otherwise busy. (#4040)
|
||||||
|
|
||||||
* Output bindings now include the `.recalculating` CSS class when they are first bound, up until the first render. This makes it possible/easier to show progress indication when the output is calculating for the first time. (#4039)
|
* Output bindings now include the `.recalculating` CSS class when they are first bound, up until the first render. This makes it possible/easier to show progress indication when the output is calculating for the first time. (#4039)
|
||||||
|
|
||||||
* A new `shiny.client_devmode` option controls client-side devmode features, in particular the client-side error console introduced in shiny 1.8.1, independently of the R-side features of `shiny::devmode()`. This usage is primarily intended for automatic use in Shinylive. (#4073)
|
* A new `shiny.client_devmode` option controls client-side devmode features, in particular the client-side error console introduced in shiny 1.8.1, independently of the R-side features of `shiny::devmode()`. This usage is primarily intended for automatic use in Shinylive. (#4073)
|
||||||
|
|
||||||
|
* Added function `reactlogAddMark()` to programmatically add _mark_ed locations in the reactlog log without the requirement of keyboard bindings during an idle reactive moment. (#4103)
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
|
|
||||||
* `downloadButton()` and `downloadLink()` are now disabled up until they are fully initialized. This prevents the user from clicking the button/link before the download is ready. (#4041)
|
* `downloadButton()` and `downloadLink()` are now disabled up until they are fully initialized. This prevents the user from clicking the button/link before the download is ready. (#4041)
|
||||||
|
|
||||||
* Output bindings that are removed, invalidated, then inserted again (while invalidated) now correctly include the `.recalculating` CSS class. (#4039)
|
* Output bindings that are removed, invalidated, then inserted again (while invalidated) now correctly include the `.recalculating` CSS class. (#4039)
|
||||||
|
|
||||||
* Fixed a recent issue with `uiOutput()` and `conditionalPanel()` not properly lower opacity when recalculation (in a Bootstrap 5 context). (#4027)
|
* Fixed a recent issue with `uiOutput()` and `conditionalPanel()` not properly lower opacity when recalculation (in a Bootstrap 5 context). (#4027)
|
||||||
|
|
||||||
# shiny 1.8.1.1
|
# shiny 1.8.1.1
|
||||||
|
|||||||
122
R/graph.R
122
R/graph.R
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# domain is like session
|
# domain is like session
|
||||||
|
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ reactIdStr <- function(num) {
|
|||||||
#' dependencies and execution in your application.
|
#' dependencies and execution in your application.
|
||||||
#'
|
#'
|
||||||
#' To use the reactive log visualizer, start with a fresh R session and
|
#' To use the reactive log visualizer, start with a fresh R session and
|
||||||
#' run the command `options(shiny.reactlog=TRUE)`; then launch your
|
#' run the command `reactlog::reactlog_enable()`; then launch your
|
||||||
#' application in the usual way (e.g. using [runApp()]). At
|
#' application in the usual way (e.g. using [runApp()]). At
|
||||||
#' any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
|
#' any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
|
||||||
#' web browser to launch the reactive log visualization.
|
#' web browser to launch the reactive log visualization.
|
||||||
@@ -43,16 +42,20 @@ reactIdStr <- function(num) {
|
|||||||
#' call `reactlogShow()` explicitly.
|
#' call `reactlogShow()` explicitly.
|
||||||
#'
|
#'
|
||||||
#' For security and performance reasons, do not enable
|
#' For security and performance reasons, do not enable
|
||||||
#' `shiny.reactlog` in production environments. When the option is
|
#' `options(shiny.reactlog=TRUE)` (or `reactlog::reactlog_enable()`) in
|
||||||
#' enabled, it's possible for any user of your app to see at least some
|
#' production environments. When the option is enabled, it's possible
|
||||||
#' of the source code of your reactive expressions and observers.
|
#' for any user of your app to see at least some of the source code of
|
||||||
|
#' your reactive expressions and observers. In addition, reactlog
|
||||||
|
#' should be considered a memory leak as it will constantly grow and
|
||||||
|
#' will never reset until the R session is restarted.
|
||||||
#'
|
#'
|
||||||
#' @name reactlog
|
#' @name reactlog
|
||||||
NULL
|
NULL
|
||||||
|
|
||||||
|
|
||||||
#' @describeIn reactlog Return a list of reactive information. Can be used in conjunction with
|
#' @describeIn reactlog Return a list of reactive information. Can be used in
|
||||||
#' [reactlog::reactlog_show] to later display the reactlog graph.
|
#' conjunction with [reactlog::reactlog_show] to later display the reactlog
|
||||||
|
#' graph.
|
||||||
#' @export
|
#' @export
|
||||||
reactlog <- function() {
|
reactlog <- function() {
|
||||||
rLog$asList()
|
rLog$asList()
|
||||||
@@ -67,12 +70,34 @@ reactlogShow <- function(time = TRUE) {
|
|||||||
reactlog::reactlog_show(reactlog(), time = time)
|
reactlog::reactlog_show(reactlog(), time = time)
|
||||||
}
|
}
|
||||||
|
|
||||||
#' @describeIn reactlog Resets the entire reactlog stack. Useful for debugging and removing all prior reactive history.
|
#' @describeIn reactlog Resets the entire reactlog stack. Useful for debugging
|
||||||
|
#' and removing all prior reactive history.
|
||||||
#' @export
|
#' @export
|
||||||
reactlogReset <- function() {
|
reactlogReset <- function() {
|
||||||
rLog$reset()
|
rLog$reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#' @describeIn reactlog Adds "mark" entry into the reactlog stack. This is
|
||||||
|
#' useful for programmatically adding a marked entry in the reactlog, rather
|
||||||
|
#' than using your keyboard's key combination.
|
||||||
|
#'
|
||||||
|
#' For example, we can _mark_ the reactlog at the beginning of an
|
||||||
|
#' `observeEvent`'s calculation:
|
||||||
|
#' ```r
|
||||||
|
#' observeEvent(input$my_event_trigger, {
|
||||||
|
#' # Add a mark in the reactlog
|
||||||
|
#' reactlogAddMark()
|
||||||
|
#' # Run your regular event reaction code here...
|
||||||
|
#' ....
|
||||||
|
#' })
|
||||||
|
#' ```
|
||||||
|
#' @param session The Shiny session to assign the mark to. Defaults to the
|
||||||
|
#' current session.
|
||||||
|
#' @export
|
||||||
|
reactlogAddMark <- function(session = getDefaultReactiveDomain()) {
|
||||||
|
rLog$userMark(session)
|
||||||
|
}
|
||||||
|
|
||||||
# called in "/reactlog" middleware
|
# called in "/reactlog" middleware
|
||||||
renderReactlog <- function(sessionToken = NULL, time = TRUE) {
|
renderReactlog <- function(sessionToken = NULL, time = TRUE) {
|
||||||
check_reactlog()
|
check_reactlog()
|
||||||
@@ -98,7 +123,6 @@ RLog <- R6Class(
|
|||||||
private = list(
|
private = list(
|
||||||
option = "shiny.reactlog",
|
option = "shiny.reactlog",
|
||||||
msgOption = "shiny.reactlog.console",
|
msgOption = "shiny.reactlog.console",
|
||||||
|
|
||||||
appendEntry = function(domain, logEntry) {
|
appendEntry = function(domain, logEntry) {
|
||||||
if (self$isLogging()) {
|
if (self$isLogging()) {
|
||||||
sessionToken <- if (is.null(domain)) NULL else domain$token
|
sessionToken <- if (is.null(domain)) NULL else domain$token
|
||||||
@@ -113,20 +137,19 @@ RLog <- R6Class(
|
|||||||
public = list(
|
public = list(
|
||||||
msg = "<MessageLogger>",
|
msg = "<MessageLogger>",
|
||||||
logStack = "<Stack>",
|
logStack = "<Stack>",
|
||||||
|
|
||||||
noReactIdLabel = "NoCtxReactId",
|
noReactIdLabel = "NoCtxReactId",
|
||||||
noReactId = reactIdStr("NoCtxReactId"),
|
noReactId = reactIdStr("NoCtxReactId"),
|
||||||
dummyReactIdLabel = "DummyReactId",
|
dummyReactIdLabel = "DummyReactId",
|
||||||
dummyReactId = reactIdStr("DummyReactId"),
|
dummyReactId = reactIdStr("DummyReactId"),
|
||||||
|
|
||||||
asList = function() {
|
asList = function() {
|
||||||
ret <- self$logStack$as_list()
|
ret <- self$logStack$as_list()
|
||||||
attr(ret, "version") <- "1"
|
attr(ret, "version") <- "1"
|
||||||
ret
|
ret
|
||||||
},
|
},
|
||||||
|
|
||||||
ctxIdStr = function(ctxId) {
|
ctxIdStr = function(ctxId) {
|
||||||
if (is.null(ctxId) || identical(ctxId, "")) return(NULL)
|
if (is.null(ctxId) || identical(ctxId, "")) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
paste0("ctx", ctxId)
|
paste0("ctx", ctxId)
|
||||||
},
|
},
|
||||||
namesIdStr = function(reactId) {
|
namesIdStr = function(reactId) {
|
||||||
@@ -141,7 +164,6 @@ RLog <- R6Class(
|
|||||||
keyIdStr = function(reactId, key) {
|
keyIdStr = function(reactId, key) {
|
||||||
paste0(reactId, "$", key)
|
paste0(reactId, "$", key)
|
||||||
},
|
},
|
||||||
|
|
||||||
valueStr = function(value, n = 200) {
|
valueStr = function(value, n = 200) {
|
||||||
if (!self$isLogging()) {
|
if (!self$isLogging()) {
|
||||||
# return a placeholder string to avoid calling str
|
# return a placeholder string to avoid calling str
|
||||||
@@ -151,10 +173,9 @@ RLog <- R6Class(
|
|||||||
# only capture the first level of the object
|
# only capture the first level of the object
|
||||||
utils::capture.output(utils::str(value, max.level = 1))
|
utils::capture.output(utils::str(value, max.level = 1))
|
||||||
})
|
})
|
||||||
outputTxt <- paste0(output, collapse="\n")
|
outputTxt <- paste0(output, collapse = "\n")
|
||||||
msg$shortenString(outputTxt, n = n)
|
msg$shortenString(outputTxt, n = n)
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize = function(rlogOption = "shiny.reactlog", msgOption = "shiny.reactlog.console") {
|
initialize = function(rlogOption = "shiny.reactlog", msgOption = "shiny.reactlog.console") {
|
||||||
private$option <- rlogOption
|
private$option <- rlogOption
|
||||||
private$msgOption <- msgOption
|
private$msgOption <- msgOption
|
||||||
@@ -174,7 +195,6 @@ RLog <- R6Class(
|
|||||||
isLogging = function() {
|
isLogging = function() {
|
||||||
isTRUE(getOption(private$option, FALSE))
|
isTRUE(getOption(private$option, FALSE))
|
||||||
},
|
},
|
||||||
|
|
||||||
define = function(reactId, value, label, type, domain) {
|
define = function(reactId, value, label, type, domain) {
|
||||||
valueStr <- self$valueStr(value)
|
valueStr <- self$valueStr(value)
|
||||||
if (msg$hasReact(reactId)) {
|
if (msg$hasReact(reactId)) {
|
||||||
@@ -205,9 +225,10 @@ RLog <- R6Class(
|
|||||||
defineObserver = function(reactId, label, domain) {
|
defineObserver = function(reactId, label, domain) {
|
||||||
self$define(reactId, value = NULL, label, "observer", domain)
|
self$define(reactId, value = NULL, label, "observer", domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
dependsOn = function(reactId, depOnReactId, ctxId, domain) {
|
dependsOn = function(reactId, depOnReactId, ctxId, domain) {
|
||||||
if (is.null(reactId)) return()
|
if (is.null(reactId)) {
|
||||||
|
return()
|
||||||
|
}
|
||||||
ctxId <- ctxIdStr(ctxId)
|
ctxId <- ctxIdStr(ctxId)
|
||||||
msg$log("dependsOn:", msg$reactStr(reactId), " on", msg$reactStr(depOnReactId), msg$ctxStr(ctxId))
|
msg$log("dependsOn:", msg$reactStr(reactId), " on", msg$reactStr(depOnReactId), msg$ctxStr(ctxId))
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
@@ -220,7 +241,6 @@ RLog <- R6Class(
|
|||||||
dependsOnKey = function(reactId, depOnReactId, key, ctxId, domain) {
|
dependsOnKey = function(reactId, depOnReactId, key, ctxId, domain) {
|
||||||
self$dependsOn(reactId, self$keyIdStr(depOnReactId, key), ctxId, domain)
|
self$dependsOn(reactId, self$keyIdStr(depOnReactId, key), ctxId, domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
dependsOnRemove = function(reactId, depOnReactId, ctxId, domain) {
|
dependsOnRemove = function(reactId, depOnReactId, ctxId, domain) {
|
||||||
ctxId <- self$ctxIdStr(ctxId)
|
ctxId <- self$ctxIdStr(ctxId)
|
||||||
msg$log("dependsOnRemove:", msg$reactStr(reactId), " on", msg$reactStr(depOnReactId), msg$ctxStr(ctxId))
|
msg$log("dependsOnRemove:", msg$reactStr(reactId), " on", msg$reactStr(depOnReactId), msg$ctxStr(ctxId))
|
||||||
@@ -234,7 +254,6 @@ RLog <- R6Class(
|
|||||||
dependsOnKeyRemove = function(reactId, depOnReactId, key, ctxId, domain) {
|
dependsOnKeyRemove = function(reactId, depOnReactId, key, ctxId, domain) {
|
||||||
self$dependsOnRemove(reactId, self$keyIdStr(depOnReactId, key), ctxId, domain)
|
self$dependsOnRemove(reactId, self$keyIdStr(depOnReactId, key), ctxId, domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
createContext = function(ctxId, label, type, prevCtxId, domain) {
|
createContext = function(ctxId, label, type, prevCtxId, domain) {
|
||||||
ctxId <- self$ctxIdStr(ctxId)
|
ctxId <- self$ctxIdStr(ctxId)
|
||||||
prevCtxId <- self$ctxIdStr(prevCtxId)
|
prevCtxId <- self$ctxIdStr(prevCtxId)
|
||||||
@@ -245,10 +264,9 @@ RLog <- R6Class(
|
|||||||
label = msg$shortenString(label),
|
label = msg$shortenString(label),
|
||||||
type = type,
|
type = type,
|
||||||
prevCtxId = prevCtxId,
|
prevCtxId = prevCtxId,
|
||||||
srcref = as.vector(attr(label, "srcref")), srcfile=attr(label, "srcfile")
|
srcref = as.vector(attr(label, "srcref")), srcfile = attr(label, "srcfile")
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
|
||||||
enter = function(reactId, ctxId, type, domain) {
|
enter = function(reactId, ctxId, type, domain) {
|
||||||
ctxId <- self$ctxIdStr(ctxId)
|
ctxId <- self$ctxIdStr(ctxId)
|
||||||
if (identical(type, "isolate")) {
|
if (identical(type, "isolate")) {
|
||||||
@@ -291,7 +309,6 @@ RLog <- R6Class(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
valueChange = function(reactId, value, domain) {
|
valueChange = function(reactId, value, domain) {
|
||||||
valueStr <- self$valueStr(value)
|
valueStr <- self$valueStr(value)
|
||||||
msg$log("valueChange:", msg$reactStr(reactId), msg$valueStr(valueStr))
|
msg$log("valueChange:", msg$reactStr(reactId), msg$valueStr(valueStr))
|
||||||
@@ -313,8 +330,6 @@ RLog <- R6Class(
|
|||||||
valueChangeKey = function(reactId, key, value, domain) {
|
valueChangeKey = function(reactId, key, value, domain) {
|
||||||
self$valueChange(self$keyIdStr(reactId, key), value, domain)
|
self$valueChange(self$keyIdStr(reactId, key), value, domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
invalidateStart = function(reactId, ctxId, type, domain) {
|
invalidateStart = function(reactId, ctxId, type, domain) {
|
||||||
ctxId <- self$ctxIdStr(ctxId)
|
ctxId <- self$ctxIdStr(ctxId)
|
||||||
if (identical(type, "isolate")) {
|
if (identical(type, "isolate")) {
|
||||||
@@ -357,7 +372,6 @@ RLog <- R6Class(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
invalidateLater = function(reactId, runningCtx, millis, domain) {
|
invalidateLater = function(reactId, runningCtx, millis, domain) {
|
||||||
msg$log("invalidateLater: ", millis, "ms", msg$reactStr(reactId), msg$ctxStr(runningCtx))
|
msg$log("invalidateLater: ", millis, "ms", msg$reactStr(reactId), msg$ctxStr(runningCtx))
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
@@ -367,14 +381,12 @@ RLog <- R6Class(
|
|||||||
millis = millis
|
millis = millis
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
|
||||||
idle = function(domain = NULL) {
|
idle = function(domain = NULL) {
|
||||||
msg$log("idle")
|
msg$log("idle")
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
action = "idle"
|
action = "idle"
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
|
||||||
asyncStart = function(domain = NULL) {
|
asyncStart = function(domain = NULL) {
|
||||||
msg$log("asyncStart")
|
msg$log("asyncStart")
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
@@ -387,7 +399,6 @@ RLog <- R6Class(
|
|||||||
action = "asyncStop"
|
action = "asyncStop"
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
|
||||||
freezeReactiveVal = function(reactId, domain) {
|
freezeReactiveVal = function(reactId, domain) {
|
||||||
msg$log("freeze:", msg$reactStr(reactId))
|
msg$log("freeze:", msg$reactStr(reactId))
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
@@ -398,7 +409,6 @@ RLog <- R6Class(
|
|||||||
freezeReactiveKey = function(reactId, key, domain) {
|
freezeReactiveKey = function(reactId, key, domain) {
|
||||||
self$freezeReactiveVal(self$keyIdStr(reactId, key), domain)
|
self$freezeReactiveVal(self$keyIdStr(reactId, key), domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
thawReactiveVal = function(reactId, domain) {
|
thawReactiveVal = function(reactId, domain) {
|
||||||
msg$log("thaw:", msg$reactStr(reactId))
|
msg$log("thaw:", msg$reactStr(reactId))
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
@@ -409,54 +419,60 @@ RLog <- R6Class(
|
|||||||
thawReactiveKey = function(reactId, key, domain) {
|
thawReactiveKey = function(reactId, key, domain) {
|
||||||
self$thawReactiveVal(self$keyIdStr(reactId, key), domain)
|
self$thawReactiveVal(self$keyIdStr(reactId, key), domain)
|
||||||
},
|
},
|
||||||
|
|
||||||
userMark = function(domain = NULL) {
|
userMark = function(domain = NULL) {
|
||||||
msg$log("userMark")
|
msg$log("userMark")
|
||||||
private$appendEntry(domain, list(
|
private$appendEntry(domain, list(
|
||||||
action = "userMark"
|
action = "userMark"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
MessageLogger = R6Class(
|
MessageLogger <- R6Class(
|
||||||
"MessageLogger",
|
"MessageLogger",
|
||||||
portable = FALSE,
|
portable = FALSE,
|
||||||
public = list(
|
public = list(
|
||||||
depth = 0L,
|
depth = 0L,
|
||||||
reactCache = list(),
|
reactCache = list(),
|
||||||
option = "shiny.reactlog.console",
|
option = "shiny.reactlog.console",
|
||||||
|
|
||||||
initialize = function(option = "shiny.reactlog.console", depth = 0L) {
|
initialize = function(option = "shiny.reactlog.console", depth = 0L) {
|
||||||
if (!missing(depth)) self$depth <- depth
|
if (!missing(depth)) self$depth <- depth
|
||||||
if (!missing(option)) self$option <- option
|
if (!missing(option)) self$option <- option
|
||||||
},
|
},
|
||||||
|
|
||||||
isLogging = function() {
|
isLogging = function() {
|
||||||
isTRUE(getOption(self$option))
|
isTRUE(getOption(self$option))
|
||||||
},
|
},
|
||||||
isNotLogging = function() {
|
isNotLogging = function() {
|
||||||
! isTRUE(getOption(self$option))
|
!isTRUE(getOption(self$option))
|
||||||
},
|
},
|
||||||
depthIncrement = function() {
|
depthIncrement = function() {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
self$depth <- self$depth + 1L
|
self$depth <- self$depth + 1L
|
||||||
},
|
},
|
||||||
depthDecrement = function() {
|
depthDecrement = function() {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
self$depth <- self$depth - 1L
|
self$depth <- self$depth - 1L
|
||||||
},
|
},
|
||||||
hasReact = function(reactId) {
|
hasReact = function(reactId) {
|
||||||
if (self$isNotLogging()) return(FALSE)
|
if (self$isNotLogging()) {
|
||||||
|
return(FALSE)
|
||||||
|
}
|
||||||
!is.null(self$getReact(reactId))
|
!is.null(self$getReact(reactId))
|
||||||
},
|
},
|
||||||
getReact = function(reactId, force = FALSE) {
|
getReact = function(reactId, force = FALSE) {
|
||||||
if (identical(force, FALSE) && self$isNotLogging()) return(NULL)
|
if (identical(force, FALSE) && self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
self$reactCache[[reactId]]
|
self$reactCache[[reactId]]
|
||||||
},
|
},
|
||||||
setReact = function(reactObj, force = FALSE) {
|
setReact = function(reactObj, force = FALSE) {
|
||||||
if (identical(force, FALSE) && self$isNotLogging()) return(NULL)
|
if (identical(force, FALSE) && self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
self$reactCache[[reactObj$reactId]] <- reactObj
|
self$reactCache[[reactObj$reactId]] <- reactObj
|
||||||
},
|
},
|
||||||
shortenString = function(txt, n = 250) {
|
shortenString = function(txt, n = 250) {
|
||||||
@@ -475,13 +491,17 @@ MessageLogger = R6Class(
|
|||||||
},
|
},
|
||||||
valueStr = function(valueStr) {
|
valueStr = function(valueStr) {
|
||||||
paste0(
|
paste0(
|
||||||
" '", self$shortenString(self$singleLine(valueStr)), "'"
|
" '", self$shortenString(self$singleLine(valueStr)), "'"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
reactStr = function(reactId) {
|
reactStr = function(reactId) {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
reactInfo <- self$getReact(reactId)
|
reactInfo <- self$getReact(reactId)
|
||||||
if (is.null(reactInfo)) return(" <UNKNOWN_REACTID>")
|
if (is.null(reactInfo)) {
|
||||||
|
return(" <UNKNOWN_REACTID>")
|
||||||
|
}
|
||||||
paste0(
|
paste0(
|
||||||
" ", reactInfo$reactId, ":'", self$shortenString(self$singleLine(reactInfo$label)), "'"
|
" ", reactInfo$reactId, ":'", self$shortenString(self$singleLine(reactInfo$label)), "'"
|
||||||
)
|
)
|
||||||
@@ -490,11 +510,15 @@ MessageLogger = R6Class(
|
|||||||
self$ctxStr(ctxId = NULL, type = type)
|
self$ctxStr(ctxId = NULL, type = type)
|
||||||
},
|
},
|
||||||
ctxStr = function(ctxId = NULL, type = NULL) {
|
ctxStr = function(ctxId = NULL, type = NULL) {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
self$ctxPrevCtxStr(ctxId = ctxId, prevCtxId = NULL, type = type)
|
self$ctxPrevCtxStr(ctxId = ctxId, prevCtxId = NULL, type = type)
|
||||||
},
|
},
|
||||||
ctxPrevCtxStr = function(ctxId = NULL, prevCtxId = NULL, type = NULL, preCtxIdTxt = " in ") {
|
ctxPrevCtxStr = function(ctxId = NULL, prevCtxId = NULL, type = NULL, preCtxIdTxt = " in ") {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
paste0(
|
paste0(
|
||||||
if (!is.null(ctxId)) paste0(preCtxIdTxt, ctxId),
|
if (!is.null(ctxId)) paste0(preCtxIdTxt, ctxId),
|
||||||
if (!is.null(prevCtxId)) paste0(" from ", prevCtxId),
|
if (!is.null(prevCtxId)) paste0(" from ", prevCtxId),
|
||||||
@@ -502,7 +526,9 @@ MessageLogger = R6Class(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
log = function(...) {
|
log = function(...) {
|
||||||
if (self$isNotLogging()) return(NULL)
|
if (self$isNotLogging()) {
|
||||||
|
return(NULL)
|
||||||
|
}
|
||||||
msg <- paste0(
|
msg <- paste0(
|
||||||
paste0(rep("= ", depth), collapse = ""), "- ", paste0(..., collapse = ""),
|
paste0(rep("= ", depth), collapse = ""), "- ", paste0(..., collapse = ""),
|
||||||
collapse = ""
|
collapse = ""
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
\alias{reactlog}
|
\alias{reactlog}
|
||||||
\alias{reactlogShow}
|
\alias{reactlogShow}
|
||||||
\alias{reactlogReset}
|
\alias{reactlogReset}
|
||||||
|
\alias{reactlogAddMark}
|
||||||
\title{Reactive Log Visualizer}
|
\title{Reactive Log Visualizer}
|
||||||
\usage{
|
\usage{
|
||||||
reactlog()
|
reactlog()
|
||||||
@@ -11,10 +12,15 @@ reactlog()
|
|||||||
reactlogShow(time = TRUE)
|
reactlogShow(time = TRUE)
|
||||||
|
|
||||||
reactlogReset()
|
reactlogReset()
|
||||||
|
|
||||||
|
reactlogAddMark(session = getDefaultReactiveDomain())
|
||||||
}
|
}
|
||||||
\arguments{
|
\arguments{
|
||||||
\item{time}{A boolean that specifies whether or not to display the
|
\item{time}{A boolean that specifies whether or not to display the
|
||||||
time that each reactive takes to calculate a result.}
|
time that each reactive takes to calculate a result.}
|
||||||
|
|
||||||
|
\item{session}{The Shiny session to assign the mark to. Defaults to the
|
||||||
|
current session.}
|
||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Provides an interactive browser-based tool for visualizing reactive
|
Provides an interactive browser-based tool for visualizing reactive
|
||||||
@@ -22,7 +28,7 @@ dependencies and execution in your application.
|
|||||||
}
|
}
|
||||||
\details{
|
\details{
|
||||||
To use the reactive log visualizer, start with a fresh R session and
|
To use the reactive log visualizer, start with a fresh R session and
|
||||||
run the command \code{options(shiny.reactlog=TRUE)}; then launch your
|
run the command \code{reactlog::reactlog_enable()}; then launch your
|
||||||
application in the usual way (e.g. using \code{\link[=runApp]{runApp()}}). At
|
application in the usual way (e.g. using \code{\link[=runApp]{runApp()}}). At
|
||||||
any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
|
any time you can hit Ctrl+F3 (or for Mac users, Command+F3) in your
|
||||||
web browser to launch the reactive log visualization.
|
web browser to launch the reactive log visualization.
|
||||||
@@ -45,17 +51,37 @@ browser will not load new activity into the report; you will need to
|
|||||||
call \code{reactlogShow()} explicitly.
|
call \code{reactlogShow()} explicitly.
|
||||||
|
|
||||||
For security and performance reasons, do not enable
|
For security and performance reasons, do not enable
|
||||||
\code{shiny.reactlog} in production environments. When the option is
|
\code{options(shiny.reactlog=TRUE)} (or \code{reactlog::reactlog_enable()}) in
|
||||||
enabled, it's possible for any user of your app to see at least some
|
production environments. When the option is enabled, it's possible
|
||||||
of the source code of your reactive expressions and observers.
|
for any user of your app to see at least some of the source code of
|
||||||
|
your reactive expressions and observers. In addition, reactlog
|
||||||
|
should be considered a memory leak as it will constantly grow and
|
||||||
|
will never reset until the R session is restarted.
|
||||||
}
|
}
|
||||||
\section{Functions}{
|
\section{Functions}{
|
||||||
\itemize{
|
\itemize{
|
||||||
\item \code{reactlog()}: Return a list of reactive information. Can be used in conjunction with
|
\item \code{reactlog()}: Return a list of reactive information. Can be used in
|
||||||
\link[reactlog:reactlog_show]{reactlog::reactlog_show} to later display the reactlog graph.
|
conjunction with \link[reactlog:reactlog_show]{reactlog::reactlog_show} to later display the reactlog
|
||||||
|
graph.
|
||||||
|
|
||||||
\item \code{reactlogShow()}: Display a full reactlog graph for all sessions.
|
\item \code{reactlogShow()}: Display a full reactlog graph for all sessions.
|
||||||
|
|
||||||
\item \code{reactlogReset()}: Resets the entire reactlog stack. Useful for debugging and removing all prior reactive history.
|
\item \code{reactlogReset()}: Resets the entire reactlog stack. Useful for debugging
|
||||||
|
and removing all prior reactive history.
|
||||||
|
|
||||||
|
\item \code{reactlogAddMark()}: Adds "mark" entry into the reactlog stack. This is
|
||||||
|
useful for programmatically adding a marked entry in the reactlog, rather
|
||||||
|
than using your keyboard's key combination.
|
||||||
|
|
||||||
|
For example, we can \emph{mark} the reactlog at the beginning of an
|
||||||
|
\code{observeEvent}'s calculation:
|
||||||
|
|
||||||
|
\if{html}{\out{<div class="sourceCode r">}}\preformatted{observeEvent(input$my_event_trigger, \{
|
||||||
|
# Add a mark in the reactlog
|
||||||
|
reactlogAddMark()
|
||||||
|
# Run your regular event reaction code here...
|
||||||
|
....
|
||||||
|
\})
|
||||||
|
}\if{html}{\out{</div>}}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user