Skip to content

Commit 2f1be58

Browse files
authored
Add support for config-aware relative paths (#172)
* Added `get_relative_path` and `strip_relative_path` functions. * Added description and examples for method usage.
1 parent 3733ead commit 2f1be58

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

R/dash.R

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,27 @@
117117
#' present a warning and return `NULL` if the Dash app was not loaded via `source()`
118118
#' if the `DASH_APP_PATH` environment variable is undefined.
119119
#' }
120+
#' \item{`get_relative_path(path, requests_pathname_prefix)`}{
121+
#' The `get_relative_path` method simplifies the handling of URLs and pathnames for apps
122+
#' running locally and on a deployment server such as Dash Enterprise. It handles the prefix
123+
#' for requesting assets similar to the `get_asset_url` method, but can also be used for URL handling
124+
#' in components such as `dccLink` or `dccLocation`. For example, `app$get_relative_url("/page/")`
125+
#' would return `/app/page/` for an app running on a deployment server. The path must be prefixed with
126+
#' a `/`.
127+
#' \describe{
128+
#' \item{path}{Character. A path string prefixed with a leading `/` which directs at a path or asset directory.}
129+
#' \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.}
130+
#' }
131+
#' \item{`strip_relative_path(path, requests_pathname_prefix)`}{
132+
#' The `strip_relative_path` method simplifies the handling of URLs and pathnames for apps
133+
#' running locally and on a deployment server such as Dash Enterprise. It acts almost opposite the `get_relative_path`
134+
#' method, by taking a `relative path` as an input, and returning the `path` stripped of the `requests_pathname_prefiex`,
135+
#' and any leading or trailing `/`. For example, a path string `/app/homepage/`, would be returned as
136+
#' `homepage`. This is particularly useful for `dccLocation` URL routing.
137+
#' \describe{
138+
#' \item{path}{Character. A path string prefixed with a leading `/` and `requests_pathname_prefix` which directs at a path or asset directory.}
139+
#' \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.}
140+
#' }
120141
#' \item{`index_string(string)`}{
121142
#' The `index_string` method allows the specification of a custom index by changing
122143
#' the default `HTML` template that is generated by the Dash UI. Meta tags, CSS, Javascript,
@@ -828,6 +849,24 @@ Dash <- R6::R6Class(
828849
},
829850

830851
# ------------------------------------------------------------------------
852+
# return relative asset URLs
853+
# ------------------------------------------------------------------------
854+
855+
get_relative_path = function(path, requests_pathname_prefix = self$config$requests_pathname_prefix) {
856+
asset = get_relative_path(requests_pathname = requests_pathname_prefix, path = path)
857+
return(asset)
858+
},
859+
860+
861+
# ------------------------------------------------------------------------
862+
# return relative asset URLs
863+
# ------------------------------------------------------------------------
864+
865+
strip_relative_path = function(path, requests_pathname_prefix = self$config$requests_pathname_prefix) {
866+
asset = strip_relative_path(requests_pathname = requests_pathname_prefix, path = path)
867+
return(asset)
868+
},
869+
831870
# specify a custom index string
832871
# ------------------------------------------------------------------------
833872
index_string = function(string) {
@@ -945,7 +984,6 @@ Dash <- R6::R6Class(
945984
self$server$on('cycle-end', function(server, ...) {
946985
# handle case where assets are not present, since we can still hot reload the app itself
947986
#
948-
# private$last_refresh is set after the asset_map is refreshed
949987
# private$last_reload stores the time of the last hard or soft reload event
950988
# private$last_cycle will be set when the cycle-end handler terminates
951989
#

R/utils.R

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,48 @@ tryCompress <- function(request, response) {
12711271
return(response$compress())
12721272
}
12731273

1274+
get_relative_path <- function(requests_pathname, path) {
1275+
# Returns a path with the config setting 'requests_pathname_prefix' prefixed to
1276+
# it. This is particularly useful for apps deployed on Dash Enterprise, which makes
1277+
# it easier to serve apps under both URL prefixes and localhost.
1278+
1279+
if (requests_pathname == "/" && path == "") {
1280+
return("/")
1281+
}
1282+
else if (requests_pathname != "/" && path == "") {
1283+
return(requests_pathname)
1284+
}
1285+
else if (!startsWith(path, "/")) {
1286+
stop(sprintf(paste0("Unsupported relative path! Paths that aren't prefixed" ,
1287+
"with a leading '/' are not supported. You supplied '%s'."),
1288+
path))
1289+
}
1290+
else {
1291+
return(paste(gsub("/$", "", requests_pathname), gsub("^/", "", path), sep = "/"))
1292+
}
1293+
}
1294+
1295+
strip_relative_path <- function(requests_pathname, path) {
1296+
# Returns a relative path with the `requests_pathname_prefix` and leadings and trailing
1297+
# slashes stripped from it. This function is particularly relevant to dccLocation pathname routing.
1298+
1299+
if (is.null(path)) {
1300+
return(NULL)
1301+
}
1302+
else if ((requests_pathname != "/" && !startsWith(path, gsub("/$", "", requests_pathname)))
1303+
|| (requests_pathname == "/" && !startsWith(path, "/"))) {
1304+
stop(sprintf(paste0("Unsupported relative path! Path's that are not prefixed ",
1305+
"with a leading 'requests_pathname_prefix` are not suported. ",
1306+
"You supplied '%s', and requests_pathname_prefix was '%s'."),
1307+
path, requests_pathname
1308+
))
1309+
}
1310+
else if (requests_pathname != "/" && startsWith(path, gsub("/$", "", requests_pathname))) {
1311+
path = sub(gsub("/$", "", requests_pathname), "", path)
1312+
}
1313+
return(trimws(gsub("/", "", path)))
1314+
}
1315+
12741316
interpolate_str <- function(index_template, ...) {
12751317
# This function takes an index string, along with
12761318
# user specified keys for the html keys of the index
@@ -1299,4 +1341,4 @@ validate_keys <- function(string) {
12991341
} else {
13001342
return(string)
13011343
}
1302-
}
1344+
}

0 commit comments

Comments
 (0)