Skip to content
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

Merged
merged 45 commits into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5c83f5c
Use dev_tools_prune_errors instead of pruned_errors (#113)
rpkyle Aug 23, 2019
d20daa8
Provide support for multiple outputs (#119)
rpkyle Sep 3, 2019
0845184
prepend multiple
Sep 3, 2019
29a3042
Better handling for user-defined error conditions in debug mode (#116)
rpkyle Sep 6, 2019
bbfc6cc
add more trace for pytest
Sep 18, 2019
2e09789
Implement support for clientside callbacks in Dash for R (#130)
rpkyle Oct 1, 2019
c947c73
Provide support for hot reloading in Dash for R (#127)
rpkyle Nov 1, 2019
8e3c168
update percy settings
Nov 4, 2019
5d485d9
Merge pull request #138 from plotly/percy
byronz Nov 4, 2019
5c2ea67
add always
Nov 4, 2019
cd33eba
Merge pull request #139 from plotly/percy
byronz Nov 4, 2019
f866d38
Support for meta tags in Dash for R (#142)
rpkyle Nov 5, 2019
7e16f8d
restore port default
Nov 14, 2019
4b99c88
update codeowners
Nov 29, 2019
2ca3f98
Create CODEOWNERS
Marc-Andre-Rivet Nov 29, 2019
68be6a9
Fixes for hot reloading interval handling and refreshing apps within …
rpkyle Dec 4, 2019
1d5ee2d
Update CHANGELOG.md
rpkyle Dec 4, 2019
e852995
Support for asynchronous loading/compression in Dash for R (#157)
rpkyle Dec 22, 2019
22227f6
make more idiomatic for routr
Dec 22, 2019
006b6d3
:necktie: :hocho: whitespace
Dec 22, 2019
93345e6
Update dash-renderer to 1.2.2 and fix dev tools UI display of stack t…
rpkyle Dec 25, 2019
e6c460a
use versions from dev branch for #996
Dec 25, 2019
8c9678b
Update CHANGELOG.md
rpkyle Dec 25, 2019
61e6dfa
Support returning asset URLs via public method within Dash class (#160)
rpkyle Jan 3, 2020
ca6613c
Update CHANGELOG.md
rpkyle Jan 3, 2020
fb05d18
Minor fix for get_asset_url + docs, add url_base_pathname (#161)
rpkyle Jan 3, 2020
85828d3
Merge branch 'master' into dev
rpkyle Jan 3, 2020
e4cedb3
Autoset routes and requests pathname prefixes (#165)
rpkyle Jan 14, 2020
cc9e06d
Inspect environment variables for host & port (#167)
rpkyle Jan 14, 2020
3733ead
Support for index page templating (#168)
HammadTheOne Feb 11, 2020
2f1be58
Add support for config-aware relative paths (#172)
HammadTheOne Feb 12, 2020
6eddf98
Update CHANGELOG.md
rpkyle Feb 12, 2020
a2907ba
Update DESCRIPTION
rpkyle Feb 12, 2020
98254a1
update authors
Feb 12, 2020
402969d
Merge branch 'dev' of github.com:plotly/dashR into dev
Feb 12, 2020
d7dcae7
Merge branch 'master' into dev
rpkyle Feb 12, 2020
c03c6c1
added dashTable version bump
rpkyle Feb 12, 2020
030adb4
renamed "Removed" section to "Deprecated"
rpkyle Feb 12, 2020
744b696
host & port changes :truck: "Deprecated" section
rpkyle Feb 12, 2020
c853cbf
:see_no_evil: fix typo
rpkyle Feb 12, 2020
7c26675
:see_no_evil: fix typo
rpkyle Feb 12, 2020
49c97da
:see_no_evil: fix typos
Feb 12, 2020
21e78db
Merge branch 'dev' of github.com:plotly/dashR into dev
Feb 12, 2020
2c46d9f
Add unit tests for index customization (#176)
rpkyle Feb 13, 2020
0085036
Send status code of 1 when unit tests fail (#177)
rpkyle Feb 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
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
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in c03c6c1

- 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This goes beyond the scope of ### Changed and could be ### Deprecated (or removed)+### Added entries instead. Same for DASH_APP_NAME below. As this is a 0.x release it's not technically 100% necessary. At your discretion.

Copy link
Contributor Author

@rpkyle rpkyle Feb 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 030adb4 and 744b696

- 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)
Expand Down Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Package: dash
Title: An Interface to the Dash Ecosystem for Authoring Reactive Web Applications
Version: 0.2.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person(family = "Plotly Technologies", role = "cph"))
Version: 0.3.0
Authors@R: c(person("Chris", "Parmer", role = c("aut"), email = "chris@plot.ly"), person("Ryan Patrick", "Kyle", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-5829-9867"), email = "ryan@plot.ly"), person("Carson", "Sievert", role = c("aut"), comment = c(ORCID = "0000-0002-4958-2844")), person("Hammad", "Khan", role = c("aut"), email = "hammadkhan@plot.ly"), person(family = "Plotly Technologies", role = "cph"))
Description: A framework for building analytical web applications, Dash offers a pleasant and productive development experience. No JavaScript required.
Depends:
R (>= 3.0.2)
Imports:
dashHtmlComponents (== 1.0.2),
dashCoreComponents (== 1.6.0),
dashTable (== 4.5.1),
dashCoreComponents (== 1.8.0),
dashTable (== 4.6.0),
R6,
fiery (> 1.0.0),
routr (> 0.2.0),
Expand All @@ -32,8 +32,8 @@ Collate:
'print.R'
'internal.R'
Remotes: plotly/dash-html-components@55c3884,
plotly/dash-core-components@c107e0f,
plotly/dash-table@3058bd5
plotly/dash-core-components@fc153b4,
plotly/dash-table@79d46ca
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Expand Down
228 changes: 199 additions & 29 deletions R/dash.R
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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',
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
#
Expand Down Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo at line 965: dire ctly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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() {
Expand Down Expand Up @@ -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
Expand All @@ -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
)
}
}
)
)
Expand Down
Loading