diff --git a/LICENSE b/LICENSE index f8dd2456..b0fc8b2a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,2 @@ -MIT License - -Copyright (c) 2019 Plotly - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +YEAR: 2021 +COPYRIGHT HOLDER: Plotly, Inc. diff --git a/R/dash.R b/R/dash.R index 59a44f1a..d9d0f21c 100644 --- a/R/dash.R +++ b/R/dash.R @@ -780,7 +780,7 @@ Dash <- R6::R6Class( #' #' For detailed examples of how to use pattern-matching callbacks, see the #' entry for \link{selectors} or visit our interactive online - #' documentation at \url{https://dashr.plotly.com}. + #' documentation at \url{https://dash.plotly.com/r/}. #' #' The `output` argument defines which layout component property should #' receive the results (via the [output] object). The events that @@ -1149,7 +1149,7 @@ Dash <- R6::R6Class( #' @param block Logical. Start the server while blocking console input? Default is `TRUE`. #' @param showcase Logical. Load the Dash application into the default web browser when server starts? Default is `FALSE`. #' @param use_viewer Logical. Load the Dash application into RStudio's viewer pane? Requires that `host` is either `127.0.0.1` or `localhost`, and that Dash application is started within RStudio; if `use_viewer = TRUE` and these conditions are not satisfied, the user is warned and the app opens in the default browser instead. Default is `FALSE`. - #' @param debug Logical. Enable/disable all the Dash developer tools (and the within-browser user interface for the callback graph visualizer and stack traces) unless overridden by the arguments or environment variables. Default is `FALSE` when called via `run_server`. For more information, please visit \url{https://dashr.plotly.com/devtools}. Environment variable: `DASH_DEBUG`. + #' @param debug Logical. Enable/disable all the Dash developer tools (and the within-browser user interface for the callback graph visualizer and stack traces) unless overridden by the arguments or environment variables. Default is `FALSE` when called via `run_server`. For more information, please visit \url{https://dash.plotly.com/r/devtools}. Environment variable: `DASH_DEBUG`. #' @param dev_tools_ui Logical. Show Dash's developer tools UI? Default is `TRUE` if `debug == TRUE`, `FALSE` otherwise. Environment variable: `DASH_UI`. #' @param dev_tools_hot_reload Logical. Activate hot reloading when app, assets, and component files change? Default is `TRUE` if `debug == TRUE`, `FALSE` otherwise. Requires that the Dash application is loaded using `source()`, so that `srcref` attributes are available for executed code. Environment variable: `DASH_HOT_RELOAD`. #' @param dev_tools_hot_reload_interval Numeric. Interval in seconds for the client to request the reload hash. Default is `3`. Environment variable: `DASH_HOT_RELOAD_INTERVAL`. diff --git a/R/utils.R b/R/utils.R index 8e0063a2..d7eea0e5 100644 --- a/R/utils.R +++ b/R/utils.R @@ -338,12 +338,26 @@ clean_dependencies <- function(deps) { } insertIntoCallbackMap <- function(map, inputs, output, state, func, clientside_function) { - map[[createCallbackId(output)]] <- list(inputs=inputs, - output=output, - state=state, - func=func, - clientside_function=clientside_function - ) + output_id <- createCallbackId(output) + + if (output_id %in% names(map)) { + stop( + sprintf( + "One or more of the following outputs are duplicated across callbacks: %s. Please ensure that all ID and property combinations are unique.", + output_id + ), + call. = FALSE + ) + } + + map[[output_id]] <- list( + inputs = inputs, + output = output, + state = state, + func = func, + clientside_function = clientside_function + ) + if (length(map) >= 2) { ids <- lapply(names(map), function(x) getIdProps(x)$ids) props <- lapply(names(map), function(x) getIdProps(x)$props) @@ -1139,7 +1153,7 @@ createCallbackId <- function(output) { } getIdProps <- function(output) { - output_ids <- strsplit(substr(output, 3, nchar(output)-2), '...', fixed=TRUE) + output_ids <- strsplit(gsub("^\\.{2}|\\.{2}$", "", output), '...', fixed=TRUE) idprops <- lapply(output_ids, strsplit, '.', fixed=TRUE) ids <- vapply(unlist(idprops, recursive=FALSE), '[', character(1), 1) props <- vapply(unlist(idprops, recursive=FALSE), '[', character(1), 2) diff --git a/README.md b/README.md index 6e03dd36..831e5667 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ -[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://circleci.com/gh/plotly/dashR/tree/master) +[![CircleCI](https://circleci.com/gh/plotly/dashR/tree/master.svg?style=svg)](https://app.circleci.com/pipelines/github/plotly/dashR?branch=master) [![GitHub](https://img.shields.io/github/license/plotly/dashR.svg?color=dark-green)](https://github.com/plotly/dashR/blob/master/LICENSE) -[![CRAN status](https://www.r-pkg.org/badges/version-ago/dash)](https://cran.r-project.org/web/packages/dash/index.html) -[![](http://cranlogs.r-pkg.org/badges/grand-total/dash)](https://cran.r-project.org/package=dash) -[![](https://cranlogs.r-pkg.org/badges/dash)](https://cran.r-project.org/package=dash) +[![CRAN status](https://www.r-pkg.org/badges/version-ago/dash)](https://CRAN.R-project.org/package=dash) +[![](http://cranlogs.r-pkg.org/badges/grand-total/dash)](https://CRAN.R-project.org/package=dash) +[![](https://cranlogs.r-pkg.org/badges/dash)](https://CRAN.R-project.org/package=dash) # Dash for R #### Create beautiful, analytic web applications in R. -[Documentation](https://dashr.plotly.com/) | [Gallery](https://dash-gallery.plotly.host/Portal/) +[Documentation](https://dash.plotly.com/r/) | [Gallery](https://dash.gallery/Portal/) ## Installation - + > 🛑 Make sure you're on at least version `3.0.2` of R. You can see what version of R you have by entering `version` in the R CLI. [CRAN](https://cran.r-project.org/bin/) is the easiest place to download the latest R version. @@ -42,9 +42,9 @@ That's it! ## Getting Started - + -The R package **dash** makes it easy to create reactive web applications powered by R. It provides an [R6](https://cran.r-project.org/web/packages/R6/index.html) class, named `Dash`, which may be initialized via the `new()` method. +The R package **dash** makes it easy to create reactive web applications powered by R. It provides an [R6](https://CRAN.R-project.org/package=R6) class, named `Dash`, which may be initialized via the `new()` method. ```r library(dash) @@ -55,24 +55,28 @@ app <- Dash$new() Similar to [Dash for Python](https://github.com/plotly/dash) and [Dash for Julia](https://github.com/plotly/Dash.jl), every Dash for R application needs a layout (i.e., user interface) and a collection of callback functions which define the updating logic to perform when input value(s) change. Take, for instance, this basic example of formatting a string: ```r -app$layout( - htmlDiv( - list( - dccInput(id = "inputID", value = "initial value", type = "text"), - htmlDiv(id = "outputID") - ) - ) -) - -app$callback(output = list(id="outputID", property="children"), - params = list(input(id="inputID", property="value"), - state(id="inputID", property="type")), - function(x, y) { - sprintf("You've entered: '%s' into a '%s' input control", x, y) - } -) +library(dash) -app$run_server(showcase = TRUE) +dash_app() %>% + set_layout( + dccInput(id = "text", "sample"), + div("CAPS: ", span(id = "out1")), + div("small: ", span(id = "out2")) + ) %>% + add_callback( + list( + output("out1", "children"), + output("out2", "children") + ), + input("text", "value"), + function(text) { + list( + toupper(text), + tolower(text) + ) + } + ) %>% + run_app() ``` Here the `showcase = TRUE` argument opens a browser window and automatically loads the Dash app for you. @@ -80,71 +84,38 @@ Here the `showcase = TRUE` argument opens a browser window and automatically loa ## Hello world example using `dccGraph` ```r -app <- Dash$new() +library(dash) -app$layout( - htmlDiv( - list( - dccInput(id = "graphTitle", - value = "Let's Dance!", - type = "text"), - htmlDiv(id = "outputID"), - dccGraph(id = "giraffe", - figure = list( - data = list(x = c(1,2,3), y = c(3,2,8), type = "bar"), - layout = list(title = "Let's Dance!") - ) - ) +# Create a Dash app +app <- dash_app() + +# Set the layout of the app +app %>% set_layout( + h1('Hello Dash'), + div("Dash: A web application framework for your data."), + dccGraph( + figure = list( + data = list( + list( + x = list(1, 2, 3), + y = list(4, 1, 2), + type = 'bar', + name = 'SF' + ), + list( + x = list(1, 2, 3), + y = list(2, 4, 5), + type = 'bar', + name = 'Montr\U{00E9}al' + ) + ), + layout = list(title = 'Dash Data Visualization') ) ) ) -app$callback(output = list(id = "giraffe", property = "figure"), - params = list(input("graphTitle", "value")), - function(newTitle) { - - rand1 <- sample(1:10, 1) - - rand2 <- sample(1:10, 1) - rand3 <- sample(1:10, 1) - rand4 <- sample(1:10, 1) - - x <- c(1,2,3) - y <- c(3,6,rand1) - y2 <- c(rand2,rand3,rand4) - - df = data.frame(x, y, y2) - - list( - data = - list( - list( - x = df$x, - y = df$y, - type = "bar" - ), - list( - x = df$x, - y = df$y2, - type = "scatter", - mode = "lines+markers", - line = list(width = 4) - ) - ), - layout = list(title = newTitle) - ) - } -) - -app$callback(output = list(id = "outputID", property = "children"), - params = list(input("graphTitle", "value"), - state("graphTitle", "type")), - function(x, y) { - sprintf("You've entered: '%s' into a '%s' input control", x, y) - } -) - -app$run_server(showcase = TRUE) +# Run the app +app %>% run_app() ``` --- diff --git a/man/Dash.Rd b/man/Dash.Rd index e10406c3..31bd2b8b 100644 --- a/man/Dash.Rd +++ b/man/Dash.Rd @@ -500,7 +500,7 @@ information but do not trigger the callback directly. For detailed examples of how to use pattern-matching callbacks, see the entry for \link{selectors} or visit our interactive online -documentation at \url{https://dashr.plotly.com}. +documentation at \url{https://dash.plotly.com/r/}. The \code{output} argument defines which layout component property should receive the results (via the \link{output} object). The events that @@ -857,7 +857,7 @@ Start the Fiery HTTP server and run a Dash application. \item{\code{dev_tools_prune_errors}}{Logical. Reduce tracebacks such that only lines relevant to user code remain, stripping out Fiery and Dash references? Only available with debugging. \code{TRUE} by default, set to \code{FALSE} to see the complete traceback. Environment variable: \code{DASH_PRUNE_ERRORS}.} -\item{\code{debug}}{Logical. Enable/disable all the Dash developer tools (and the within-browser user interface for the callback graph visualizer and stack traces) unless overridden by the arguments or environment variables. Default is \code{FALSE} when called via \code{run_server}. For more information, please visit \url{https://dashr.plotly.com/devtools}. Environment variable: \code{DASH_DEBUG}.} +\item{\code{debug}}{Logical. Enable/disable all the Dash developer tools (and the within-browser user interface for the callback graph visualizer and stack traces) unless overridden by the arguments or environment variables. Default is \code{FALSE} when called via \code{run_server}. For more information, please visit \url{https://dash.plotly.com/r/devtools}. Environment variable: \code{DASH_DEBUG}.} \item{\code{dev_tools_ui}}{Logical. Show Dash's developer tools UI? Default is \code{TRUE} if \code{debug == TRUE}, \code{FALSE} otherwise. Environment variable: \code{DASH_UI}.} diff --git a/man/dash-package.Rd b/man/dash-package.Rd index 15d5ef73..3ad3c077 100644 --- a/man/dash-package.Rd +++ b/man/dash-package.Rd @@ -15,12 +15,12 @@ Dash apps are rendered in the web browser. You can deploy your apps to servers a There is a lot behind the framework. To learn more about how it is built and what motivated Dash, watch our talk from \href{https://youtu.be/5BAthiN0htc}{Plotcon} or read our \href{https://medium.com/@plotlygraphs/introducing-dash-5ecf7191b503}{announcement letter}. -Dash is an open source package, released under the permissive MIT license. Plotly develops Dash and offers a \href{https://plotly.com/dash/pricing/}{platform for easily deploying Dash apps in an enterprise environment}. If you're interested, \href{https://plotly.typeform.com/to/rkO85m?_ga=2.223907347.9240264.1560484539-2037997284.1554944507}{please get in touch}. +Dash is an open source package, released under the permissive MIT license. Plotly develops Dash and offers a \href{https://plotly.com/dash/}{platform for easily deploying Dash apps in an enterprise environment}. If you're interested, \href{https://plotly.com/get-pricing/}{please get in touch}. } \seealso{ Useful links: \itemize{ - \item \url{http://dashr.plotly.com} + \item \url{https://dash.plotly.com/r/} \item \url{https://github.com/plotly/dashR} \item Report bugs at \url{https://github.com/plotly/dashR/issues} } diff --git a/package-lock.json b/package-lock.json index c723bed9..de3b1254 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,12 +21,12 @@ "fs-extra": "^9.0.1", "gulp": "^4.0.2", "gulp-concat": "2.6.1", - "gulp-footer": "^2.0.2", "gulp-print": "^5.0.2", "gulp-rename": "^2.0.0", "gulp-replace": "^1.0.0", "mkdirp": "^0.5.4", "prettier": "^1.14.2", + "set-value": ">=4.0.1", "shelljs": "0.8.4" } }, @@ -874,6 +874,33 @@ "node": ">=0.10.0" } }, + "node_modules/cache-base/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-base/node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2870,19 +2897,6 @@ "node": ">= 0.10" } }, - "node_modules/gulp-footer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-footer/-/gulp-footer-2.0.2.tgz", - "integrity": "sha512-HsG5VOgKHFRqZXnHGI6oGhPDg70p9pobM+dYOnjBZVLMQUHzLG6bfaPNRJ7XG707E+vWO3TfN0CND9UrYhk94g==", - "dev": true, - "dependencies": { - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.6.2", - "map-stream": "0.0.7" - } - }, "node_modules/gulp-print": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/gulp-print/-/gulp-print-5.0.2.tgz", @@ -3507,6 +3521,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-primitive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", + "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3880,125 +3903,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "node_modules/lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "node_modules/lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "node_modules/lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "node_modules/lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "node_modules/lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5608,30 +5512,21 @@ "dev": true }, "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", + "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", "dev": true, + "funding": [ + "https://github.com/sponsors/jonschlinkert", + "https://paypal.me/jonathanschlinkert", + "https://jonschlinkert.dev/sponsor" + ], "dependencies": { - "is-extendable": "^0.1.0" + "is-plain-object": "^2.0.4", + "is-primitive": "^3.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=11.0" } }, "node_modules/shebang-command": { @@ -6410,6 +6305,33 @@ "node": ">=0.10.0" } }, + "node_modules/union-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/unique-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", @@ -7431,6 +7353,29 @@ "to-object-path": "^0.3.0", "union-value": "^1.0.0", "unset-value": "^1.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + } } }, "call-bind": { @@ -9121,19 +9066,6 @@ "vinyl": "^2.0.0" } }, - "gulp-footer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-footer/-/gulp-footer-2.0.2.tgz", - "integrity": "sha512-HsG5VOgKHFRqZXnHGI6oGhPDg70p9pobM+dYOnjBZVLMQUHzLG6bfaPNRJ7XG707E+vWO3TfN0CND9UrYhk94g==", - "dev": true, - "requires": { - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.6.2", - "map-stream": "0.0.7" - } - }, "gulp-print": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/gulp-print/-/gulp-print-5.0.2.tgz", @@ -9594,6 +9526,12 @@ "isobject": "^3.0.1" } }, + "is-primitive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", + "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -9884,125 +9822,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -11290,26 +11109,13 @@ "dev": true }, "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", + "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "is-plain-object": "^2.0.4", + "is-primitive": "^3.0.1" } }, "shebang-command": { @@ -11955,6 +11761,29 @@ "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + } } }, "unique-stream": { diff --git a/package.json b/package.json index 41a0cc18..5a8a6fb9 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "eslint-plugin-react": "^7.11.1", "fs-extra": "^9.0.1", "gulp": "^4.0.2", - "gulp-footer": "^2.0.2", "gulp-concat":"2.6.1", "gulp-print": "^5.0.2", "gulp-replace": "^1.0.0", @@ -37,6 +36,7 @@ "fancy-log": "^1.3.3", "mkdirp": "^0.5.4", "prettier": "^1.14.2", + "set-value": ">=4.0.1", "shelljs": "0.8.4" }, "dependencies": { diff --git a/tests/testthat/test-callback.R b/tests/testthat/test-callback.R index 75730701..3d0bc455 100644 --- a/tests/testthat/test-callback.R +++ b/tests/testthat/test-callback.R @@ -8,7 +8,8 @@ test_that("Callback outputs can be provided with or without output function", { dccInput(id='input-1-state', type='text', value='Montreal'), dccInput(id='input-2-state', type='text', value='Canada'), html$button(id='submit-button', n_clicks=0, children='Submit'), - html$div(id='output-state') + html$div(id='output-state'), + html$div(id='output-state2') ) ) ) @@ -24,7 +25,7 @@ test_that("Callback outputs can be provided with or without output function", { ) expect_silent( - app$callback(output(id = 'output-state', property = 'children'), + app$callback(output(id = 'output-state2', property = 'children'), list(input(id = 'submit-button', property = 'n_clicks'), state(id = 'input-1-state', property = 'value'), state(id = 'input-2-state', property = 'value')),