-
-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dash for R v0.3.0 #175
Dash for R v0.3.0 #175
Changes from 38 commits
5c83f5c
d20daa8
0845184
29a3042
bbfc6cc
2e09789
c947c73
8e3c168
5d485d9
5c2ea67
cd33eba
f866d38
7e16f8d
4b99c88
2ca3f98
68be6a9
1d5ee2d
e852995
22227f6
006b6d3
93345e6
e6c460a
8c9678b
61e6dfa
ca6613c
fb05d18
85828d3
e4cedb3
cc9e06d
3733ead
2f1be58
6eddf98
a2907ba
98254a1
402969d
d7dcae7
c03c6c1
030adb4
744b696
c853cbf
7c26675
49c97da
21e78db
2c46d9f
0085036
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,23 @@ | ||
# Change Log for Dash for R | ||
All notable changes to this project will be documented in this file. | ||
|
||
|
||
## [0.3.0] - 2020-02-12 | ||
### Added | ||
- Support for config-aware relative paths [#172](https://github.com/plotly/dashR/pull/172) | ||
- Support index customization and index templates [#168](https://github.com/plotly/dashR/pull/168) | ||
- Application titles may be set using the `app$title()` method, for parity with Dash for Python's `app.title` syntax [#168](https://github.com/plotly/dashR/pull/168) | ||
|
||
### Changed | ||
- Dash for R now requires `dashCoreComponents` v1.8.0 | ||
- Dash for R now requires `dashTable` v4.6.0 | ||
- Rename `DASH_HOST` to `HOST` and `DASH_PORT` to `PORT` [#167](https://github.com/plotly/dashR/pull/167) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This goes beyond the scope of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
- Automatically set routes and requests pathname prefixes if `DASH_APP_NAME` environment variable has been set [#165](https://github.com/plotly/dashR/pull/165) | ||
|
||
### Deprecated | ||
- Application titles can no longer be set using `name` parameter, which is now deprecated with a warning, for parity with Dash for Python [#168](https://github.com/plotly/dashR/pull/168) | ||
|
||
|
||
## [0.2.0] - 2020-01-03 | ||
### Added | ||
- Support for asynchronous/dynamic loading of dependencies, resource caching, and asset fingerprinting [#157](https://github.com/plotly/dashR/pull/157) | ||
|
@@ -28,6 +45,7 @@ All notable changes to this project will be documented in this file. | |
- Fixes for hot reloading interval handling and refreshing apps within viewer pane [#148](https://github.com/plotly/dashR/pull/148) | ||
- `get_asset_url` checks `getAppPath()` as well as `DASH_APP_ROOT_PATH` environment variable when invoked [#161](https://github.com/plotly/dashR/pull/161) | ||
|
||
|
||
## [0.1.0] - 2019-07-10 | ||
### Added | ||
- Initial release | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
#' @usage Dash | ||
#' | ||
#' @section Constructor: Dash$new( | ||
#' name = "dash", | ||
#' name = NULL, | ||
#' server = fiery::Fire$new(), | ||
#' assets_folder = 'assets', | ||
#' assets_url_path = '/assets', | ||
|
@@ -24,7 +24,7 @@ | |
#' @section Arguments: | ||
#' \tabular{lll}{ | ||
#' `name` \tab \tab Character. The name of the Dash application (placed in the `<title>` | ||
#' of the HTML page).\cr | ||
#' of the HTML page). DEPRECATED; please use `index_string()` or `interpolate_index()` instead.\cr | ||
#' `server` \tab \tab The web server used to power the application. | ||
#' Must be a [fiery::Fire] object.\cr | ||
#' `assets_folder` \tab \tab Character. A path, relative to the current working directory, | ||
|
@@ -100,6 +100,9 @@ | |
#' from the Dash backend. The latter may offer improved performance relative | ||
#' to callbacks written in R. | ||
#' } | ||
#' \item{`title("dash")`}{ | ||
#' The title of the app. If no title is supplied, Dash for R will use 'dash'. | ||
#' } | ||
#' \item{`callback_context()`}{ | ||
#' The `callback_context` method permits retrieving the inputs which triggered | ||
#' the firing of a given callback, and allows introspection of the input/state | ||
|
@@ -114,12 +117,89 @@ | |
#' present a warning and return `NULL` if the Dash app was not loaded via `source()` | ||
#' if the `DASH_APP_PATH` environment variable is undefined. | ||
#' } | ||
#' \item{`run_server(host = Sys.getenv('DASH_HOST', "127.0.0.1"), | ||
#' port = Sys.getenv('DASH_PORT', 8050), block = TRUE, showcase = FALSE, ...)`}{ | ||
#' \item{`get_relative_path(path, requests_pathname_prefix)`}{ | ||
#' The `get_relative_path` method simplifies the handling of URLs and pathnames for apps | ||
#' running locally and on a deployment server such as Dash Enterprise. It handles the prefix | ||
#' for requesting assets similar to the `get_asset_url` method, but can also be used for URL handling | ||
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")` | ||
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with | ||
#' a `/`. | ||
#' \describe{ | ||
#' \item{path}{Character. A path string prefixed with a leading `/` which directs at a path or asset directory.} | ||
#' \item{requests_pathname_prefix}{Character. The pathname prefix for the app on a deployed application. Defaults to the environment variable set by the server, or `""` if run locally.} | ||
#' } | ||
#' \item{`strip_relative_path(path, requests_pathname_prefix)`}{ | ||
#' The `strip_relative_path` method simplifies the handling of URLs and pathnames for apps | ||
#' running locally and on a deployment server such as Dash Enterprise. It acts almost opposite the `get_relative_path` | ||
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefiex`, | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as | ||
#' `homepage`. This is particularly useful for `dccLocation` URL routing. | ||
#' \describe{ | ||
#' \item{path}{Character. A path string prefixed with a leading `/` and `requests_pathname_prefix` which directs at a path or asset directory.} | ||
#' \item{requests_pathname_prefix}{Character. The pathname prefix for the app on a deployed application. Defaults to the environment variable set by the server, or `""` if run locally.} | ||
#' } | ||
#' \item{`index_string(string)`}{ | ||
#' The `index_string` method allows the specification of a custom index by changing | ||
#' the default `HTML` template that is generated by the Dash UI. Meta tags, CSS, Javascript, | ||
#' are some examples of features that can be modified. | ||
#' This method will present a warning if your HTML template is missing any necessary elements | ||
#' and return an error if a valid index is not defined. The following interpolation keys are | ||
#' currently supported: | ||
#' \describe{ | ||
#' \item{`{%metas%}`}{Optional - The registered meta tags.} | ||
#' \item{`{%favicon%}`}{Optional - A favicon link tag if found in assets.} | ||
#' \item{`{%css%}`}{Optional - Link tags to css resources.} | ||
#' \item{`{%config%}`}{Required - Config generated by dash for the renderer.} | ||
#' \item{`{%app_entry%}`}{Required - The container where dash react components are rendered.} | ||
#' \item{`{%scripts%}`}{Required - Collected dependencies scripts tags.} | ||
#' } | ||
#' \describe{ | ||
#' \item{Example of a basic HTML index string:}{ | ||
#' \preformatted{ | ||
#' "<!DOCTYPE html> | ||
#' <html> | ||
#' <head> | ||
#' \{\%meta_tags\%\} | ||
#' <title>\{\{%css\%\}\}</title> | ||
#' \{\%favicon\%\} | ||
#' \{\%css_tags\%\} | ||
#' </head> | ||
#' <body> | ||
#' \{\%app_entry\%\} | ||
#' <footer> | ||
#' \{\%config\%\} | ||
#' \{\%scripts\%\} | ||
#' </footer> | ||
#' </body> | ||
#' </html>" | ||
#' } | ||
#' } | ||
#' } | ||
#' } | ||
#' \item{`interpolate_index(template_index, ...)`}{ | ||
#' With the `interpolate_index` method, we can pass a custom index with template string | ||
#' variables that are already evaluated. We can directly pass arguments to the `template_index` | ||
#' by assigning them to variables present in the template. This is similar to the `index_string` method | ||
#' but offers the ability to change the default components of the Dash index as seen in the example below: | ||
#' \preformatted{ | ||
#' app$interpolate_index( | ||
#' template_index, | ||
#' metas = "<meta_charset='UTF-8'/>", | ||
#' renderer = renderer, | ||
#' config = config) | ||
#' } | ||
#' \describe{ | ||
#' \item{template_index}{Character. A formatted string with the HTML index string. Defaults to the initial template} | ||
#' \item{...}{Named List. The unnamed arguments can be passed as individual named lists corresponding to the components | ||
#' of the Dash html index. These include the same arguments as those found in the `index_string()` template.} | ||
#' } | ||
#' } | ||
#' \item{`run_server(host = Sys.getenv('HOST', "127.0.0.1"), | ||
#' port = Sys.getenv('PORT', 8050), block = TRUE, showcase = FALSE, ...)`}{ | ||
#' The `run_server` method has 13 formal arguments, several of which are optional: | ||
#' \describe{ | ||
#' \item{host}{Character. A string specifying a valid IPv4 address for the Fiery server, or `0.0.0.0` to listen on all addresses. Default is `127.0.0.1` Environment variable: `DASH_HOST`.} | ||
#' \item{port}{Integer. Specifies the port number on which the server should listen (default is `8050`). Environment variable: `DASH_PORT`.} | ||
#' \item{host}{Character. A string specifying a valid IPv4 address for the Fiery server, or `0.0.0.0` to listen on all addresses. Default is `127.0.0.1` Environment variable: `HOST`.} | ||
#' \item{port}{Integer. Specifies the port number on which the server should listen (default is `8050`). Environment variable: `PORT`.} | ||
#' \item{block}{Logical. Start the server while blocking console input? Default is `TRUE`.} | ||
#' \item{showcase}{Logical. Load the Dash application into the default web browser when server starts? Default is `FALSE`.} | ||
#' \item{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 satsified, the user is warned and the app opens in the default browser instead. Default is `FALSE`.} | ||
rpkyle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
@@ -174,7 +254,7 @@ Dash <- R6::R6Class( | |
config = list(), | ||
|
||
# i.e., the Dash$new() method | ||
initialize = function(name = "dash", | ||
initialize = function(name = NULL, | ||
server = fiery::Fire$new(), | ||
assets_folder = 'assets', | ||
assets_url_path = '/assets', | ||
|
@@ -191,13 +271,18 @@ Dash <- R6::R6Class( | |
suppress_callback_exceptions = FALSE) { | ||
|
||
# argument type checking | ||
assertthat::assert_that(is.character(name)) | ||
assertthat::assert_that(inherits(server, "Fire")) | ||
assertthat::assert_that(is.logical(serve_locally)) | ||
assertthat::assert_that(is.logical(suppress_callback_exceptions)) | ||
|
||
# save relevant args as private fields | ||
private$name <- name | ||
if (!is.null(name)) { | ||
warning(sprintf( | ||
"The supplied application title, '%s', should be set using the title() method, or passed via index_string() or interpolate_index(); it has been ignored, and 'dash' will be used instead.", | ||
name), | ||
call. = FALSE | ||
) | ||
} | ||
private$serve_locally <- serve_locally | ||
private$eager_loading <- eager_loading | ||
# remove leading and trailing slash(es) if present | ||
|
@@ -213,8 +298,8 @@ Dash <- R6::R6Class( | |
private$in_viewer <- FALSE | ||
|
||
# config options | ||
self$config$routes_pathname_prefix <- resolve_prefix(routes_pathname_prefix, "DASH_ROUTES_PATHNAME_PREFIX", url_base_pathname) | ||
self$config$requests_pathname_prefix <- resolve_prefix(requests_pathname_prefix, "DASH_REQUESTS_PATHNAME_PREFIX", url_base_pathname) | ||
self$config$routes_pathname_prefix <- resolvePrefix(routes_pathname_prefix, "DASH_ROUTES_PATHNAME_PREFIX", url_base_pathname) | ||
self$config$requests_pathname_prefix <- resolvePrefix(requests_pathname_prefix, "DASH_REQUESTS_PATHNAME_PREFIX", url_base_pathname) | ||
self$config$external_scripts <- external_scripts | ||
self$config$external_stylesheets <- external_stylesheets | ||
|
||
|
@@ -763,11 +848,61 @@ Dash <- R6::R6Class( | |
sep="/"))) | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# return relative asset URLs | ||
# ------------------------------------------------------------------------ | ||
|
||
get_relative_path = function(path, requests_pathname_prefix = self$config$requests_pathname_prefix) { | ||
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path) | ||
return(asset) | ||
}, | ||
|
||
|
||
# ------------------------------------------------------------------------ | ||
# return relative asset URLs | ||
# ------------------------------------------------------------------------ | ||
|
||
strip_relative_path = function(path, requests_pathname_prefix = self$config$requests_pathname_prefix) { | ||
asset = strip_relative_path(requests_pathname = requests_pathname_prefix, path = path) | ||
return(asset) | ||
}, | ||
|
||
# specify a custom index string | ||
# ------------------------------------------------------------------------ | ||
index_string = function(string) { | ||
private$custom_index <- validate_keys(string) | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# modify the templated variables by using the `interpolate_index` method. | ||
# ------------------------------------------------------------------------ | ||
interpolate_index = function(template_index = private$template_index[[1]], ...) { | ||
template = template_index | ||
kwargs <- list(...) | ||
|
||
for (name in names(kwargs)) { | ||
key = paste0('\\{\\%', name, '\\%\\}') | ||
template = sub(key, kwargs[[name]], template) | ||
} | ||
|
||
invisible(validate_keys(names(kwargs))) | ||
|
||
private$template_index <- template | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# specify a custom title | ||
# ------------------------------------------------------------------------ | ||
title = function(string = "dash") { | ||
assertthat::assert_that(is.character(string)) | ||
private$name <- string | ||
}, | ||
|
||
# ------------------------------------------------------------------------ | ||
# convenient fiery wrappers | ||
# ------------------------------------------------------------------------ | ||
run_server = function(host = Sys.getenv('DASH_HOST', "127.0.0.1"), | ||
port = Sys.getenv('DASH_PORT', 8050), | ||
run_server = function(host = Sys.getenv('HOST', "127.0.0.1"), | ||
port = Sys.getenv('PORT', 8050), | ||
block = TRUE, | ||
showcase = FALSE, | ||
use_viewer = FALSE, | ||
|
@@ -848,7 +983,6 @@ Dash <- R6::R6Class( | |
self$server$on('cycle-end', function(server, ...) { | ||
# handle case where assets are not present, since we can still hot reload the app itself | ||
# | ||
# private$last_refresh is set after the asset_map is refreshed | ||
# private$last_reload stores the time of the last hard or soft reload event | ||
# private$last_cycle will be set when the cycle-end handler terminates | ||
# | ||
|
@@ -1266,6 +1400,24 @@ Dash <- R6::R6Class( | |
|
||
# akin to https://github.com/plotly/dash/blob/d2ebc837/dash/dash.py#L338 | ||
# note discussion here https://github.com/plotly/dash/blob/d2ebc837/dash/dash.py#L279-L284 | ||
custom_index = NULL, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo at line 965: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed, fixed, fixed in 49c97da |
||
template_index = c( | ||
"<!DOCTYPE html> | ||
<html> | ||
<head> | ||
{%meta_tags%} | ||
<title>{%title%}</title> | ||
{%favicon%} | ||
{%css_tags%} | ||
</head> | ||
<body> | ||
{%app_entry%} | ||
<footer> | ||
{%config%} | ||
{%scripts%} | ||
</footer> | ||
</body> | ||
</html>", NA), | ||
.index = NULL, | ||
|
||
generateReloadHash = function() { | ||
|
@@ -1434,13 +1586,32 @@ Dash <- R6::R6Class( | |
css_tags <- all_tags[["css_tags"]] | ||
|
||
# retrieve script tags for serving in the index | ||
scripts_tags <- all_tags[["scripts_tags"]] | ||
scripts <- all_tags[["scripts_tags"]] | ||
|
||
# insert meta tags if present | ||
meta_tags <- all_tags[["meta_tags"]] | ||
|
||
# define the react-entry-point | ||
app_entry <- "<div id='react-entry-point'><div class='_dash-loading'>Loading...</div></div>" | ||
# define the dash default config key | ||
config <- sprintf("<script id='_dash-config' type='application/json'> %s </script>", to_JSON(self$config)) | ||
|
||
if (is.null(private$name)) | ||
private$name <- 'dash' | ||
|
||
if (!is.null(private$custom_index)) { | ||
string_index <- glue::glue(private$custom_index, .open = "{%", .close = "%}") | ||
|
||
private$.index <- string_index | ||
} | ||
|
||
else if (length(private$template_index) == 1) { | ||
private$.index <- private$template_index | ||
} | ||
|
||
private$.index <- sprintf( | ||
'<!DOCTYPE html> | ||
else { | ||
private$.index <- sprintf( | ||
'<!DOCTYPE html> | ||
<html> | ||
<head> | ||
%s | ||
|
@@ -1450,23 +1621,22 @@ Dash <- R6::R6Class( | |
</head> | ||
|
||
<body> | ||
<div id="react-entry-point"> | ||
<div class="_dash-loading">Loading...</div> | ||
</div> | ||
|
||
%s | ||
<footer> | ||
<script id="_dash-config" type="application/json"> %s </script> | ||
%s | ||
%s | ||
</footer> | ||
</body> | ||
</html>', | ||
meta_tags, | ||
private$name, | ||
favicon, | ||
css_tags, | ||
to_JSON(self$config), | ||
scripts_tags | ||
) | ||
meta_tags, | ||
private$name, | ||
favicon, | ||
css_tags, | ||
app_entry, | ||
config, | ||
scripts | ||
) | ||
} | ||
} | ||
) | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The table version bump should also be mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in c03c6c1